Luny
Back

ブルーグリーンデプロイ

開発者環境から、ステージング環境を通じて、プロダクション環境にデプロイする時は、いつもダウンタイムがあるはずでしょう。じゃ、エンドユーザーの体験のためどうやってこのダウンタイムを最小化するかな?

Published on
Updated 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スクリプトそのものはそもそも説明しづらいのか、私のコード品質が低かったのか…