ブルーグリーンデプロイとカナリアリリースを理解したいならOSSの「Argo Rollouts」で実践しようCloud Nativeチートシート(27)

Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、代表的なデプロイ戦略の「ブルーグリーンデプロイ」と「カナリアリリース」について「Argo Rollouts」で実践する。

» 2023年05月15日 05時00分 公開
[飯野拓人, 岡本隆史, 正野勇嗣株式会社NTTデータ]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

 Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。前回から「Argo Rollouts」に触れ、シリーズを通して概要からハンズオンを交えた使い方までを紹介していきます。前回は第1弾として、Argo Rolloutsの概要とサポートされるデプロイ戦略について解説しました。

 今回は、手を動かすハンズオンを交えて「Argo Rolloutsがどのように動くのか」について理解していただきたいと思います。具体的には、前回紹介した代表的なデプロイ戦略の内「ブルーグリーンデプロイ」と「カナリアリリース」を取り上げ、Argo Rolloutsで指定できるデプロイパラメーターの詳細についても解説します。なお、プログレッシブデリバリーについては次回紹介する予定です。

環境構築

 ハンズオンに当たり、実行環境の準備が必要です。本稿では下記バージョンのソフトウェアで動作を検証します。他のバージョンでも同様に動くと思いますが、全ての環境で検証していないことにご留意ください。

項目 バージョン
Kubernetes v1.26.2
Argo CD v2.6.4
Argo Rollouts v1.4.1

Kubernetesクラスタの作成

 Argo Rolloutsの利用を始める前に、Argo RolloutsおよびアプリケーションをデプロイするKubernetesクラスタを用意してください。

 本稿で利用するサンプルアプリでは「Ingress」を利用します。「minikube」の場合はデフォルトでIngress機能が有効化されていないので、Ingress拡張機能を有効化してください。

minikube addons enable ingress ingress-dns

Argo CDのインストール

 作成したKubernetesクラスタ上に「argocd」ネームスペースを作成し、Argo CDをデプロイします。

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.6.4/manifests/install.yaml

 次のコマンドを別ターミナルで実行します。

kubectl port-forward svc/argocd-server -n argocd 8080:443

 ブラウザで「http://localhost:8080」にアクセスすると、Argo CDのダッシュボード画面にアクセスできます。

Argo CDのログイン画面

※なお、管理者ユーザー「admin」のパスワードは下記コマンドで確認できます。Argo CDにログインが必要になる際に利用してください。

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Argo Rolloutsのインストール

 作成したKubernetesクラスタ上に「argo-rollouts」ネームスペースを作成し、Argo Rolloutsをデプロイします。

kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.4.1/install.yaml

サンプルの取得

 本稿で利用するサンプルを「GitLab」で公開しています。次のコマンド(あるいはご利用のIDE)でGitリポジトリをクローンしてください。

git clone https://gitlab.com/cloudnativetips/argorollouts-sample.git

ブルーグリーンデプロイ

 前回のおさらいですが、ブルーグリーンデプロイは、新バージョンのアプリケーションを別の環境にデプロイし、トラフィックを瞬間的に切り替える方法です。旧バージョンと新バージョンが完全に分離しているので、問題が発生した際に迅速にロールバックできます。

 デプロイ実行における各リソースの動きをArgo Rolloutsコントローラー視点で整理すると、次の通りです。

  • 【1】Rolloutに対して、新バージョン環境の作成を命令する
  • 【2】「Preview」サービスに対して、新バージョン環境にルート切り替えを命令する
  • 【3】「Active」サービスに対して、新バージョン環境にルート切り替えを命令する
  • 【4】Rolloutに対して、旧バージョン環境の削除を命令する
ブルーグリーンデプロイの詳細説明図

 本稿では、ブルーグリーンデプロイの動作を次の手順で確認します。

  • A)Kubernetesマニフェストの準備
    Kubernetesにデプロイするマニフェストファイルを作成する。ただし、Deploymentリソースに対してはDeploymentの代わりにRolloutリソースを利用し、ブルーグリーンデプロイができるようにする
  • B)Argo CDの設定
    本稿ではデプロイ自動化ツールとしてArgo CDを利用するので、Argo CDにマニフェストファイルを格納したGitリポジトリを登録する
  • C)デプロイ実行時の挙動の確認
    旧バージョン(v1)がデプロイされている状態の環境に対して新バージョン(v2)をデプロイした際の挙動を確認する
  • D)ロールバック実行時の挙動の確認
    「旧バージョン(v2)がデプロイされている状態の環境に対して新バージョン(v3)をデプロイしようとしたところ、本番昇格前にアプリケーション側の問題に気付いた」というシナリオを想定して、エンドユーザーに影響を与えずに旧バージョン(v2)に戻す際の挙動を確認する

A)Kubernetesマニフェストの準備

 サンプルリポジトリ「manifests/02_BlueGreen」フォルダ配下にブルーグリーンデプロイに関連するサンプルがあります。ファイル構成は次の通りです。

