コードを使ってインフラストラクチャをデプロイする手法が広まり、インフラエンジニアにもソフトウェアエンジニアに近いスキルが求められるようになってきました。
従来の手動設定管理やデプロイから、IaC(Infrastructure as Code)を導入することで、効率的で再現性のある環境構築が可能となっています。
私が関わっているプロジェクトでは、TerraformとAnsibleを使用してインフラ環境をデプロイし、新機能のリリースやミドルウェアのバージョンアップに「Blue/Greenデプロイメント戦略」を採用しています。
Blue/Greenデプロイメントは、サービスの中断を最小限に抑えながら新しいリリースを導入する方法で、既存の環境(Blue)と新しい環境(Green)を並行して稼働させることが特徴です。この切り替えは運用担当のインフラエンジニアに任されているため、深く理解することが求められます。
今回の記事では、Blue/Greenデプロイメントの概要と、実際に手を動かして学ぶハンズオンを紹介します。この記事を通じて、基本的な概念と実践的な手法を学び、自分のプロジェクトに応用できるスキルを身につけていただければと思います。
Blue/Greenデプロイメントハンズオン
1.Blue/Greenデプロイメントとは
Blue/Greenデプロイメントは、ソフトウェアリリースを安全かつ確実に行うためのデプロイメント戦略です。この手法を使用すると、ダウンタイムを最小限に抑え、問題が発生した場合に迅速にロールバックすることができます。
■Blue/Greenデプロイメントの基本原理
- Blue環境
現在稼働している本番環境。
ユーザーのリクエストを処理し、アプリケーションのサービスを提供しています。
- Green環境
新しいバージョンのアプリケーションをデプロイしてテストするための環境。
現在の本番環境に影響を与えることなく、コードを検証できます。
■デプロイメントフロー
-
新しいバージョンをGreen環境にデプロイ
新しいアプリケーションバージョンをGreen環境にデプロイします。この段階では、ユーザーのトラフィックはまだBlue環境に向いています。
↓
-
Green環境でテストと検証
Green環境で新しいバージョンをテストし、すべてが正常に動作することを確認します。これには、自動化されたテストや手動での確認が含まれます。
↓
- トラフィックの切り替え
Green環境が正常に動作することが確認されたら、ロードバランサーやリバースプロキシ(NGINXなど)の設定を変更して、ユーザーのトラフィックをGreen環境に切り替えます。これにより、Green環境が新しい本番環境となり、Blue環境は待機状態になります。
↓
- モニタリング
新しい環境(Green)が正常に動作していることを監視します。問題が発生した場合は、迅速にロールバック(元のBlue環境にトラフィックを戻す)します。
↓
- ロールバック
問題が発生した場合、ロードバランサーやリバースプロキシの設定を変更して、トラフィックを元のBlue環境に戻します。これにより、ユーザーは問題のない環境に戻ります。
■Blue/Greenデプロイメントのメリット
- ダウンタイムの最小化
デプロイ中にユーザーに影響を与えないため、ダウンタイムがほとんどありません。
- リスクの低減
新しいバージョンを独立した環境でテストできるため、リスクを最小限に抑えられます。
- 迅速なロールバック
問題が発生した場合、迅速に元の環境に戻すことができます。
Blue/Greenデプロイメントについて、基本的な概要はお分かりいただけましたでしょうか。次からはBlue/Greenデプロイメントハンズオンを実施し、理解を深めていきましょう。
2. ハンズオンガイド
Blue/Greenデプロイメントの仕組みを理解するためのハンズオンを用意しました。Flaskアプリでサービスを提供している前提で、ダウンタイムなしで新バージョンの環境に切り替えてみましょう。
■前提条件
ハンズオンを実施するにあたって、知識の前提条件は以下の通りです。
・AWSを利用
・Amazon VPC
・Amazon EC2(Amazon Linux 2023 latest)
・AWS IAM
・インターネットからの通信可能な経路の許可(MyIPを許可するだけでよいです)
もしterraformを利用している場合、↓のリポジトリを利用してください。必要な環境がセットアップされます。
https://github.com/saitou-cpi/testserver
また、以下の知識があるとより理解しやすいかと思います。
・Git
・Flask
・Nginx
必要なファイルやコマンドを用意してありますので、難しいものではありません。ぜひ気軽に試してみてください。
■環境のセットアップ
Blue/Greenデプロイメントを体験するための環境を用意します。コマンドを実行する箇所には、"☆"をつけてありますので、目印にしてください。
●ステップ1: パッケージインストール
まずはFlaskアプリを稼働させるためのパッケージや環境を作っていきます。
サーバに接続します。
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
Last login: Sat Aug 3 08:39:24 2024 from 175.177.44.70
[ec2-user@ip-10-0-1-32 ~]$
☆↓必要なパッケージをインストールします。
sudo dnf install -y python3-pip git nginx
pip install virtualenv
●ステップ2: ファイル配置
Flaskアプリケーションのスクリプトを用意します。今回はBlue/Greenデプロイメントの仕組みの理解がキモなので、スクリプトはわたしのリポジトリからcloneしましょう。
ディレクトリ構造は以下の通りです。
BlueGreenTest/
│
├── blue/
│ ├── app.py
│ └── run.sh
│
├── green/
│ ├── app.py
│ └── run.sh
│
├── nginx/
│ └── nginx.conf
│
├── requirements.txt
├── deploy.sh
├── rollback.sh
└── check_default_env.sh
☆↓リポジトリをcloneしてください。
git clone https://github.com/saitou-cpi/BlueGreenTest.git
今回使うファイルの確認をしておきましょう。メインとなるFlaskのapp.pyは"Hello"と返すシンプルなスクリプトになっています。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, Flask with Gunicorn and Nginx!"
if __name__ == "__main__":
app.run()
"nginx.conf"は次の通りです。
worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# Adjust types_hash settings to resolve warning
types_hash_max_size 4096;
types_hash_bucket_size 128;
# Define upstream servers for blue and green environments
upstream blue {
server 127.0.0.1:8000;
}
upstream green {
server 127.0.0.1:8001;
}
# Map environment variable to upstream servers
map $upstream_env $upstream_servers {
blue blue;
green green;
}
server {
listen 80;
server_name example.com;
location / {
set $upstream_env blue; # Set default environment
proxy_pass http://$upstream_servers; # Use mapped upstream server
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /green {
proxy_pass http://green/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /blue {
proxy_pass http://blue/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Flaskにも開発用のwebサーバが実装されていますが、本番稼働での使用は非推奨です。
おすすめの構成は、Flask + Gunicorn + Nginxです。
Nginxをプロキシサーバとして外からのリクエストを処理し、Gunicornを介してFlaskアプリの到達します。Blue/Greenデプロイメントを実現するために、デフォルトにはないUpstreamセクションとMapセクションを追加し、環境切り替えを容易にしてあります。
↓Blue環境とGreen環境を切り替えるためのスクリプト"deploy.sh"です。引数に"blue"もしくは、"green"を入れることで、切り替えが可能です。
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 {blue|green}"
exit 1
fi
DEPLOY_ENV=$1
UPSTREAM_ENV=""
if [ "$DEPLOY_ENV" == "blue" ]; then
UPSTREAM_ENV="green"
TARGET_DIR="./blue/"
SERVICE_NAME="blue.service"
elif [ "$DEPLOY_ENV" == "green" ]; then
UPSTREAM_ENV="blue"
TARGET_DIR="./green/"
SERVICE_NAME="green.service"
else
echo "Invalid environment: $DEPLOY_ENV"
echo "Usage: $0 {blue|green}"
exit 1
fi
# Pull latest code
git pull origin main
# Apply changes to the target environment
cp -r ./new_code/* $TARGET_DIR
# Restart the target environment (assumes you are using a systemd service or similar)
sudo systemctl restart $SERVICE_NAME
# Wait for a manual confirmation before promoting to production
echo "http://example.com/$DEPLOY_ENV を確認し、問題なければ 'y'、問題がある場合は 'Ctrl+C' を押してください..."
read -n 1 -s
# Swap upstream environment to point to the target as the main environment
if [ "$DEPLOY_ENV" == "blue" ]; then
sudo sed -i 's/set $upstream_env green;/set $upstream_env blue;/g' /etc/nginx/nginx.conf
else
sudo sed -i 's/set $upstream_env blue;/set $upstream_env green;/g' /etc/nginx/nginx.conf
fi
sudo nginx -s reload
# Restart both environments to apply the new configuration
sudo systemctl restart blue.service
sudo systemctl restart green.service
echo "Deployment complete. $DEPLOY_ENV is now the new production environment."
さいごに、切り替えした後にアプリに問題があった場合、ロールバックするためのスクリプト"rollback.sh"を用意しました。
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 {blue|green}"
exit 1
fi
ROLLBACK_ENV=$1
if [ "$ROLLBACK_ENV" == "blue" ]; then
CURRENT_ENV="green"
elif [ "$ROLLBACK_ENV" == "green" ]; then
CURRENT_ENV="blue"
else
echo "Invalid environment: $ROLLBACK_ENV"
echo "Usage: $0 {blue|green}"
exit 1
fi
# Wait for a manual confirmation before rolling back
echo "Rolling back to $ROLLBACK_ENV environment. Press 'y' to confirm, or 'Ctrl+C' to cancel."
read -n 1 -s
# Swap upstream environment to point back to the rollback environment
if [ "$ROLLBACK_ENV" == "blue" ]; then
sudo sed -i 's/set $upstream_env green;/set $upstream_env blue;/g' /etc/nginx/nginx.conf
else
sudo sed -i 's/set $upstream_env blue;/set $upstream_env green;/g' /etc/nginx/nginx.conf
fi
sudo nginx -s reload
# Restart both environments to apply the old configuration
sudo systemctl restart blue.service
sudo systemctl restart green.service
echo "Rollback complete. $ROLLBACK_ENV is now the new production environment."
●ステップ3: 仮想環境準備
☆仮想環境を作成し、必要なパッケージをインストールします。
virtualenv .venv
source .venv/bin/activate
cd BlueGreenTest/
pip install -r requirements.txt
☆スクリプトの実行権限を付与します。
sudo chmod u+x deploy.sh check_default_env.sh rollback.sh
●ステップ4: サービス作成
☆各環境のFlaskアプリケーションを管理するために、以下の内容でSystemdサービスファイルを作成します。※もしユーザーを作成していた場合、パスを適宜変更してください。
sudo cp /home/ec2-user/BlueGreenTest/service_files/blue.service /etc/systemd/system/blue.service
sudo cp /home/ec2-user/BlueGreenTest/service_files/green.service /etc/systemd/system/green.service
☆↓新しいサービスファイルを認識させるために、systemdをリロードします。
sudo systemctl daemon-reload
☆↓サービスを有効化して、自動的に起動するように設定します。
sudo systemctl enable blue.service
sudo systemctl enable green.service
●ステップ5: SELinux無効化
Amazon Linux 2023のAMIを利用しているEC2インスタンスでは、SELinuxが有効化されています。
デフォルトのSELinuxのポリシーでは、Flaskアプリのインターフェースとして利用する"gunicorn"の実行が拒否されます。gunicornの実行許可ルールを作成し、ポリシーを適用していきます。
☆↓まずはサービスを起動します。gunicornの実行が拒否されているので、statusを見るとfatalとなっています。
sudo systemctl start blue.service
sudo systemctl start green.service
sudo systemctl restart blue.service
sudo systemctl restart green.service
☆↓次のコマンドで、ポリシーを作成します。
sudo cat /var/log/audit/audit.log | grep "gunicorn"
sudo grep "gunicorn" /var/log/audit/audit.log | audit2allow -M custom_policy
☆↓作成したポリシーをSELinuxに適用します。
sudo semodule -i custom_policy.pp
☆↓サービスを再起動してみましょう。
sudo systemctl restart blue.service
sudo systemctl restart green.service
☆↓正常に起動されたか確認します。
sudo systemctl status blue.service
sudo systemctl status green.service
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ sudo systemctl status blue.service
● blue.service - Gunicorn instance to serve blue environment
Loaded: loaded (/etc/systemd/system/blue.service; enabled; preset: disabled)
Active: active (running) since Sun 2024-08-04 07:57:10 UTC; 7s ago
Main PID: 26464 (gunicorn)
Tasks: 5 (limit: 9247)
Memory: 64.1M
CPU: 589ms
CGroup: /system.slice/blue.service
<省略>
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ sudo systemctl status green.service
● green.service - Gunicorn instance to serve blue environment
Loaded: loaded (/etc/systemd/system/green.service; enabled; preset: disabled)
Active: active (running) since Sun 2024-08-04 07:57:14 UTC; 1min 23s ago
Main PID: 26474 (gunicorn)
Tasks: 5 (limit: 9247)
Memory: 64.3M
CPU: 587ms
CGroup: /system.slice/green.service
<省略>
☆↓適用したポリシーは不要なので、削除します。
rm custom_policy.*
●ステップ6: Nginx起動
☆nginxの有効化と起動を実施します。
sudo systemctl enable nginx
sudo systemctl start nginx
●ステップ7: nginx.confの配置と適用
Flaskアプリにリクエストをプロキシしてもらうための設定ファイルを[/etc/nginx/]に配置し、設定を適用します。
☆↓まずは設定ファイルを配置します。
sudo cp /home/ec2-user/BlueGreenTest/nginx/nginx.conf /etc/nginx/nginx.conf
☆↓設定ファイルを適用し、nginxを再起動しましょう。
sudo nginx -t
sudo nginx -s reload
sudo systemctl status nginx
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ sudo nginx -s reload
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ sudo systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
Active: active (running) since Sun 2024-08-04 07:59:24 UTC; 13min ago
Process: 26621 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
Process: 26622 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
Process: 26623 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
Main PID: 26624 (nginx)
Tasks: 3 (limit: 9247)
Memory: 3.5M
CPU: 67ms
☆すべての設定が終わりましたので、ブラウザからhttpでアクセスし、確認してみましょう。
http://<パブリックIPアドレス>/
"Hello, Flask with Gunicorn and Nginx!"と表示されていればOKです。
☆デフォルトではBlue環境にルーティングされます。続いて、Green環境も問題ないか確認してみましょう。
http://<パブリックIPアドレス>/green
こちらも"Hello, Flask with Gunicorn and Nginx!"と表示されていればOKです。
環境のセットアップは以上です。
3. 動作確認
Blue/Greenデプロイメントを体験してみましょう。
流れは以下の通りです。
1.新しいバージョンのデプロイ(new_code/⇒green/)
↓
2.テストと検証(Green環境)
↓
3.トラフィックの切り替え(Blue環境からGreen環境)
↓
4.ロールバックの手順(Green環境からBlue環境)
■1.新しいバージョンのデプロイ(new_code/⇒green/)
☆まずは現在の本番環境がBlue環境なのか、Green環境なのか確認しましょう。
./check_default_env.sh
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ ./check_default_env.sh
The current default environment is: blue
☆続いて、new_code/app.pyを変更します。"Hello, Flask with Gunicorn and Nginx!"の末尾に"!!!!!!!"を追加してみましょう。
vi new_code/app.py
【変更前】
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, Flask with Gunicorn and Nginx!"
if __name__ == "__main__":
app.run()
【変更後】
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, Flask with Gunicorn and Nginx!!!!!!"
if __name__ == "__main__":
app.run()
■2.テストと検証(Green環境)
☆"deploy.sh"を実行し、環境を切り替えていきます。"deploy.sh"には検証機能も含まれておりますので、実行してみましょう。
./deploy.sh green
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ ./deploy.sh green
http://example.com/green を確認し、問題なければ 'y'、問題がある場合は 'Ctrl+C' を押してください...
☆確認メッセージが表示されたと思います。green環境を確認してみましょう。
http://<パブリックIPアドレス>/green
変更が反映されていますね。
■3.トラフィックの切り替え(Blue環境からGreen環境)
変更に問題なければ、コマンドラインで"y"を押しましょう。Blue環境からGreen環境に切り替わります。
☆さきほどまでデフォルトではBlue環境にルーティングされていましが、Green環境にルーティングされるようになるはずです。
http://<パブリックIPアドレス>/
☆Blue環境はどうなったかというと、
http://<パブリックIPアドレス>/blue
Blue環境は古い状態でそのまま稼働していますね。
■4.ロールバックの手順(Green環境からBlue環境)
☆もし変更に問題があったら、ロールバックしなければなりません。現在の本番環境がBlue環境なのか、Green環境なのか一応確認しましょう。
./check_default_env.sh
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ ./check_default_env.sh
The current default environment is: green
☆それでは、Green環境からBlue環境にロールバックします。
./rollback.sh blue
【実行結果】
(.venv) [ec2-user@ip-10-0-1-238 BlueGreenTest]$ ./rollback.sh blue
Rolling back to blue environment. Press 'y' to confirm, or 'Ctrl+C' to cancel.
Rollback complete. blue is now the new production environment.
☆確認してみましょう。
http://<パブリックIPアドレス>/
Blue/Greenデプロイメントのハンズオンは以上です。
まとめ
Blue/Greenデプロイメントは、ユーザーへの影響を最小限に抑えつつ、新バージョンの提供や修正を行うことができる優れた手法です。インフラエンジニアとして、サービスレベル契約(SLA)に則り、システムの停止時間を限りなくゼロに抑えることが求められています。今回紹介したBlue/Greenデプロイメントは、ゼロダウンタイムを実現するための有効な方法の一つです。
このデプロイメント戦略を採用することで、既存の環境(Blue)と新しい環境(Green)を並行して稼働させ、トラフィックの切り替えをスムーズに行うことが可能です。これにより、ユーザーが新しいバージョンのリリースによる影響を受けることなく、安定したサービスを提供し続けることができます。
実際のプロジェクトでは、さらに複雑なシナリオが想定されるかもしれませんが、Blue/Greenデプロイメントの基本的な仕組みを理解し、導入に取り組むことが重要です。この手法をマスターすることで、システムの可用性と信頼性を向上させることができ、運用効率の改善にもつながります。
また、Blue/Greenデプロイメントを効果的に実施するためには、綿密な計画とテストが欠かせません。環境の切り替え時に発生する可能性のある問題を事前に予測し、対応策を準備することが求められます。これにより、予期せぬトラブルを回避し、スムーズなリリースを実現することができるでしょう。
今回のハンズオンを通じて、Blue/Greenデプロイメントの概念と実践的な手法を学んでいただけたと思います。これを機に、自分のプロジェクトでの活用を検討し、より安定したシステム運用を目指していってください。
参考リンク:ブルーグリーン・デプロイメントとは(Red Hat),[Blue/Green デプロイ(AWS)](https://docs.aws.amazon.com/ja_jp/whitepapers/latest/introduction-devops-aws/blue-green-deployments.html#:~:text=Blue%2FGreen%20(%E3%83%AC%E3%83%83%E3%83%89%2F%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF,%E3%82%92%E8%A7%A3%E6%94%BE%E3%81%99%E3%82%8B%E6%89%8B%E6%B3%95%E3%81%A7%E3%81%99%E3%80%82 "Blue/Green デプロイ(AWS)")