ArgoCDとArgo Rolloutsで行うBlue/Green Deployment

今回はArgoCDで管理しているアプリに対してkubernetes上でBule/Green Deploymentをできる様にしてくれる Argo Rolloutsを使用して Blue/Green Deploymentを行う方法を紹介していきます。

環境

Amazon EKS(Fargateを使用しています):  1.16

argocd : 1.6.1

argo-rollouts: 0.9.0

kustomize: 3.8.2

この様な環境で作業を行いました。

EKSの作成などは省略します。 eksctlで作成するのでも問題ありませんが毎回面倒なのでコードで管理したい場合はterraformなどを使用して環境を作成されるのをお勧めします。

前提としてArgoRollouts以外のツールを最低限使用できるという前提で考えています。

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

最初にArgoCDにも接続していない簡単なアプリケーションのデプロイを行います。

僕は簡単なレスポンスを返すアプリでも構いませんし公式のレポジトリで配布されているnginxを使用しても構いません。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app-deployment
spec:
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: app-container
          image: 好みのimageを使用してください。
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: sample-app-service
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  selector:
    app: sample-app

この様な簡単なアプリケーションをkustomizeを使用してデプロイします。

Ingressを使用して外部との通信をできるようにします。 ALB Ingress Controllerを使用しているのでAWSの公式の方法でalb-ingress-controllerをデプロイしてみてください。 Ingressリソースの部分は先ほど作成したServiceに対してトラフィックを流せるようにしたいので編集します

---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: app-a-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80},{"HTTPS": 443}]'
    alb.ingress.kubernetes.io/certificate-arn: <ACMで作成した場合のarn>
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - path: /
            backend:
              serviceName: sample-app-service
              servicePort: 80
          - path: /app-a
            backend:
              serviceName: sample-app-service
              servicePort: 80

次にArgoCDのデプロイです。

ArgoCD

公式の導入方法で導入していただいても構いません

argoproj.github.io

コードでArgoCDを管理してkustomizeでデプロイする際は以下の様にしてワンライナーでbaseを作成できお勧めの使用方法なのでこの方法で試してみてください。

bases:
  - github.com/argoproj/argo-cd/manifests/cluster-install?ref=v1.6.1

GUIの操作やコードで管理するなどのことは今回は割愛しますが実際にはGithubリポジトリとの接続などをmanifest上で管理することをお勧めします。 Githubと接続し参照するmanifestを指定することができたら次のステップ、Argo Rolloutsの導入に進みます。

Argo Rolloutsの導入

こちらも特に指定の方法はなく公式の方法で導入して頂いて構いません。

argoproj.github.io

コードで管理したい場合、Argo RolloutsもArgoCD同様の方法でワンライナーでbaseを作成できるので kustomization.yamlに以下の様に記述してください。

bases:
  - github.com/argoproj/argo-rollouts/manifests/cluster-install?ref=v0.9.0

これで導入することはできます。 kusotmizeだとoverlaysなどで環境毎に設定を変更することができるのですが今回変更することはないのでそのまま進みます。 もしimageの更新などを開発環境だけ適用させたいなどあればそれぞれの環境配下でpatchを当ててkustomizeで更新していく方法をとって各環境問題なく動作していれば最終的にbase側を更新するなどの対応をとってもいいと思います。

今回はnamespaceの作成もkustomizeの一貫で作成したいので namespace.yamlを作成してそこで作っていきましょう。

apiVersion: v1
kind: Namespace
metadata:
  name: argo-rollouts

kustomization.yamlで反映します。

---
namespace: argo-rollouts

commonLabels:
  region: ap-northeast-1

bases:
  - ../../../bases/argo-rollouts

resources:
  - namespace.yaml

こうすることでnamespace、argo-rolloutsが作成され各リソースも作成したnamespaceで作成されます。

DeploymentをRolloutに置き換える

ではここから実際にBule/Green Deploymentを行えるようにする Rollout リソースを作成していきます。

Rolloutリソースは Argo RolloutsでBule/Greenを行うために Deploymentのstrategyフィールドに Blue/Green DeploymentとCanary Releaseを実現するために拡張したCRDになります。

