BlueとGreenの2世代のDeploymentとEnvoy PodをまとめてデプロイするOperatorを作成し、Envoyの構成を動的に制御するxDSサーバの機能もそのOperatorに組み込めば、Blue-Green Deploymentを標準装備したOperatorが作れそうです。
Operatorのフレームワーク(Operator SDK)とxDSサーバのフレームワーク(go-control-plane)がGitHubに公開されており、どちらもGo言語なので頑張れば一体化できるかもしれません。
...ということで作ってみました。Operatorの構造を下図に示します。
作成したコードはGitHubに公開しました。そのコードをダウンロードしてビルドし、Blue-Green Deploymentのシナリオを実行する手順をここに書き残しておきます。
ビルド済のコンテナイメージがDockerhubにpublicで登録されているので、単に動作を再現するだけなら以下の「実行環境構築」の1,3,4はスキップしても大丈夫です。
ここではOperatorやxDSサーバの実装の詳細には言及しませんが、興味のあるかたは上記のArchitecture図をたよりにソースコードを覗いてみてください。Go初心者のad hocなプログラムなので、Goプログラミングの参考にはなりませんが、動いたという事実と処理の流れくらいは参考になると思います。
動作確認環境は次のとおりです。
- OS: Ubuntu 18.04.1 LTS (Bionic Beaver)
- Golang: go1.15 linux/amd64
- Operator SDK: v0.17.2
- Docker: 19.03.12
- Kubernetes: お好みで (この記事ではIBM Cloud IKSを使用)
Operator SDKはテンプレート(ソースコード)生成時にv0.17.2を使用した都合上、v0.17.2を前提としています(v0.18以上では互換性の問題が出るかもしれません)。他は最新バージョンでいいと思います。
go-control-planeはライブラリとして使用していますが、明示的にインストールする必要はありません。
実行環境構築
1. 前提ソフトウェアをインストール
上記の動作確認環境に必要なソフトウェアをインストールします(手順は各リンク先参照)。
Operator SDKはRELEASE_VERSION=v0.17.2
とする他はリンク先の手順のとおりで大丈夫です。
2. GitHubリポジトリをダウンロード
git clone https://github.com/takeyan/bgdeploy-xds2.git
3. Operatorのコードおよびコンテナイメージをビルド
cd bgdeploy-xds2
export OPERATOR_IMAGE={image name and tag for your container registry}
operator-sdk build $OPERATOR_IMAGE
docker login to your registry
docker push $OPERATOR_IMAGE
4. Operatorのマニフェストファイルを編集
deploy/operator.yaml内でOperatorのイメージ名を参照しているので、上記で指定した名前に変更します。(初期状態ではtakeyan/bgdeploy-oprator:0.1.0となっています)
vi deploy/operator.yaml
5. 以下のマニフェストを適用
kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/crds/swallowlab.com_bgdeploys_crd.yaml
kubectl create -f envoy-configmap.yaml
動作確認シナリオ実行
Operatorはカスタムリソースのマニフェストを定期的にモニターし、マニフェストが変化したらマニフェストの定義に合わせてリソースの状態を変更します。マニフェストのtransitは起動するDeploymentの数を指示しており、OFFの時にはactiveに指定した方のDeploymentとServiceを、ONではblueとgreenの両方とも起動します。activeはEnvoyがリクエストを転送する相手も指示しています。
下図にシナリオの流れを示します。
1. Operatorをデプロイ
kubectl create -f deploy/operator.yaml
2. BGDeployカスタムリソースをデプロイ
kubectl create -f bgdeploy_phase1.yaml
Operatorをデプロイした後初めてカスタムリソースをデプロイするタイミングでは、EnvoyのPodとService、およびOperatorのgrpcポートとhttpポートを公開するためのServiceが起動し、これらはその後稼動し続けます。さらにマニフェストの指定に従ってblueのDeploymentとServiceが起動します。
3. bgdeploy-svc-envoyのNodePort番号を確認
kubectl get svc
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bgdeploy-svc-envoy NodePort 172.21.229.116 <none> 10000:32478/TCP 15m
K8sクラスタ外部からEnvoyに対してHTTP Getを送付するのにNodePortを使用します。EnvoyのhttpリスニングポートにHTTPリクエストを送付すると、EnvoyがblueまたはgreenのServiceにそのリクエストを転送し、応答を返してくれます。
4. HTTP Getリクエストを送付
curl {worker nodeのIPアドレス}:{EnvoyのNodePort番号}/api/echo
# curl 10.242.0.5:32478/api/echo
{"api":"echo","nodename":"10.243.0.4","pod_ip":"172.17.5.151","podname":"bgdeploy-dep-blue-68bb89dbf4-glwkd","query_string":[""],"timestamp":"2020-08-27T11:44:31.500561"}
サンプルアプリは/api/echoというパスでHTTP Getリクエストを受け取ると、Pod名を含むJSONフォーマットのメッセージを返す仕掛けになっています。Pod名に含まれる"blue"または"green"で、Envoyがblue/greenのどちらに振り分けたかが確認できます。
以下のターミナル画面の上段ではcurlを、下段ではkubectl get podとkubectl get service(getall.sh内で呼び出し)をそれぞれ2秒間隔で実行し、マニフェストの更新によってpodとserviceの増減やアプリ応答が変化する様子をモニターします。以下の画面ではblueのpod(bgdeploy-dep-blue-xx-xx)とservice(bgdeploy-svc-blue)が起動しており、curlにはblueが応答していることがわかります。
5. マニフェストを更新し、応答がblueからgreenに変わることを確認
マニフェストのtransitをONに変更します。
kubectl apply -f bgdeploy_phase2.yaml
bgdeploy-phase2.yamlの適用によりtransit=ON, active=blueになると、greenのpodとserviceが起動し、blueとgreenの共存状態となりました。curlには引き続きblueが応答しています。
マニフェストのactiveをgreenに変更します
kubectl apply -f bgdeploy_phase3.yaml
bgdeploy-phase3.yamlの適用によりtransit=ON, active=greenになると、curlに対してgreenが応答するようになりました。podとserviceは引き続きblueとgreenが共存しています。
マニフェストのtransitをOFFに変更します
kubectl apply -f bgdeploy_phase4.yaml
bgdeploy-phase4.yamlの適用によりtransit=OFF, active=greenになると、blueのpodとserviceが停止しました。
まとめ
この記事ではBGDeployというカスタムリソースによるBlue-Green Deploymentの流れををご紹介しました。
OperatorとEnvoyの欲しいところだけをコンパクトに実装したいというニーズは、EdgeコンピューティングとEdge向け軽量K8sの普及に伴って広がってくると思います。どちらもプログラミングするとなると難しそうな印象ですが、フレームワークのおかげで敷居はずいぶん低くなっていると感じました。
この記事がOperatorやEnvoyに興味を持っている方の参考になれば幸いです。
以上です。