02_BlueGreen
├── ingress.yaml
├── kustomization.yaml    
├── namespace.yaml
├── rollout.yaml          # Rollout定義
├── service-active.yaml   # 本番トラフィック用Service定義
└── service-preview.yaml  # 試験トラフィック用Service定義

 Argo Rolloutsによるブルーグリーンデプロイのポイントは、次の2つです。

  • Deploymentリソースではなく、Rolloutリソースを利用する
  • サービス定義は、ユーザーからアクセスされるActiveサービスと、リリース前確認用のPreviewサービスの2つを用意する

 特に「Rollout」(rollout.yaml)はArgo Rolloutsの独自リソースであり、今回のハンズオンの肝です。ブルーグリーンデプロイ時は、次のようにRolloutリソース(rollout.yaml)を定義します。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: bluegreen-demo
  labels:
    app: bluegreen-demo
spec:
  replicas: 3
  revisionHistoryLimit: 1
  selector:
    matchLabels:
      app: bluegreen-demo
  template:
    metadata:
      labels:
        app: bluegreen-demo
    spec:
      containers:
      - name: bluegreen-demo
        image: registry.gitlab.com/h-meru/argorollouts-hands-on/hello-world:v1
        imagePullPolicy: Always
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        resources:
          requests:
            memory: 32Mi
            cpu: 5m
  strategy: # この部分が「Rollout」独自の拡張定義
    blueGreen:
      activeService: bluegreen-demo-active    # 本番トラフィック用Service定義
      previewService: bluegreen-demo-preview  # 試験トラフィック用Service定義
      autoPromotionEnabled: false             # 本番自動昇格の無効化
      scaleDownDelaySeconds: 180              # 旧環境の削除猶予期間(秒)

 定義をよく見ると、Deploymentリソースに似ていることが分かります。RolloutリソースはDeploymentリソースの拡張です。「strategy」定義の部分で、ブルーグリーンデプロイやカナリアリリースといったデプロイ戦略を定義します。ここではブルーグリーンデプロイを設定します。

B)Argo CDの設定

 これらのサンプルをArgo CDを用いてデプロイし、旧バージョン(v1)がデプロイされている初期状態を作ります。

 今回はArgo CDに登録するための設定済み定義ファイルを「manifests/argocd/application-bluegreen.yaml」に用意しています。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: bluegreen-demo
spec:
  project: default
  source:
    repoURL: https://gitlab.com/cloudnativetips/argorollouts-sample.git # 同期対象となるGitリポジトリURL
    targetRevision: main # 同期対象となるブランチ名
    path: manifests/02_BlueGreen # 同期対象となるKustomizeファイルパス
  destination:
    server: https://kubernetes.default.svc

 サンプルリポジトリを読者自身の環境にForkする場合は「repoURL」の部分を変更して利用してください。次のコマンドでデプロイできます。

kubectl -n argocd apply -f manifests/argocd/application-bluegreen.yaml

 無事に設定が完了すると、下記画像のようなカードがArgo CDダッシュボード上に表示されていることを確認できます。

ブルーグリーンデプロイにおけるArgo CDの初期画面

 この状態では、まだArgo CDに登録されているだけです。デプロイされているわけではないので、先のカードの「Sync」ボタンから同期します。

 同期が無事に完了すると、カード表示が切り替わることを確認できるので、カードを選択してデプロイされたサンプルを確認します。

ブルーグリーンデプロイにおけるArgo CDの同期完了画面

 ステータスが「Synced」となっており、旧バージョン(v1)のPodが3つ作られていることを確認できます。

C)デプロイ実行時の挙動の確認

 デプロイ実行時の挙動は次の手順に沿って確認します。

  1. 初期状態の確認
    エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」と非公開となるテスト用エンドポイント「bg.preview.dev.sample.io"」に対してリクエストを送信すると、両方とも旧バージョン(v1)からレスポンスが返ることを確認する
  2. 新バージョン環境の作成
    Rolloutのイメージバージョンを新バージョン(v2)に切り替えた後にArgo CDで同期し、ステータスが「Suspended」に変わることを確認する
  3. Previewサービス切り替えの確認
    エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」は変わらず旧バージョン(v1)からレスポンスが返却されるが、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」は新バージョン(v2)からレスポンスが返ることを確認する
  4. 昇格実行
    Argo CDで「Resume」を選択し、ステータスが「Synced」に変わることを確認する
  5. Activeサービス切り替えの確認
    エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」と、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信すると、両方とも新バージョン(v2)からレスポンスが返ることを確認する
  6. 旧バージョン環境の削除
    3分経過後、旧バージョン(v1)環境が削除されることを確認する
ブルーグリーンデプロイのデプロイ実行フロー

・1. 初期状態の確認

 エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」と、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信します。

# エンドユーザーに公開されているエンドポイント
curl -sS bg.active.dev.sample.io | jq
 
# 非公開となるテスト用エンドポイント
curl -sS bg.preview.dev.sample.io | jq

 次のようなレスポンスが返されます。

{
  "message": "Hello World!!!",
  "version": "v1"
}