なので先ほど作成したDeploymentのリソースをRolloutに置き換えます

---
apiVersion: argoproj.io/v1alpha1 #apps/v1から置き換え
kind: Rollout #Deploymentから置き換え
metadata:
  name: sample-app-deployment
spec:
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: app-container
          image: 好みのimageを使用してください。
          ports:
            - containerPort: 8080
#ここから下がBule/Greenの設定
  strategy:
      blueGreen:
        activeService: sample-app-service
        previewService: sample-app-preview-service
        autoPromotionEnabled: false

apiVersionとkindの部分を置き換えましたが注目して欲しいのは strategyのフィールドです。 ここでbuleGreenやcanaryを指定してデプロイメントの戦略を決めていきます。

今回はBule/Greenでやっていくので blueGreenを選択してその下のフィールドを設定します。

activeService、previewServiceはそれぞれ本番で稼働しているserviceと検証のために立ち上げているserviceの2種類でactiveServiceに本番で使用するServiceリソースの metadata.namepreviewで使用したいServiceの metadata.nameを記入するようにしてください。

autoPromotionEnabledはpreviewのServiceが立ち上がったら自動的に昇格するか否かを決めるフィールドでdefaultではtureになっています。 今回のBule/Greenでは検証して問題なければ昇格をさせたいのでfalseに値を設定しています。

昇格させる際はargo rolloutのCLIを使用できるkubectlプラグインがありますので以下を参考にして使えるようにしてください。

argoproj.github.io

ServiceとIngresspreview用に作成します。

---
apiVersion: v1
kind: Service
metadata:
  name: sample-app-preview-service
  labels:
    app: sample-app
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
  selector:
    app: sample-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: sample-app-preview-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80},{"HTTPS": 443}]'
    alb.ingress.kubernetes.io/certificate-arn: <ACMのarn>
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - path: /
            backend:
              serviceName: sample-app-preview-service
              servicePort: 80
          - path: /app-a
            backend:
              serviceName: sample-app-preview-service
              servicePort: 80

この設定で先ほどのRollout含めリリースするとServiceとIngressがそれぞれ作成されます。

DeploymentからRolloutにリソースを変更した時の最初の状態はこのような状態になります f:id:yuzun225:20200824122810p:plain

Podに関しては最初は一つしかできてないですがGitOpsのフローに乗ってimage tagが更新されマージされた際に通常であればpodが更新されると思うのですがRolloutリソースがpreview用のPodを作成してくれます。

f:id:yuzun225:20200824123527p:plain

これによって先ほど作成したIngressで作成したALBからアクセスして検証することができるようになります。

最後にこの変更が問題なくサービスに展開したいのであれば

kubectl argo rollouts promote <rollout-service>

これを実行することでpreviewで動いているPodを昇格させることができこれでBule/Greenデプロイの完了です。 また最初のような状態に戻り今まで本番で動いていたPodはしばらくすると自動的に削除されます。

f:id:yuzun225:20200824123652p:plain

簡単なステップでBule/Green デプロイメントを実行することができました。 Ingressのリソースがずっと残ってしまうので費用がかかったりArgoCD側の方でたまに変な挙動になったりと不具合もありそうですが動作としては問題なく使えていました。

今回はあくまで自分の環境下で行いましたがArgoCD上から rollouts promoteコマンドを使えないか、もし使えないのであればChatOpsなどを導入して実行するなどの必要があるかもしれないです。

Argo RolloutsのGUIの画面などもみれたような気がするので今後も調べてみたいと思います。

2020年9月1日追記

ArgoCDのGUI上から実行できることがわかったので方法を追記します。

Rolloutリソースを追加した状態でリリースを行いArgoCDのGUIからRolloutリソースをクリックすると以下のようにメニューが表示されます

f:id:yuzun225:20200901112334p:plain

その項目のResumeを押すことでBuleを昇格させることができる = kubectl argo rollouts promote <rollout-service>と同等のことができるようになります。

argoproj.github.io