NginxでBlue Green Deploymentをやってみる
Nginx を利用して Blue/Green Deployment を試してみました。 よく k8s を利用したものなどを紹介されていることが多いですが、今回は Nginx の設定ファイルを良しなにして Blue/Green Deployment を行います。 また、切り替え時に既存の通信が正常に処理されるのかも確かめたいと思います。
ophum/kakisute/nginx-blue-green
構成
検証環境は Docker を利用しました。
nginx と blue 用のアプリケーションと green 用のアプリケーションの 3 つのコンテナを利用します。
アプリケーションは、それぞれの環境名を返すだけの Web サーバーです。blue の場合blue
、green の場合 green
とレスポンスが返されます。
また、クエリパラメータでsleep
を指定することで、レスポンスを指定時間遅らせることができます。(http://localhost:8080/?sleep=10s
10 秒後にレスポンスが返る)
初期状態では、blue を現行環境、green を新バージョン環境とします。
つまり、本番 URL の localhost:8080
でアクセスすると blue
が返り、 preview:8080
でアクセスするとgreen
が返ります。
現行から新バージョンに環境を切り替えた後は、本番 URL の localhost:8080
でアクセスするとgreen
が返り、preview:8080
でアクセスするとblue
が返るようになります
こうすることで、無停止で新バージョンに切り替えが可能となります。また、新バージョンに不具合がある場合も無停止で旧バージョンに切り戻しできます。 さらに新しいバージョンをデプロイするときは、今度は blue に新バージョンをデプロイし切り替えるといった具合です。
また、新バージョンに対しての入り口を用意しておけば事前確認も可能です。(Host が関わるような仕様がアプリケーションにある場合は工夫が必要ですが今回は省きます。)
実装
ここでは、どのように実現するかを説明します。
構成で説明した内容を実現するには、以下のような設定が必要になります。
blue が現行の場合
- blue の設定 (
blue.conf
現行) - green の設定 (
green-preview.conf
プレビュー)
green が現行の場合
- blue の設定 (
blue-preview.conf
プレビュー) - green の設定 (
green-conf
現行)
またどちらが現行によって設定ファイルを切り替える必要があります。
これらの 4 つの設定ファイルは任意の場所(今回は/etc/nginx/sites-available
に配置)に置いておき /etc/nginx/conf.d/
にシンボリックリンクを張ることで設定を反映させます。
つまり blue が現行の場合は以下のように設定します。
1ln -s /etc/nginx/sites-available/blue.conf /etc/nginx/conf.d/blue.conf
2ln -s /etc/nginx/sites-available/green-preview.conf /etc/nginx/conf.d/green-preview.conf
blue から green への切り替えは、blue.conf
とgreen-preview.conf
のリンクを削除し green.conf
とblue-preview.conf
のリンクを作成します。
設定の反映は nginx をリロードすることで行います。
今回は docker を利用しているので、nginx コマンドでリロードします。nginx -s reload
とすることでリロードできます。
systemd を利用している場合はsystemctl reload nginx
です。
reload することで、現行に接続中の通信を途中で切断することなく新しいバージョンに切り替えられます。
ここまでの内容をスクリプトにしました。 スクリプト: scripts/bg-change.sh
1#!/bin/bash
2
3
4CONFD=/etc/nginx/conf.d
5SITES_AVAILABLE=/etc/nginx/sites-available
6
7function change() {
8 echo "$1 -> $2"
9 rm $CONFD/$1.conf
10 rm $CONFD/$2-preview.conf
11
12 ln -s $SITES_AVAILABLE/$2.conf $CONFD/$2.conf
13 ln -s $SITES_AVAILABLE/$1-preview.conf $CONFD/$1-preview.conf
14
15 nginx -s reload
16}
17
18current=$(bash /etc/nginx/scripts/bg-current.sh)
19if [ $current == "blue" ]; then
20 change blue green
21else
22 change green blue
23fi
実行ログ
1$ git clone https://github.com/ophum/kakisute.git
2$ cd kakisute/nginx-blue-green/
3$ docker compose up -d
この時点では設定ファイルが nginx の初期のものになっているので、初期ページが表示されます。
1$ curl localhost:8080
2<!DOCTYPE html>
3<html>
4...
default.conf
を削除し blue.conf
と green-preview.conf
を設置するスクリプトを実行します。
$ docker compose exec --workdir /etc/nginx/scripts/ nginx bash bg-init.sh
2024/07/18 19:15:46 [notice] 42#42: signal process started
curl-release.sh
でblue
、 curl-preview.sh
でgreen
が表示されることを確認します。
$ bash ./curl-release.sh
blue
$ bash ./curl-preview.sh
green
それぞれスクリプトの内容は以下のようになっています。
1$ cat ./curl-release.sh
2#!/bin/bash
3
4DURATION=${1-0s}
5curl localhost:8080/?sleep=$DURATION
6
7echo
8
9$ cat ./curl-preview.sh
10#!/bin/bash
11
12DURATION=${1-0s}
13curl -H "Host: preview" localhost:8080/?sleep=$DURATION
14
15echo
次に、blue と green を切り替えてみます。
1$ docker compose exec --workdir /etc/nginx/scripts/ nginx bash bg-change.sh
2blue -> green
32024/07/18 19:18:26 [notice] 58#58: signal process started
curl-release.sh
でgreen
, curel-preview.sh
でblue
が表示されることを確認します。
1$ bash ./curl-release.sh
2green
3$ bash ./curl-preview.sh
4blue
うまく切り替わっていることが確認できました。
切り替え時に既存の通信が正常に処理されるか
blue から green に切り替える際、blue に接続していた通信はそのまま正常に処理され、切り替え後のリクエストは green で処理されるか検証します。
今回利用したアプリケーションではレスポンスまでの時間を遅らせることができるので、blue の時点で 10 秒遅延するリクエストを送り、10 秒以内に切り替え、10 秒後に blue のレスポンスが返ってくることを確認します。 また、切り替え後のリクエストは green の内容が返ることを確認します。
blue が現行の状態で行う。
1$ docker compose exec --workdir /etc/nginx/scripts/ nginx bash bg-current.sh
2blue
10 秒遅延でcurl-release.sh
を実行。10 秒間待ち状態になります。
1$ bash ./curl-release.sh 10s
待ち状態の間別のターミナルで切り替えます。
この時、curl-release.sh
を遅延なしで実行して green に切り替わっていることを確認します。
1$ docker compose exec --workdir /etc/nginx/scripts/ nginx bash bg-change.sh
22024/07/18 19:25:32 [notice] 95#95: signal process started
3$ bash ./curl-release.sh
4green
10 秒経過後、blue が返ることを確認します。
1$ bash ./curl-release.sh 10s
2blue
以上で、blue と green を無停止で切り替えることができ、切り替え前の通信は切断されずに処理が行われることがわかりました。