・2. 新バージョン環境の作成

 デプロイ対象のイメージバージョンを新バージョン(v2)に変更します。ここでは、簡単に操作を試すためにArgo CDの機能を利用してイメージバージョンを変更します。プロジェクトで運用する際には、マニフェスト上(ここではrollout.yaml)のイメージバージョンを変更してGitリポジトリにコミットしてください。Argo CDはGitOpsツールなので、変更したマニフェストをコミットするだけでブルーグリーンデプロイが実施され環境に反映されます。

 Argo CDダッシュボードから「App Details」ボタンを押し、「Parameters」タブの該当箇所を「v2」に変更し「Save」ボタンから保存します。

イメージタグの変更画面

 ステータスが「OutOfSync」に変わった後に「Sync」ボタンを押し、ステータスが「Suspended」に変わることを確認します。

ブルーグリーンデプロイの保留画面

 この画像からも分かる通り、この時点で既に新バージョン(v2)の環境が作成されており、いつでもトラフィックを受け付けられる状態になっています。

・3. Previewサービス切り替えの確認

 エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」に対してリクエストを送信しても、前回と変わらず旧バージョン(v1)からレスポンスが返されます。

{
  "message": "Hello World!!!",
  "version": "v1"
}

 一方で、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信してみると、新バージョン(v2)からレスポンスが返るように変わります。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 これはエンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」側のサービスの向き先は変更されずに、テスト用エンドポイント「bg.preview.dev.sample.io」側のサービスの向き先が新バージョン(v2)に切り替わったからです。この状態なら、エンドユーザーに影響を及ばさずに新バージョン(v2)の環境を検証できます。

・4. 昇格実行

 「新バージョン(v2)の環境に問題がなかった」と仮定し、昇格します。手順はとても簡単で、Argo CDダッシュボードでRolloutリソースを選択した上で「Resume」を選択するだけです。

ブルーグリーンデプロイの昇格画面

 ステータスが「Synced」に変わったら、昇格完了です。

・5. Activeサービス切り替えの確認

 エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」と、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信すると、両方とも新バージョン(v2)からレスポンスが返るように変化します。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 これはエンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」側のサービスの向き先が新バージョン(v2)に切り替わったからです。この時点で全てのリクエストが新バージョン(v2)環境に到達するようになり、旧バージョン(v1)環境はサービスから切り離された状態になります。

・6. 旧バージョン環境の削除

 今回は「scaleDownDelaySeconds: 180」と設定しているので、昇格完了から3分経過すると旧バージョン(v1)の環境が自動的に削除されるようになっています。Argo CDダッシュボード画面を確認すると、確かに新バージョン(v2)の環境のPodが3つある状態になっていることを確認できます。

ブルーグリーンデプロイの削除画面

 以上、ブルーグリーンデプロイにおけるデプロイ実行時の挙動です。

 Argo Rolloutsコントローラー側でReplicaSetの制御やServiceの制御を“よしな”にやってくれているので、運用作業者はデプロイ作業ではなくユーザーへの影響のみに集中できるようになりました。

D)ロールバック実行時の挙動の確認

 先ほどは「新バージョンに問題がなかった」と仮定した際の動きでしたが、リリース作業は100%問題なくできるとは限りません。ここでは、「新バージョン(v3)に問題がある」と仮定し、エンドユーザーへの影響を最小限にするために、迅速に旧バージョン(v2)にロールバックした際の挙動を確認します。次の手順に沿ってロールバック実行時の動きを確認します。

  1. 新バージョン環境の作成
    Rolloutのイメージバージョンを新バージョン(v3)に切り替えた後にArgo CDで「Sync」ボタンを押し、ステータスが「Suspended」に変わることを確認する
  2. Previewサービス切り替えの確認
    エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」は変わらず旧バージョン(v2)からレスポンスを返すが、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」は新バージョン(v3)からレスポンスが返却されることを確認する
  3. ロールバック実行
    Argo CDで「Abort」を選択し、ステータスが「Degraded」に変わることを確認する
  4. 最終状態の確認
    エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」と、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信すると、両方とも旧バージョン(v2)からレスポンスを返すことを確認する
ブルーグリーンデプロイのロールバックの実行フロー

・1. 新バージョン環境の作成

 デプロイ実行時の挙動の確認と同じ手順で、Argo CDダッシュボードから「App Details」ボタンを押し、「Parameters」タブの該当箇所を「v3」に変更して「Save」ボタンで保存します。

 ステータスが「OutOfSync」に変わるので、「Sync」ボタンを押してステータスが「Suspended」に変わることを確認します。

・2. Previewサービス切り替えの確認

 エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」に対してリクエストを送信しても、前回と変わらず旧バージョン(v2)からレスポンスが返却されます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 一方で、非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信すると、新バージョン(v3)からレスポンスが返却されるように変化します。

{
  "message": "Hello World!!!",
  "version": "v3"
}

・3. ロールバック実行

 今回は「新バージョン(v3)に問題があった」と仮定するので、迅速に旧バージョン(v2)にロールバックする必要があります。手順はとても簡単で、Argo CDダッシュボードで「Abort」を選択するだけです。

ブルーグリーンデプロイにおけるロールバックの実行画面

 ステータスが「Degraded」に変わったら、無事にロールバック作業が完了しました。

ブルーグリーンデプロイにおけるロールバックの完了画面

