ブルーグリーンデプロイ
開発者環境から、ステージング環境を通じて、プロダクション環境にデプロイする時は、いつもダウンタイムがあるはずでしょう。じゃ、エンドユーザーの体験のためどうやってこのダウンタイムを最小化するかな?
Published onUpdated on
8 min read
コンテキスト
開発者であれば、きっとバージョン管理システム(英 Version Control System)という概念が聞いたことがあるはずですね。 昔はね、Subversionというツールが最も人気で、多くの企業が利用していました。 ですが、リーナストーバルズがGitを使って依頼、開発の世界がまるで一夜にして変わりました。 突然に、Gitが爆発的に流行りになり、会社も個人開発者も採用し始めました。
Gitの一番の強みは、やっぱりチーム開発の場合にですね。 みんなが自分のブランチで並行に開発できるようになりました。 そして、開発のパイプラインを最適化するため、CI/CDという概念が生まれました。
CIとはContinuous Integration(継続的インテグレーション)の略であります。 Gitに小さなチェンジをプッシュすると、すぐにコードをチェックしたり、テストしたり、レビューしたりしてくれます。 そのからこそ、Continuous(継続的)と呼ばれますよ。 CIの後のCDとは、Continuous Delivery(継続的デリバリー)の略であります。 テストしてビルドするのが終わったら、それがどう配布するのかがCDの仕業です。
例えば、Reactのウェブアプリを作っている際、CIはそのアプリをトランスフォームして最終的なHTMLを生成します。 それで、そのHTMLをNGINXなどのホストに自動的にデプロイするのがCDの役目です。 ですから、CIとCDは普通にセットで使用されます。
でも、CDには一つの問題があります。気づきましたかな? それは、新しいバージョンがデプロイしているときには、短い時間でもプロダクションのアプリが止まってしまうことです。 私のインターンしていた会社でもこの問題に悩んでいましたので、私がブルーグリーンというデプロイ戦略を実装しました。
ブルーグリーンっては何ですか
ブルーグリーンというデプロイ戦略は、一つのプロダクション環境(ブルー)をそのままにしておき、新しいバージョンが他の環境にデプロイして(グリーン)、ヘルスチェックを行うことです。 ヘルスチェックが成功したら、リバースプロキシやゲートウェイなどのホストが徐々にグリーンへ移動します。 そうすることで、新しいのをデプロイしても、エンドユーザーに全く影響がありません。
理論上、ブルーがプロダクション環境で、グリーンが新しいステージング環境と呼ばれます。 ですが、実際にはいつも必ずそうだとは限りません。 経験によると、アプリが順調にグリーン環境に動作している場合は、新しいバージョンが本番にアップされると、ブルーの方がステージングとして使われるであろう。 結局、「ブルー」「グリーン」というのは祖先呼び名にすぎないので、主点わかれば大丈夫だと思います。
実現上
弊社では、デポロイが必要なのはSpringのバックエンドだけなので、まさに普通のBashスクリプトならできると思います。 Kubernetesのような複雑なツールなどを使うことができますけど、開発者の時間を大切にするため、あえて簡単な方法にしました。
以下のスクリプトは、一つのSSHアクションだけで十分ですけど、関数や処理などが多いので、行ごとに説明していきましょう。
ステップ1 準備
チームはDockerがとっても便利と思うので、Dockerでデプロイします。 直接デプロイする方法もいいですが、この投稿では、書かないようにしました。
- name: Build and push Docker image (latest + commit-sha)
id: build-push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
${{
github.event_name == 'push' && github.ref == 'refs/heads/main'
&& format('{0}/{1}:latest', env.REGISTRY, env.IMAGE_NAME)
|| ''
}}
GitHub Actionsというツールも聞いたことがあるでしょう。 このステップが、ドッカーイメージを作ってGitHubのGHCRにプッシュするのです。 これで準備OKですね。
ステップ2 プル
echo "インフォ:イメージ$IMAGE:$TAGと最新をプルしている"
docker login ghcr.io -u "$GITHUB_ACTOR" -p "$GITHUB_TOKEN"
docker pull "$IMAGE:$TAG"
docker pull "$IMAGE"
GHCRもDocker Hubも、プライベートリポジトリを使う際には、ログインしなくてはいけません。 パブリックリポジトリを使っても、プッシュ権利があるアカウントにログインしないと、プッシュすることができません。 でも、プルしたい場合には、ログイン必要があるのはプライベートリポジトリからのみです。
ステップ3 書き換え
あなたのサーバーはすでに最新バージョンをプルしましたね。 次にやるべきことは、本番環境をダウンせずに、徐々に新バージョンへ切り替えるのでしょう。 この会社はDockerのNginxを使っていますので、ボリュームがマウントしないと、直接に設定ファイルを編集するのは不可能ですね。 ですが、解決はまさに簡単です。 コンテナの中であらゆるのawkやsedなどのようなコマンドを実行して、書き換えばいいのです。
if exec_rev_proxy "grep -sq \"backend-blue\" $NGINX_CONF_PATH"; then
echo "サーバーはブルーです"
echo "ステージング環境のグリーンを起動する"
check_and_start backend-green
healthcheck $GREEN_URL
swap $GREEN_URL
else
echo "サーバーはグリーン"
echo "ステージング環境のブルーを起動する"
check_and_start backend-blue
healthcheck $BLUE_URL
swap $BLUE_URL
fi
注意:check_and_startなどのコマンドは関数であり、一般的インストールされているコマンドじゃありません。
上のコードを見たら、だいたい何をしているのかはわかりやすいと思います。 とはいえ、Bash未経験者にとっては、少しでもわかりづらいかもしれません。 実際に、もう長くLinuxを使っていた他のインターンさえも、「このスクリプトは複雑すぎてレビューしたりできない」と言い、全部理解することができなかったようです。 Bashスクリプトそのものはそもそも説明しづらいのか、私のコード品質が低かったのか…