最近,Vercel が再度価格を調整し、Hobby プランではますます不十分になったため、Vercel の使用をやめ、プライベートサーバーに移行して Next.js プロジェクトをデプロイすることにしました。
プライベートサーバーでのデプロイ体験は非常に不便です。第一に、Vercel のような完全自動デプロイがなく、迅速なロールバックもできません。第二に、Next.js プロジェクトのビルドには非常に大きなメモリと CPU リソースが必要で、一般的な軽量サーバーではビルド中にクラッシュするか、ダウンしてしまうことがあります。
目標#
- GitHub を利用して、ビルド時の環境変数に影響されない汎用的な成果物を構築する。(後者については、一次構建多处部署 - Next.js Runtime Env という記事で詳しく知ることができます)
- ビルド成果物をリモートサーバーにプッシュする方法
- 異なるソースコードリポジトリでビルドのワークフローを実行する方法(この要件は、クローズドソースリポジトリに対して GitHub CI の時間やその他の制限があるためです;もう一つは、このようなワークフロー構成リポジトリをオープンソースにし、ソースコードリポジトリをクローズドソースにできることです)
- ロールバックを実現する方法(便利ではないかもしれませんが、使用可能です)
プロセス#
上記の目標に基づいて、私たちが行うべきことを考え出すことができます。おおよそこのようなビルドプロセスです。
- ワークフローレポジトリではなく、ソースコードリポジトリからコードをチェックアウトすることが重要です。
- 通常のコードビルド
- バージョンを区別し、サーバーにプッシュする
- ビルドを完了する
ソースコードリポジトリにコードの変更があった場合、ワークフローレポジトリのパイプラインを再実行する必要があります。

2 つのリポジトリ#
上記のプロセスが明確になったので、CI 用に専用のリポジトリを作成する必要があります。これが上記で述べたワークフローレポジトリです。
次に、ワークフロー構成を作成します。
上記のコメントの部分に注意が必要です。
ビルドとデプロイ#
ビルドとジョブ間での成果物共有#
次に、デプロイの作業構成を書きます。
ジョブ間での成果物共有には、Artifact を使用する必要があります。ビルドプロセスの中で、最終的な成果物を Artifact としてアップロードし、次のジョブで Artifact をダウンロードして使用します。
Important
この方法を使用すると、ビルド成果物が漏洩する可能性があります。リポジトリがオープンソースである場合、アップロードされた成果物は誰でも(GitHub にログインしている人)ダウンロードできます。
GitHub にサインインしていて、リポジトリに対する読み取りアクセス権を持っている人は、ワークフローのアーティファクトをダウンロードできます。
上記の方法は安全ではないため、ここでは CI キャッシュを使用して同じ機能を実現します。
SSH を使用して成果物をリモートサーバーに転送#
上記で成果物のビルドが完了したので、次にサーバーへのデプロイプロセスを書きます。
ここでは、SSH + SCP の方法を使用してビルド成果物をサーバーにアップロードし、関連するスクリプトを直接実行します。
私たちは GitHub ワークフロー ID を現在のビルドの識別子として使用し、サーバーデプロイディレクトリで区別します。これにより、毎回デプロイされた成果物がサーバーに存在し、将来のロールバックが容易になります。ロールバックプロセスは比較的伝統的ですが、実現できたと言えます。
私は PM2 を使用してプロジェクトをホストしていますが、もちろん他の方法を使用することもできます。
クロスリポジトリでのワークフロー呼び出し#
ソースコードリポジトリに新しいコミットがあると、ワークフローレポジトリのパイプラインを再実行する必要があります。
ここでは API 呼び出しを使用できます。
ソースコードリポジトリに新しいワークフローを追加します。
ここでは、GitHub API を利用してワークフローレポジトリのパイプラインを再実行します。
次に、呼び出される側のワークフロー構成を変更する必要があります。
types は呼び出し元が定義したもので、一致させる必要があります。
これで、ソースが main に更新されると、API インターフェースを介して repository_dispatch 内の types と一致するワークフローが呼び出されます。

重複バージョンのビルドを防ぐ#
上記の構成は基本的に使用可能ですが、いくつかの点を判断する必要があります。
例えば、同じコミットは重複と見なされ、ビルドとデプロイは一度だけ行われるべきです。重複が発生した場合、ビルドとデプロイのプロセス全体をスキップする必要があります。
ここでは、各コミットハッシュを使用して判断し、前回成功したデプロイのハッシュを保存し、現在進行中のコミットハッシュと比較します。一致すればスキップします。
前回のコミットハッシュをファイルの形式で記録します(アーティファクトを使用することもできますが、なぜファイルを使用するのかは次のセクションで説明します)。
毎回ビルドが完了したコミットハッシュを現在のリポジトリの build_hash ファイルに保存します。
これを実現するために、いくつかのプロセスが必要です。まず、現在のリポジトリの build_hash を読み取り、次のプロセスで読み取れるように GITHUB_OUTPUT に保存します。
次のプロセスでは、ソースコードリポジトリをチェックアウトし、ソースコードリポジトリのコミットハッシュを読み取り、build_hash と比較して、boolean 値を出力します。同様に、GITHUB_OUTPUT に保存します。
次のプロセスでは、if を利用して、全体のプロセスを終了すべきかどうかを判断します(後続のプロセスはこれに依存しているため、すべて終了することになります)。
最後のプロセスでは、デプロイが完了した後、現在のコミットハッシュをリポジトリに保存します。Push アクションを使用しました。
このため、毎回 Bot が新しいコミットをプッシュすることになり、これもこのワークフローを実行すべきではありません。したがって、最初のプロセスで if をコミットメッセージに基づいてガードします。
参考構成は以下の通りです。
永遠に無効にならない Cronjob の実行#
このワークフローを定期的に実行するために、schedule を使用できます。
GitHub アクションの制限により、リポジトリが 3 か月間活動がない場合、ワークフローが無効になります。したがって、前のセクションでコミットを使用して無効化を防ぐ方法を使用しました。毎回ビルドしてハッシュをアップロードすることも良い選択です。
以上がすべての内容です。
完全な構成はここにあります:
この記事は Mix Space によって xLog に同期更新されました。原始リンクは https://innei.in/posts/tech/automatically-build-projects-across-repositories-and-deploy-to-servers