・4. 最終状態の確認

 無事にロールバック作業が完了したので、エンドユーザーに公開されているエンドポイント「bg.active.dev.sample.io」に対してリクエストを送信してみると、旧バージョン(v2)からレスポンスが返却されます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 一方でエンドユーザーに非公開となるテスト用エンドポイント「bg.preview.dev.sample.io」に対してリクエストを送信してみると、503エラーが返却されます。

これは本来存在するはずの新バージョン(v3)の環境がロールバックによって削除されたからです。

 これは望ましい状態ではないので、ロールバックはあくまでも暫定処置として留意し、修正パッチ適用後の正しいアプリケーションを改めてデプロイすることで「Healthy」な状態を目指しましょう。

ブルーグリーンデプロイのパラメーター詳細

 Argo Rolloutsにおけるブルーグリーンデプロイのパラメーターについて、参考までに紹介します。

 Argo Rolloutsにおけるブルーグリーンデプロイでは次の項目を設定できます。

spec:
  strategy:
    blueGreen:
      activeService: string
      previewService: string
      activeMetadata: object
      previewMetadata: object
      autoPromotionEnabled: boolean
      autoPromotionSeconds: int32
      maxUnavailable: stringOrInt
      prePromotionAnalysis: object
      postPromotionAnalysis: object
      previewReplicaCount: int32
      scaleDownDelaySeconds: int32
      scaleDownDelayRevisionLimit: int32
      abortScaleDownDelaySeconds: int32
      antiAffinity: object

 公式HPに掲載されている項目に関しては参照リンクを添付し、掲載されていない項目に関してはGitソースコードから読み解いて解説します。

項目
(デフォルト値)
解説
activeService 旧バージョンのReplicaSetのみにトラフィックを送信するServiceを設定する。これによって通常ユーザーのトラフィックが常に旧バージョンのReplicaSetに到達するようになる
previewService 新バージョンのReplicaSetのみにトラフィックを送信するServiceを設定する。これによって、新バージョンテスト用のエンドポイントが提供される。
新バージョン環境の昇格実行前にテスト用リクエストを送信できるので、基本的に設定することを推奨
activeMetadata 新バージョンのPodが昇格した後に付与されるメタデータ
previewMetadata 新バージョンのPodがデプロイ作業中(昇格前)に付与されるメタデータ。昇格後にこのメタデータは削除される
autoPromotionEnabled
(true)
新バージョンのReplicaSetが正常に起動したら自動的に昇格するようにする。このフィールドが指定されていない場合、デフォルトで有効となる。
ReplicaSetが正常に起動する場合もアプリケーションに問題がある可能性があるので、prePromotionAnalysisやpostPromotionAnalysisを構成しない場合は基本的に無効化を推奨
autoPromotionSeconds ロールアウトが「Suspended」状態になってから指定時間が経過すると、新バージョンのReplicaSetを自動的に昇格する。AutoPromotionEnabledがtrueに設定されている場合、このフィールドは無視される
maxUnavailable
(25%)
デプロイ中に利用できなくなる可能性のあるPodの最大数を定義する。この設定項目は整数値またはパーセンテージを文字列で指定する
prePromotionAnalysis トラフィックを新バージョンに切り替える前処理として「分析」フェーズを構成する。「分析」が正常に終了するまで、サービスの向き先変更を抑止できる。「分析」の成功または失敗によって、昇格作業に移るか、ロールバック作業に移るかが決定される
postPromotionAnalysis トラフィックを新バージョンに切り替えた後の処理として「分析」フェーズを構成する。「分析」が失敗またはエラーになった場合、トラフィックを以前の安定したReplicaSetに切り替える。scaleDownDelaySecondsが指定されている場合、「分析」途中でも実行が中断され、ReplicaSetをスケールダウンさせる
previewReplicaCount 基本的にプレビューのReplicaSetはRolloutで指定されたレプリカ総数に応じてスケールするが、テスト用に完全にスケールアップしたアプリケーションが不要な場合、この機能によってリソースを節約できる。
ブルーグリーンデプロイの良さが失われるので、よほどコスト削減を求められている環境でない限り、設定しないことを推奨
scaleDownDelaySeconds
(30)
アクティブServiceが新バージョンのReplicaSetに切り替わった後、旧バージョンのReplicaSetのスケールダウンを指定時間分だけ遅らせる。
0に設定することで自動スケールダウンを抑止できる
scaleDownDelayRevisionLimit scaleDownDelaySecondsを0に設定した場合、旧バージョンの全てのReplicaSetが残り続けてしまうので、本設定によって保持するReplicaSetの世代数を制限できる
abortScaleDownDelaySeconds
(30)
デプロイ作業を中断した後、新バージョンのReplicaSetのスケールダウンを指定時間分だけ遅らせる。
ロールバック実行後にデプロイ予定だった新バージョン環境が自動的に削除されてしまうと、解析作業を追加できなくなる可能性があるので、適切な値にすることを推奨。
0に設定することで自動スケールダウンを抑止できる
antiAffinity Cluster構成によってはデプロイ完了後に旧バージョン環境が削除された場合、ノードがAutoScalerによって縮退し、縮退したノード上のPodが別のノードに移動されて再起動することがある。ワーカーノードのプールが十分に大きく、かつ、AntiAffinityを設定することで、この頻度を少なくできる

