Blue-Green Deployment の 簡易版。Docker とかで切り替えるのではなく、フォルダを空にして毎回そこに環境を構築するだけで、サーバ環境自体は使いまわしているので、Immutable ではない。
私は心配性なので(?)
- app8001
- app8002
- app8003
ディレクトリの3運用。それぞれを次のラベルが行き来する。
- prev
- (無印)メイン
- next
だって、Blue-Green だけだったら、
- Green で検証して、Live の Blue を Green に切り替え
- Blue で次期バージョンの検証を始める
- Green で致命的なバグが見つかる、もう一つ前のバージョンでは大丈夫だったのに…
ってなったら戻せないじゃん?まあ、そんなことは滅多にないのかもしれないんだけどさ。
そういうわけで、nodejs アプリの deploy でそういう環境を作っている。後々 Docker に入れるんだけど、今は fossil ってリポジトリも実行ファイルもそれぞれ 1ファイルで持ち運べる git 的なのを使っている。1から環境構築を繰り返すことにこだわらないならば、3つのディレクトリに加えて、親の fossil リポジトリを持っておけば、next になったフォルダでそこから pull するだけで済む。
settings.json
が deploy.sh
の実行で上書き生成されるようになっていて、ポート番号とかをインタラクティブに答える(prev に使っていたディレクトリの中身を next 用に再構築する時に毎回この作業が起こる。ポート番号は変わらないが、1から環境構築を繰り返すのが Blue-Green Deployment っぽいと思ってそういう仕組みにしてみた)。
read -p "port: " port port=${port:-8000} echo -e "{\n \"port\": ${port}\n}" > settings.json
てな具合で、デフォ値を 8000 にしてユーザの入力を受け付けることができる。
参考:
それを本体で
var settings = require('./settings.json');
で呼び出して使っている。お気づきのとおり、初めのディレクトリ名はポート番号をそのまま指している。appの部分はアプリケーション名。参照先のポートを nginx で切り替えるのが切り替えになっている。
location ~ ^/app-prev($|/.*$) { allow xxx.xxx.xxx.xxx; deny all; proxy_pass http://127.0.0.1:8001$1; } location ~ ^/app($|/.*$) { proxy_pass http://127.0.0.1:8002$1; } location ~ ^/app-next($|/.*$) { allow xxx.xxx.xxx.xxx; deny all; proxy_pass http://127.0.0.1:8003$1; }
の数字部分がくるくる。allow, deny は prev と next を IP でアクセス制限してます。
deploy ごとのモジュールのインストール
package.json の dependencies が書いてあれば、npm install
だけで行ける。
参考:
- javascript - How do I update each dependency in package.json to the latest version? - Stack Overflow dependency の数字を update する方法
forever で uid にフォルダ名を付ける
forever start --uid ${PWD##*/} server.js
参考:
- shell - Get current directory name (without full path) in Bash Script - Stack Overflow
${PWD##*/}
のトリックを紹介 - foreverjs/forever
--uid
オプションの説明はここ参照
ユーザデータとかどうするか
データを受け取ってセーブするだけのサーバも切り分けた上で Blue-Green Deployment するのが最強なんだろうけど、Cloud FormationによるBlue-Green Deployment - Dev io mtup11 003 見てもRDSは妥協って書いてたり。僕もそこは妥協してます。あと、一応データ更新に失敗した通知はするようにしている。できるなら lichess.org みたいに、アップデート10秒前に "Brace for Impact." って表示するのはカッコいいと思ってるし、そういうの実装しようかなw