前置きが長いので、さっさと簡単なBlue/Green Deploymentを読ませろって方はコチラ
Kubernetes上のアプリケーションのデプロイ方式
デプロイ方式として筆者が認識しているもので以下の4つが有ります。
- Recreate
- RollingUpdate
- Blue/Green Deployment
- Canary Release
それぞれ一長一短は有りますが、以下のような使い分けが考えられます。
デプロイ方式 | ユースケース |
---|---|
Recreate | DBのマイグレーションを含むような後方互換性の無いアプリケーションのリリース |
RollingUpdate | ダウンタイム無しのリリース |
Blue/Green Deployment | アプリケーションの動作を事前確認しつつ、ダウンタイム無しのリリース |
Canary Release | A/Bテストや一部のユーザだけに先行公開してリリース |
これは筆者の主観ですが、Canary Releaseは多くのアプリ開発の現場では現状too muchだと考えています。
限られたユーザに先行的に公開して新機能の価値仮説を検証するというのは、イノベーター理論でいうアーリアダプター層ぐらいまでしか実践できておらず、マス層は安全にリリースできれば良いと考えていると思っています。
つまり、多くのユーザが望むデプロイ方式はBlue/Green デプロイメントだと考えています。
しかし、ここで問題が有ります。
Kubernetes上にBlue/Green Deploymentでリリース
アプリケーションをKubernetes上にデプロイするためにはK8s標準リソースのDeploymentを使用することが一般的かと思いますが、デプロイ方式としてはRecreateとRollingUpdateしかサポートしておりません。
つまりBlue/Green Deploymentは自前で行う必要が有るのです。
K8s標準リソースのDeploymentとServiceだけでBlue/Green Deployment
Kubernetesの標準リソースのDeploymentとServiceだけでBlue/Green Deploymentをしようと思うと意外と手順が煩雑です。
インタラクティブにmanifestを書き換える必要があります
例えば、Ver1からVer2にアプリケーション(コンテナ)をアップデートする際にBlue/Greenデプロイメントでやりたいとします。
詳細な手順はこちらの記事を確認して頂きたいですが、簡単には以下のようになります。
- Ver2のアプリをデプロイ
- Ver2のアプリに内部からだけアクセスするためのServiceをデプロイする。
- Ver2のアプリの動作に問題ないことを確認する
- Ver1のアプリにルーティングさせているSerivceのSelectorをVer2に切り替える
- Ver1のアプリを削除する。
確かにレガシーなシステムでBlue/Green Deploymentを実現することに比べると格段に楽ではありますが、
以下の様な辛みが残っています。
- 一時的にVer1とVer2のDeploymentを2つ管理しないといけない
- DeploymentのlabelでアプリのVerを管理しないといけない
- ServiceのSelectorを書き換える必要がある
- 使い終わったVer1の片づけをしないといけない
本当にやりたいことは、DeploymentにRollingUpdateのStrategyを書くように、宣言的にBlue/Green DeploymentのStrategyを書き、後はDeploymentのコンテナのタグをVer1⇒Ver2に変更するだけで、Kubernetesに宜しく上記の手順を自動でやってほしいのです。
これを実現してくれる素晴らしいソリューションが有ります。
Argo Rolloutsを使ったBlue/Green Deployment
Argo Rolloutsです。
簡潔にはDeploymentのStrategyにBlue/Green DeploymentとCanary Releaseを対応するように拡張したCRDです。
インストール方法
以下のコマンドでRolloutリソースが扱えるようになります。
$ kubectl create namespace argo-rollouts
$ kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
使用方法
既存のDeploymentを以下のように書き換えます。
apiVersion: argoproj.io/v1alpha1 #apps/v1から書き換え
kind: Rollout #Deploymentから書き換え
# -----この行から下は元のDeploymentと一緒------
metadata:
name: rollout-bluegreen
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollout-bluegreen
template:
metadata:
labels:
app: rollout-bluegreen
spec:
containers:
- name: rollouts-demo
image: gcr.io/heptio-images/ks-guestbook-demo:0.2
imagePullPolicy: Always
ports:
- containerPort: 80
strategy:
# -----この行から上は元のDeploymentと一緒------
# -----この行から下はRolloutの拡張部分------
blueGreen:
# 本番アクセス用のServiceの名前
activeService: rollout-bluegreen-active
# Previewアクセス用のServiceの名前
previewService: rollout-bluegreen-preview
# 手動昇格の有無
autoPromotionEnabled: true
# オプション Preview環境限定でreplicasの上書き
previewReplicaCount: 1
# オプション ReplicaSetが準備完了になってから自動昇格するまでの時間
autoPromotionSeconds: 300
# オプション 新Verにルーティングを切り替えた後に旧VerのPodのスケールダウンを開始させるまでの時間
scaleDownDelaySeconds: 30
後は、Previewアクセス用と本番アクセス用のServiceを用意するだけです。
これでRollout内のimageを書き換えれば自動でBlue/Green Deploymentができます。
kind: Service
apiVersion: v1
metadata:
name: rollout-bluegreen-active
spec:
selector:
app: rollout-bluegreen
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: rollout-bluegreen-preview
spec:
selector:
app: rollout-bluegreen
type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 80
デモ
Serviceと新旧Verのアプリケーションのルーティングの関係を分かりやすくするために、ArgoCDのGUIを使用して説明します。
ArgoCDについては以前ハンズオンしてみた記事を書いたので宜しければ参照ください。
今回使用したmanifestはこちらのリポジトリに有ります。
Ver1のアプリケーションのデプロイ
Rolloutリソースを使用してアプリケーション(Ver1)と、本番アクセスとPreviewアクセス用のServiceをデプロイ。
アプリケーション(Ver1)は本番アクセス用のServiceからすぐにルーティングされます。
Ver2のアプリケーションのデプロイ
Rolloutリソース内のコンテナイメージのタグをVer2に変更して再デプロイ。
まずは、Ver1のアプリケーションはそのままで、Ver2のアプリケーションはPreview用のサービスから自動でルーティングされるようになります。
そして、Ver2のアプリケーションのReplicaSetがReadyになり次第、自動で本番アクセス用のServiceにルーティングが一括で切り替わります。最後にVer1のアプリケーションがシュリンクされます。
ReplicaSetがReadyになった時、自動で本番アクセス用のServiceにルーティングされるようになりますが、Rolloutsに以下のように設定することで手動昇格にすることも可能です。
strategy:
blueGreen:
autoPromotionEnabled: false
デモ手順でいうと、Ver2のアプリケーションがPreview用のサービスからルーティングされるようになった後に停止点が設けられます。
例えばこの手動停止時に、Previe用のアクセス経路からE2Eテスト等を実施することで一般ユーザに公開前に動作確認ができます。
手動昇格する際は、Rolloutsリソースの中のpauseフラグをfalseにします。
$ kubectl patch rollout example-rollout --type merge -p '{"spec": {"paused": false}}'
更にArgoCDに関してはArgo Project繋がりからかGUIから手動昇格が可能になっており、ArgoCDによるGitOpsと相性が良いです。
終わりに
当初はGitOpsでBlue/Green Deploymentをしたかったのですが、インタラクティブなデプロイ方式だと不便だったので、都合の良いソリューション探していたら見つかりました。
同じような悩みを持つ誰かの役に立ちましたら幸いです。