カナリアリリース

 前回のおさらいですが、カナリアリリースは、新バージョンのアプリケーションを一部のユーザー(カナリア)に対して展開し、徐々に全体に展開する方法です。新バージョンのアプリケーションの品質を評価して問題が発生した場合は迅速にロールバックできます。

 デプロイ実行における各リソースの動きをRolloutコントローラー視点で整理すると、次の通りです。

  • 【1】Rolloutに対して、新バージョン環境の最小構成(Pod数=2)での作成を命令する
  • 【2】Ingressコントローラーに対して、カナリア環境へのトラフィック割合の増加を命令する
  • 運用作業者はカナリアユーザーへの影響をモニタリングし、問題ないことを確認する
  • 【3】Rolloutに対して、旧バージョン環境のPod数削減を命令する。
    以下工程を、カナリア環境に全てのトラフィックが流れるまで繰り返す
    1. 【4】【7】【10】【13】Ingressコントローラーに対して、カナリア環境へのトラフィック割合の増加を命令する
    2. 運用作業者はカナリアユーザーへの影響をモニタリングし、問題ないことを確認する
    3. 【5】【8】【11】【14】Rolloutに対して、旧バージョン環境のPod数削減を命令する
    4. 【6】【9】【12】Rolloutに対して、新バージョン環境のPod数増加を命令する

 今回は、段階的にカナリア側のトラフィック割合を増やしては都度問題ないことを確認する流れで説明していますが、初回テスト【2】の段階で問題がないことを確認した後に、そのままカナリア環境に全てのトラフィックを流す運用方法もあります。デプロイにかかる運用コストと品質でバランスを見て、どちらが適切かを判断するといいでしょう。

カナリアリリースの詳細説明図

 本稿では、カナリアリリースの動作を下記の手順で確認します。

  • A)Kubernetesマニフェストの準備
    Kubernetesにデプロイするマニフェストファイルを作成する。ただし、Deploymentリソースに対してはDeploymentの代わりにRolloutリソースを利用し、カナリアリリースができるようにする
  • B)Argo CDの設定
    本稿ではデプロイ自動化ツールとしてArgo CDを利用するので、Argo CDにマニフェストファイルを格納したGitリポジトリを登録する
  • C)デプロイ実行時の挙動の確認
    旧バージョン(v1)がデプロイされている状態の環境に対して新バージョン(v2)をデプロイした際の挙動を確認する
  • D)ロールバック実行時の挙動の確認
    旧バージョン(v2)がデプロイされている状態の環境に対して新バージョン(v3)をデプロイしようとしたところ、カナリアテストの段階でアプリケーション側の問題に気付き、エンドユーザーの影響を最小限に抑えながら旧バージョン(v2)に戻す際の挙動を確認する

 ここからはサンプルを動かして動作を確認します。

A)Kubernetesマニフェストの準備

 サンプルリポジトリの「manifests/03_Canary」フォルダ配下にカナリアリリースに関連するサンプルがあります。ファイル構成は次の通りです。

03_Canary
├── ingress.yaml
├── kustomization.yaml
├── namespace.yaml
├── rollout.yaml         # Rollout定義
├── service-canary.yaml  # Canary側Service定義
└── service-stable.yaml  # Stable側Service定義

 Argo Rolloutsによるカナリアリリースのポイントは、次の2点です。

  • Deploymentリソースではなく、Rolloutリソースを利用する
  • サービス定義は本番トラフィック用の「Stable」サービスと、カナリアトラフィック用の「Canary」サービスの2つを用意する
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: canary-demo
spec:
  replicas: 5
  revisionHistoryLimit: 1
  selector:
    matchLabels:
      app: canary-demo
  template:
    metadata:
      labels:
        app: canary-demo
    spec:
      containers:
      - name: canary-demo
        image: registry.gitlab.com/h-meru/argorollouts-hands-on/hello-world:v1
        imagePullPolicy: Always
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        resources:
          requests:
            memory: 32Mi
            cpu: 5m
  strategy: # この部分が「Rollout」独自の拡張定義
    canary:
      stableService: canary-demo-stable  # Stable側Service定義
      canaryService: canary-demo-canary  # Canary側Service定義
      dynamicStableScale: true           # Stable側Pod数のトラフィックに比例した変動
      minPodsPerReplicaSet: 2            # ReplicaSetにおける最小Pod数
      steps:                             # カナリアリリース工程(詳細は後述)
      - setWeight: 20
      - pause: {}
      - setWeight: 40
      - pause: {duration: 10}
      - setWeight: 60
      - pause: {duration: 10}
      - setWeight: 80
      - pause: {duration: 10}
      trafficRouting:
        nginx:
          stableIngress: canary-demo     # Ingress定義

 ブルーグリーンデプロイと同様に、strategyでデプロイ戦略を設定します。ここではカナリアリリースを設定します。

B)Argo CDの設定

 これらのサンプルを、Argo CDを用いてデプロイし、旧バージョン(v1)がデプロイされている初期状態を作ります。今回はArgo CDに登録するための設定済み定義ファイルを「manifests/argocd/application-canary.yaml」に用意しています。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: canary-demo
