Help us understand the problem. What is going on with this article?

Kubernetesで超簡単にBlue/Green Deploymentを実現する

More than 1 year has passed since last update.

前置きが長いので、さっさと簡単な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デプロイメントでやりたいとします。
詳細な手順はこちらの記事を確認して頂きたいですが、簡単には以下のようになります。

  1. Ver2のアプリをデプロイ
  2. Ver2のアプリに内部からだけアクセスするためのServiceをデプロイする。
  3. Ver2のアプリの動作に問題ないことを確認する
  4. Ver1のアプリにルーティングさせているSerivceのSelectorをVer2に切り替える
  5. 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からすぐにルーティングされます。

Cut2019_1116_1149_52.jpg

Ver2のアプリケーションのデプロイ

Rolloutリソース内のコンテナイメージのタグをVer2に変更して再デプロイ。

まずは、Ver1のアプリケーションはそのままで、Ver2のアプリケーションはPreview用のサービスから自動でルーティングされるようになります。

Cut2019_1116_1152_26.jpg

そして、Ver2のアプリケーションのReplicaSetがReadyになり次第、自動で本番アクセス用のServiceにルーティングが一括で切り替わります。最後にVer1のアプリケーションがシュリンクされます。

Cut2019_1116_1153_26.jpg

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をしたかったのですが、インタラクティブなデプロイ方式だと不便だったので、都合の良いソリューション探していたら見つかりました。
同じような悩みを持つ誰かの役に立ちましたら幸いです。

ttr_tkmkb
某SI企業でコンテナとかAWSを中心にインフラエンジニアをやっています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away