VMで動くソフトウェアをカナリアリリースするソフトウェアを公開しました

k8sに関してはArgo Rolloutsで以上!!!って感じのこの領域ですが、VMで動くソフトウェアを安全にリリースしたかったので開発しました。大まかな流れは下記のとおりです。

  1. GibHubのReleaseをポーリングする
  2. 最新のリリースがあれば、1台のみデプロイする
  3. 指定した時間、ヘルスチェックが通過すれば、残りの全台デプロイする

デプロイや、ロールバック、ヘルスチェックは利用者が任意のスクリプトや、コマンドを準備する必要があります。

例えばdebパッケージをインストールするスクリプトは下記のようになります。

#!/bin/bash
set -e -x
dpkg -i $ASSET_FILE

フックされるスクリプトには、アセットファイルが 環境変数ASSET_FILE として渡ります。またタグはRELEASE_TAG 環境変数にセットされます。

ヘルスチェックについては下記のようにmackerelのpluginを利用したり、任意のコマンドでチェックすることが出来ます。

#!/bin/bash
set -e
check-tcp -p 80 -w 5 -c 10
check-tcp -p 443 -w 5 -c 10
check-log -p critical -f /var/log/nginx/error.log  -w 3 -c 5

またヘルスチェックが失敗した場合は、任意のロールバックを実行できます。下記はdebパッケージをロールバックする例です。

#!/bin/bash
set -e -x
dpkg --force-downgrade -i $ASSET_FILE

この場合、ASSET_FILEは直近インストールされていたバージョンのアセットファイルのパスが環境変数経由で渡されます。

現在インストールされているバージョンを取得するのも任意のスクリプトで実装が可能です。

#!/bin/bash
set -e
echo v`dpkg-query -l yourpackage |grep -oP '(\d+\.\d+\.\d+)'`

このようなスクリプトを設定ファイルや環境変数、コマンドライン引数でパスを指定する必要があります。

# デプロイ時にコールされるスクリプト
deploy_command = "/var/lib/gacr/deploy"
# ロールバック時にコールされるスクリプト
rollback_command = "/var/lib/gacr/rollback"
# ヘルスチェック時のコールされるスクリプト
healthcheck_command = "/var/lib/gacr/healthcheck"
# 現在インストールされているバージョンを取得するスクリプト
version_command = "/var/lib/gacr/get_version"
# 監視するリポジトリ
repo = "STNS/STNS"
# ダウンロードするアセットファイルの正規表現パターン
package_name_pattern = "stns-v.*_amd64.jammy.deb"

# 10秒間でカナリアリリース判定
canary_rollout_window = "1m"
# ヘルスチェックは10秒ごとに実行
healthcheck_interval = "10s"

[redis]
host = "redis"

とりあえず動かして見たい場合、下記のようにdocker-composeで動かすことが出来ます。

$ git clone git@github.com:pyama86/git-assets-canary-releaser.git
$ cd git-assets-canary-releaser
$ GITHUB_TOKEN=xxx make run_example

上記を実行すると私が開発しているSTNSのサーバが自動でインストールされる様子を確認できます。

カナリアリリースの排他制御はRedisのSetNXを利用しています。最近いろんなソフトウェアでSetNX多用しており、こんなに便利で大丈夫???となってます。

最後に、それぞれスクリプトに自由度があるので、色々なところで使えると思います。ぜひアイディアの一つとして考えてみてください!