spec:
  project: default
  source:
    repoURL: https://gitlab.com/cloudnativetips/argorollouts-sample.git # 同期対象となるGitリポジトリURL
    targetRevision: main # 同期対象となるブランチ名
    path: manifests/03_Canary # 同期対象となるKustomizeファイルパス
  destination:
    server: https://kubernetes.default.svc

 もし、サンプルリポジトリを自分の環境にForkする場合は「repoURL」の部分を変更して利用してください。次のコマンドでデプロイできます。

kubectl -n argocd apply -f manifests/argocd/application-canary.yaml

 無事に設定が完了すると、下記画像のようなカードがArgo CDダッシュボード上に表示されていることを確認できます。

カナリアリリースにおけるArgo CDの初期画面

 この状態は、まだArgo CDに登録されているだけで、デプロイされているわけではありません。先のカードの「Sync」ボタンから同期します。

 無事に同期が完了すると、カード表示が切り替わることを確認できるので、カードを選択してデプロイされたサンプルを確認します。

 ステータスが「Synced」となっており、旧バージョン(v1)のPodが5つ作られていることを確認できます。

カナリアリリースにおけるArgo CDの同期完了画面

C)デプロイ実行時の挙動の確認

 デプロイ実行時の挙動は次の手順に沿って確認します。

  1. 初期状態の確認
    エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信すると、必ず旧バージョン(v1)からレスポンスが返却されることを確認する
  2. 新バージョン環境の作成
    Rolloutのイメージバージョンを新バージョン(v2)に切り替えた後にArgo CDで同期し、ステータスが「Suspended」に変わることを確認する
  3. カナリアテストの確認
    エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」の内、8割は旧バージョン(v1)からレスポンスが返却されるが、残る2割は新バージョン(v2)からレスポンスが返却されることを確認する
  4. 昇格実行
    Argo CDで「Resume」を選択すると、徐々に新バージョン(v2)のPod数が増加し、最終的に全て新バージョン(v2)に置き換わった後にステータスが「Synced」に変わることを確認する
  5. 最終状態の確認
    エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信すると、必ず新バージョン(v2)からレスポンスが返却されることを確認する
カナリアリリースにおけるデプロイの実行フロー

・1. 初期状態の確認

 エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信します。

curl -sS canary.dev.sample.io | jq

 次のようなレスポンスが返却されます。

{
  "message": "Hello World!!!",
  "version": "v1"
}

・2. 新バージョン環境の作成

 デプロイ対象のイメージバージョンを新バージョン(v2)に変更します。

 ここでも、簡単に操作を試すためにArgo CDの機能を利用してイメージバージョンを変更します。開発現場で利用する場合は、Gitリポジトリに変更したマニフェストをコミットするようにしてください。

 Argo CDダッシュボードから「App Details」ボタンを押し、「Parameters」タブの該当箇所を「v2」に変更して「Save」ボタンから保存します。

イメージタグの変更画面

 ステータスが「OutOfSync」に変わった後に「Sync」ボタンを押し、ステータスが「Suspended」に変わることを確認します。

カナリアリリースにおける保留画面

 本来ならカナリア側には2割のトラフィックが到達するので、望ましいカナリア側のPod数は「5 * 0.2 = 1」個のはずです。しかし、「minPodsPerReplicaSet: 2」の設定値によって、最小Pod数が2個と制限されているために上記画像のような構成となります。

・3. カナリアテストの確認

 エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを何回か送付します。

curl -sS canary.dev.sample.io | jq

 2割の確率で次のようなレスポンスが返却されます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 今回は検証の容易性を考慮して2割という大きな値を設定していますが、本番で利用する際はもっと小さな値を設定するといいでしょう。また、実運用ではカナリアの対象とするユーザーをHTTP Headerなどで区分するケースが多いです。今回は検証を簡略化するために省略しています。

・4. 昇格実行

 「新バージョン(v2)の環境に問題がなかった」と仮定し、昇格します。手順はとても簡単で、Argo CDダッシュボードでRolloutリソースを選択した上で「Resume」を選択するだけです。

カナリアリリースにおける昇格画面

 ここで、改めてRolloutの設定値を確認します。

steps:
- setWeight: 20
- pause: {}
- setWeight: 40
- pause: {duration: 10}
- setWeight: 60
- pause: {duration: 10}
- setWeight: 80
- pause: {duration: 10}

 上記設定値は、以下のように読み替えることができます。

  • カナリアテストとして、本番トラフィックのうち2割を利用する
  • 手動での昇格実行を待つ
  • 本番トラフィックのうち4割を新バージョンに割り振る
  • 10秒間一時停止する
  • 本番トラフィックのうち6割を新バージョンに割り振る
  • 10秒間一時停止する
  • 本番トラフィックのうち8割を新バージョンに割り振る
  • 10秒間一時停止する
  • 本番トラフィックを全て新バージョンに割り振る

 今回はArgo Rolloutsのサンプルとして上記のような動きに設定しましたが、実運用ではカナリアテスト後に段階的にトラフィックを増加させずに、全てのトラフィックをカナリア側に振り分ける手法もよく使われます。

 Argo CDダッシュボード画面を確認すると、トラフィック割合に応じて旧バージョン(v1)と新バージョン(v2)の環境のPod数が変動していることが分かります。

 またエンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信すると、デプロイ作業が進むにつれて段階的に次のようなレスポンスが返却される確率が高くなっていることを確認できます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

・5. 最終状態の確認

 先の行程によってトラフィックは全て新バージョン(v2)環境で処理されるようになったはずなので、リクエストを送付して確認します。

カナリアリリースにおける最終画面

 エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信してみると、次のようなレスポンスが必ず返却されるように変化したことを確認できます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 以上が、カナリアリリースにおけるデプロイ時の挙動です。

 Argo Rolloutsコントローラー側でReplicaSetの制御やServiceの制御を“よしな”にやってくれているので、運用作業者はデプロイ作業ではなくユーザー影響のみに集中できるようになりました。

 トラフィックの割合を詳細に制御できるので、アプリケーションの特性に合わせてカスタマイズしやすい点も分かったと思います。

D)ロールバック実行時の挙動の確認

 先ほどは「新バージョンに問題がなかった」と仮定した際の動きでしたが、リリース作業では100%問題なくリリースできるとは限りません。ここでは「新バージョン(v3)に問題がある」と仮定し、エンドユーザーへの影響を最小限にするために迅速に旧バージョン(v2)にロールバックした際の挙動を確認します。次の手順に沿ってロールバック時の動きを確認します。

  1. カナリアテストの確認
    Rolloutのイメージバージョンを新バージョン(v3)に切り替えた後にArgo CDで「Sync」ボタンを押し、ステータスが「Suspended」に変わることを確認する。その後、エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」の内、8割は旧バージョン(v2)からレスポンスが返却されるが、残る2割は新バージョン(v3)からレスポンスが返却されることを確認する
  2. ロールバック実行
    Argo CDで「Abort」を選択し、ステータスが「Degraded」に変わることを確認する
  3. 最終状態の確認
    エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信すると、旧バージョン(v2)からレスポンスが返却されることを確認する
カナリアリリースにおけるロールバックの実行フロー

・1. カナリアテストの確認

 デプロイ実行時の挙動の確認と同じ手順で、Argo CDダッシュボードから「App Details」ボタンを押し、「Parameters」タブの該当箇所を「v3」に変更し「Save」ボタンから保存します。ステータスが「OutOfSync」に変わるので、「Sync」ボタンから同期してステータスが「Suspended」に変わることを確認します。その後、エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを何回か送付します。

curl -sS canary.dev.sample.io | jq

 2割の確率で次のようなレスポンスが返却されます。

{
  "message": "Hello World!!!",
  "version": "v3"
}

・2. ロールバック実行

 今回は新バージョン(v3)のカナリアテストで問題があったと仮定するので、迅速に旧バージョン(v2)にロールバックする必要があります。手順はとても簡単で、Argo CDダッシュボードで「Abort」を選択するだけです。

カナリアリリースにおけるロールバックの実行画面

 ステータスが「Degraded」に変わったら、無事にロールバック作業が完了しました。

カナリアリリースにおけるロールバックの完了画面

・3. 最終状態の確認

 トラフィックは全て新バージョン(v2)環境で処理されるようになったはずなので、リクエストを送付して確認します。

 エンドユーザーに公開されているエンドポイント「canary.dev.sample.io」に対してリクエストを送信してみると、次のようなレスポンスが必ず返却されるように変化したことを確認できます。

{
  "message": "Hello World!!!",
  "version": "v2"
}

 ロールバックの場合は、デプロイ実行時のように段階的にデプロイ状態を推移させるのではなく、迅速に環境が切り替わるかどうかを確認できたと思います。これによって、万が一カナリアテストまたはその後のデプロイ中であってもエンドユーザーへの影響を最小限にとどめることができます。

カナリアリリースのパラメーター詳細

 最後に参考までに、Argo Rolloutsにおけるカナリアリリースのパラメーターを紹介します。Argo Rolloutsにおけるカナリアリリースでは次の項目を設定できます。

spec:
  strategy:
    canary:
      stableService: string
      canaryService: string
      stableMetadata: object
      canaryMetadata: object
      dynamicStableScale: boolean
      maxSurge: stringOrInt
      maxUnavailable: stringOrInt
      minPodsPerReplicaSet: int32
      scaleDownDelaySeconds: int32
      scaleDownDelayRevisionLimit: int32
      abortScaleDownDelaySeconds: int32
      analysis: object
      steps:
        - setWeight: int32
        - pause: object
        - setCanaryScale: object
        - setHeaderRoute: object
        - setMirrorRoute: object
        - analysis: object
        - experiment: object
      antiAffinity: object
      trafficRouting: object
      pingPong: object

 公式HPに掲載されている項目に関しては参照リンクを添付し、掲載されていない項目に関してはGitソースコードから読み解いて解説します。

項目
(デフォルト値)
解説
stableService 旧バージョンのReplicaSetのみにトラフィックを送信するServiceを設定する。これによって通常ユーザーのトラフィックが常に旧バージョンのReplicaSetに到達する
canaryService 新バージョンのReplicaSetのみにトラフィックを送信するServiceを設定する。これによってカナリアユーザーのトラフィックが常に新バージョンのReplicaSetに到達する
stableMetadata 新バージョンのPodが昇格後に付与されるメタデータ
canaryMetadata 新バージョンのPodがデプロイ作業中(昇格前)に付与されるメタデータ。昇格後にはこのメタデータは削除される
dynamicStableScale
(false)
trafficRouting設定を利用した場合、デフォルトではデプロイ中は旧バージョンのReplicaSetを100%にスケールしたままにしておく。これには「デプロイ作業を中断する場合に、トラフィックを遅延なく直ちに旧バージョンのReplicaSetに戻すことができる」という利点がある。一方で、「デプロイ中は最大で2倍のPod数が稼働する」というデメリットもある(ブルーグリーンデプロイと同様)。
カナリアリリースにブルーグリーンデプロイの要素を足すことになるので、可用性という観点だけ見れば利点が多いように思えるが、一般的なカナリアリリースとは異なる挙動になるので、注意が必要
maxSurge
(25%)
最後のsetWeightで指定された割合に移行するためにRolloutが一度に作成できるPodの最大数を定義する。この設定項目は整数値またはパーセンテージを文字列で指定できる
maxUnavailable
(25%)
デプロイ中に利用できなくなる可能性のあるPodの最大数を定義する。この設定項目は整数値またはパーセンテージを文字列で指定できる。MaxSurgeが0の場合、この設定項目値を0にできない
minPodsPerReplicaSet
(1)
trafficRouting設定を利用した場合に利用できる設定項目。カナリア側のReplicaSetに要求されるPodの最小数。これによってカナリアリリース実行時の高可用性を確保できる
scaleDownDelaySeconds
(30)
アクティブServiceが新バージョンのReplicaSetに切り替わった後、旧バージョンのReplicaSetのスケールダウンを指定時間分だけ遅らせる。
0に設定することで自動スケールダウンの抑止も可能
scaleDownDelayRevisionLimit scaleDownDelaySecondsを0に設定した場合、旧バージョンの全てのReplicaSetが残り続けてしまうので、本設定によって保持するReplicaSetの世代数を制限できる
abortScaleDownDelaySeconds
(30)
デプロイ作業を中断した後、新バージョンのReplicaSetのスケールダウンを指定時間分だけ遅らせる。
ロールバック実行後に、デプロイ予定であった新バージョン環境が自動的に削除されてしまうと、追加で解析できなくなる可能性があるので、適切な値にすることを推奨。
0に設定することで自動スケールダウンの抑止も可能
analysis デプロイ時にバックグラウンドで実行する「分析」を定義する。初回デプロイ時にはスキップされる
steps デプロイにおけるReplicaSet制御やトラフィック制御、分析フェーズの追加などを自由にカスタマイズ可能にする項目。具体的な使用方法は本文の中で紹介している
antiAffinity Cluster構成によっては、デプロイ完了後旧バージョン環境が削除された際に、ノードがAutoScalerによって縮退し、縮退したノード上のPodが別のノードに移動されて再起動することがある。ワーカーノードのプールが十分に大きく、AntiAffinityを設定することで、この頻度を少なくできる
trafficRouting 新バージョン〜旧バージョン間のトラフィックの流れを制御するために適用するトラフィック管理ルール。設定しない場合は、デフォルトのPod数に比例したトラフィック比率のルーティングが使用される
nil Ingressコントローラーに応じた、より詳細なトラフィック管理ルールを定義できる。使っているIngressコントローラーが対応しているかどうかの確認が必要
pingPong 「AWS LoadBalancer」をIPモードで利用している場合に、正しくデプロイできなかった問題に対処するために作られた項目。
詳細背景はこちらのリンクを参照

コラム ターミナルからのArgo Rolloutsの操作

 今回は、デプロイ確認としてArgo CDやArgo Rolloutsに標準で用意されているダッシュボード画面(GUI)にブラウザからアクセスしましたが、プロジェクトによってはブラウザでアクセスするのが手間となり、ターミナルからアクセスしたい場合もあると思います。

 そのような場合は、Argo CDやArgo Rolloutsが公式にサポートしている「Kubectl」のプラグインを導入するといいでしょう。プラグインを導入することで、プロモートやロールバック実行やデプロイ状況確認をKubectlコマンドで確認できます。

 インストール方法は次の通りです。

 本ハンズオンで利用する場合、次のコマンドを実行します。

curl -LO https://github.com/argoproj/argo-cd/releases/download/v2.6.4/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

 本ハンズオンで利用する場合、次のコマンドを実行します。

curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.4.1/kubectl-argo-rollouts-linux-amd64
sudo install -m 555 kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts
rm kubectl-argo-rollouts-linux-amd64

次回は、Argo Rolloutsの肝、プログレッシブデリバリー

 今回は、Argo Rolloutsを用いたブルーグリーンデプロイとカナリアリリースを紹介しました。Argo Rolloutsの要となるRolloutリソースとデプロイ、ロールバック操作について理解できたと思います。次回は、Argo Rolloutsの肝、プログレッシブデリバリーを実践します。

Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。