すべてのプロダクト
Search
ドキュメントセンター

Microservices Engine:Jenkins CI/CD パイプラインによるエンドツーエンドカナリアリリースの実装

最終更新日:Mar 12, 2026

Microservices Engine (MSE) のトラフィックガバナンスを Jenkins CI/CD パイプラインと統合し、マイクロサービスアプリケーションのカナリアリリースを自動化します。このワークフローは、ビルド、デプロイメント、検証、昇格 (またはロールバック) を単一のパイプラインにまとめることで、リリースの速度を維持しながらデプロイメントのリスクを低減します。

仕組み

Jenkins パイプラインは、リリースライフサイクル全体を自動化します。

  1. ビルド -- ソースコードをパッケージ化し、コンテナイメージをビルドします。

  2. カナリアのデプロイ -- 安定したベースバージョンと並行して新しいバージョンをデプロイします。

  3. カナリアトラフィックのルーティング -- MSE は、定義したヘッダー、Cookie、またはリクエストパラメーターに基づいて、トラフィックのサブセットをカナリアにルーティングします。

  4. 検証 -- カナリアが期待どおりに動作することを確認します。

  5. 昇格またはロールバック -- 検証に合格した場合、カナリアを本番環境に完全に昇格させるか、ベースバージョンにロールバックします。

次の図は、アーキテクチャを示しています。

Architecture diagram

MSE は、3 つのカナリアルーティング戦略をサポートしています。

戦略説明
パーセンテージベーストラフィックの固定パーセンテージをカナリアにルーティングします。
ルールベース特定のヘッダー、Cookie、またはリクエストパラメーターに一致するトラフィックをルーティングします。
タグベースカナリアトラフィックを x-mse-tag: gray のような組み込みヘッダーでマークし、呼び出しチェーン全体を通してルーティングします。

このチュートリアルでは、x-mse-tag: gray ヘッダーを使用したタグベースルーティングを使用します。

前提条件

開始する前に、以下が完了していることを確認してください。

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

このチュートリアルでは、ACK クラスターにデプロイされた 5 つのアプリケーションを使用します。

アプリケーション役割コンテナポート
spring-cloud-zuulイングレスゲートウェイ20000
spring-cloud-aアプリケーション A20001
spring-cloud-bアプリケーション B8080
spring-cloud-cアプリケーション C20003
nacos-serverサービスレジストリ (スタンドアロンモード)--

呼び出しチェーンは、spring-cloud-zuul -> spring-cloud-a -> spring-cloud-b -> spring-cloud-c です。

spring-cloud-zuul ゲートウェイは、100 QPS の通常トラフィックと、追加で 10 QPS のカナリアトラフィックを処理します。x-mse-tag: gray ヘッダーを持つリクエストは、gray タグが付いたダウンストリームノードに自動的にルーティングされます。要件に合わせて、gray を任意のカスタムタグ値に置き換えることができます。

ステップ 1:Deployment の作成

  1. ACK コンソールにログインします。左側のナビゲーションウィンドウで、[クラスター] をクリックします。

  2. [クラスター] ページで、対象のクラスター名を見つけてクリックします。

  3. 左側のナビゲーションウィンドウで、[ワークロード] > [Deployments] を選択します。

  4. [YAML から作成] をクリックし、以下の YAML ファイルを適用します。

spring-cloud-zuul (イングレスゲートウェイ)

[YAML を表示]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-cloud-zuul
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-cloud-zuul
  template:
    metadata:
      labels:
        app: spring-cloud-zuul
        msePilotCreateAppName: spring-cloud-zuul
    spec:
      containers:
        - name: spring-cloud-zuul
          image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-zuul:1.0.1
          imagePullPolicy: Always
          ports:
            - containerPort: 20000

spring-cloud-a (ベースバージョン)

[YAML を表示]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-cloud-a
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-a
  template:
    metadata:
      labels:
        app: spring-cloud-a
        msePilotCreateAppName: spring-cloud-a
    spec:
      containers:
      - name: spring-cloud-a
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-a:0.1-SNAPSHOT
        imagePullPolicy: Always
        ports:
        - containerPort: 20001
        livenessProbe:
          tcpSocket:
            port: 20001
          initialDelaySeconds: 10
          periodSeconds: 30

spring-cloud-b (ベースバージョン)

[YAML を表示]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-cloud-b
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-cloud-b
  strategy:
  template:
    metadata:
      labels:
        app: spring-cloud-b
        msePilotCreateAppName: spring-cloud-b
    spec:
      containers:
      - name: spring-cloud-b
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-b:0.1-SNAPSHOT
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 20002
          initialDelaySeconds: 10
          periodSeconds: 30

spring-cloud-c (ベースバージョン)

[YAML を表示]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-cloud-c
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-cloud-c
  template:
    metadata:
      labels:
        app: spring-cloud-c
        msePilotCreateAppName: spring-cloud-c
    spec:
      containers:
      - name: spring-cloud-c
        image: registry.cn-shanghai.aliyuncs.com/yizhan/spring-cloud-c:0.1-SNAPSHOT
        imagePullPolicy: Always
        ports:
        - containerPort: 20003
        livenessProbe:
          tcpSocket:
            port: 20003
          initialDelaySeconds: 10
          periodSeconds: 30

nacos-server (サービスレジストリ) と SLB サービス

[YAML を表示]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nacos-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nacos-server
  template:
    metadata:
      labels:
        app: nacos-server
    spec:
      containers:
      - env:
        - name: MODE
          value: standalone
        image: nacos/nacos-server:v2.2.0
        imagePullPolicy: Always
        name: nacos-server
      dnsPolicy: ClusterFirst
      restartPolicy: Always

# SLB service for the spring-cloud-zuul gateway
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
  name: zuul-slb
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 20000
  selector:
    app: spring-cloud-zuul
  type: LoadBalancer

ステップ 2:デプロイメントの検証

すべてのアプリケーションをデプロイした後、MSE コンソールを開き、アプリケーション A のトラフィックを確認します。すべてのトラフィックは [タグなし] ノードに流れ、カナリアノードにはトラフィックがないはずです。

カナリアルーティング用のレーンの作成

レーンは、MSE がマイクロサービスの呼び出しチェーンを通じてカナリアトラフィックをどのようにルーティングするかを定義します。まずレーングループを設定し、次にルーティングルールを持つレーンを作成します。

ステップ 1:レーングループの作成

  1. MSE コンソールにログインし、上部のナビゲーションバーでリージョンを選択します。

  2. 左側のナビゲーションウィンドウで、[マイクロサービスガバナンス] > [フルトレースグレースケール] を選択します。

  3. [レーングループとレーンの作成] をクリックします。マイクロサービス名前空間にレーングループが既に存在する場合は、[+ レーングループの作成] をクリックします。

  4. レーングループを設定します。

    パラメーター
    レーングループ名レーングループの分かりやすい名前。
    Ingress タイプ[Java マイクロサービスゲートウェイ] を選択します。
    レーングループ トラフィックエントリイングレスアプリケーション (spring-cloud-zuul) を選択します。
    レーングループアプリケーション呼び出しチェーン内のすべてのアプリケーションを選択します。
  5. [OK] をクリックします。

作成後、[フルトレースグレースケール] ページの [レーングループに関連するアプリケーション] セクションにイングレスアプリケーションと関連アプリケーションが表示されることを確認します。レーングループを変更するには、Edit をクリックします。

ステップ 2:レーンの作成

  1. [フルトレースグレースケール] ページで、レーングループと同じマイクロサービス名前空間を選択します。

  2. [クリックして最初の分割レーンを作成] をクリックします。レーンが既に存在する場合は、[レーンの作成] をクリックします。

    重要

    アプリケーションにエンドツーエンドのカナリアリリースを設定すると、これらのアプリケーションはカナリアリリースやタグベースルーティングなどの機能をサポートしなくなります。

  3. レーンパラメーターを設定します:ルーティング条件は、以下のパラメータータイプをサポートしています。

    重要

    どのカナリアルーティング条件にも一致しないトラフィックは、ベースバージョンのタグなしノードにルーティングされます。

    パラメーター説明
    [ノードタグの追加]カナリアノードを識別するためのタグ (例:gray) を追加します。
    [レーン情報の入力][レーンタグ] を設定し、[一致関係の確認] を使用してタグ付けされたノード数を確認します。
    [ルーティングとカナリアリリースのルールの設定]ルーティング条件を定義します (次の表を参照)。
    パラメータータイプ説明
    パラメーターリクエストパラメーター
    ヘッダーリクエストヘッダー
    CookieHTTP Cookie
    本文コンテンツJSON 形式のリクエストボディ
  4. [OK] をクリックします。

設定後、ゲートウェイは次のようにトラフィックをルーティングします。

  • カナリアのルールに一致しないトラフィックは、ベースバージョンに送られます。Base version traffic routing

  • カナリアのルールに一致するトラフィックは、カナリアバージョンに送られます。Canary version traffic routing

Jenkins パイプラインの設定

ステップ 1:イメージレジストリの認証情報の設定

Jenkins がご利用の Container Registry にイメージをプッシュできるように、Kubernetes Secret を作成します。レジストリの認証情報を含む config.json ファイルを生成した後、以下を実行します。

kubectl create secret generic jenkins-docker-cfg -n jenkins --from-file=/root/.docker/config.json

詳細については、「Jenkins を設定してアプリケーション配信パイプラインを構築する」をご参照ください。

ステップ 2:パイプラインの作成

  1. Jenkins ダッシュボードの左側のナビゲーションウィンドウで [新規アイテム] をクリックします。

  2. パイプライン名を入力し、タイプとして [パイプライン] を選択し、[OK] をクリックします。

  3. 設定ページで [パイプライン] タブをクリックし、以下を設定します。

    • [定義][SCM からのパイプラインスクリプト] を選択します。

    • [SCM][Git] を選択します。

    • [リポジトリ URL]:Git リポジトリの URL を入力します。このチュートリアルでは https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/mse-simple-demo を使用します。> 注: ご利用の Jenkins インスタンスが GitHub にアクセスできない場合は、代わりに Gitee のミラーを使用してください。

    • [スクリプトパス]Jenkinsfile と入力します。

  4. [保存] をクリックします。

Jenkinsfile は 4 つのパイプラインステージを定義します。

[Jenkinsfile を表示]

#!groovy
pipeline {

    // ビルドエージェントのラベル
    agent{
        node{
          label 'slave-pipeline'
        }
    }

    // パラメーターから組み立てられたイメージレジストリのパス
    environment{
        IMAGE = sh(returnStdout: true,script: 'echo registry.$image_region.aliyuncs.com/$image_namespace/$image_reponame:$image_tag').trim()
        BRANCH =  sh(returnStdout: true,script: 'echo $branch').trim()
    }
    options {
        // 最大10件のビルドを保持
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }

    parameters {
        string(name: 'image_region', defaultValue: 'cn-shanghai')
        string(name: 'image_namespace', defaultValue: 'yizhan')
        string(name: 'image_reponame', defaultValue: 'spring-cloud-a')
        string(name: 'image_tag', defaultValue: 'gray')
        string(name: 'branch', defaultValue: 'master')
        string(name: 'number_of_pods', defaultValue: '2')
    }

    stages {

        stage('Code packaging') {
            steps{
                container("maven") {
                    echo "Image building......"
                    sh "cd A && mvn clean package"
                }

            }
        }


        stage('Image building and releasing'){
          steps{
              container("kaniko") {
                  sh "kaniko -f `pwd`/A/Dockerfile -c `pwd`/A --destination=${IMAGE} --skip-tls-verify"
              }
          }
        }



        stage('Canary deployment') {
            steps{
                container('kubectl') {
                    echo "Canary deployment......"
                    sh "cd A && sed -i -E \"s/${env.image_reponame}:.+/${env.image_reponame}:${env.image_tag}/\" A-gray-deployment.yaml"
                    sh "cd A && sed -i -E \"s/replicas:.+/replicas: ${env.number_of_pods}/\" A-gray-deployment.yaml"
                    sh "kubectl apply -f A/A-gray-deployment.yaml -n default"
                }
            }
        }

        stage('Completing canary deployment') {
            input {
                message "Are you sure that you want to enable a full release"
                ok "OK"
                parameters {
                    string(name: 'continue', defaultValue: 'true', description: 'true indicates a full release, and false indicates a rollback')
                }
            }
            steps{
                script {
                    env.continue = sh (script: 'echo ${continue}', returnStdout: true).trim()
                    if (env.continue.equals('true')) {
                        container('kubectl') {
                            echo "Full releasing......"
                            sh "cd A && sed -i -E \"s/${env.image_reponame}:.+/${env.image_reponame}:${env.image_tag}/\" A-deployment.yaml"
                            sh "cd A && sed -i -E \"s/replicas:.+/replicas: ${env.number_of_pods}/\" A-deployment.yaml"
                            sh "kubectl apply -f A/A-deployment.yaml -n default"
                        }
                    } else {
                        echo 'Rolling back'
                    }
                    container('kubectl') {
                        sh "kubectl delete -f A/A-gray-deployment.yaml -n default"
                    }
                }
            }
        }
    }
}

パイプラインステージ:

ステージ内容コンテナ
コードのパッケージングMaven (mvn clean package) でアプリケーションをビルドします。maven
イメージのビルドとリリースKaniko でコンテナイメージをビルドし、プッシュします。kaniko
カナリアデプロイメントgray デプロイメントの YAML を新しいイメージタグで更新し、適用します。kubectl
カナリアデプロイメントの完了手動入力を待ちます。昇格するには true、ロールバックするには false を入力します。kubectl

パイプラインパラメーター:

パラメーターデフォルト説明
image_regioncn-shanghaiContainer Registry のリージョン。
image_namespaceyizhanContainer Registry の名前空間。
image_reponamespring-cloud-aイメージリポジトリ名。
image_taggrayカナリアビルドのイメージタグ。
branchmasterビルド元の Git ブランチ。
number_of_pods2Pod レプリカの数。

パイプラインの実行と検証

ステップ 1:パイプラインのビルド

  1. Jenkins ダッシュボードで、パイプライン名の横にある Build をクリックします。

  2. [ビルド] をクリックします。

    説明

    最初のビルドでは、Git リポジトリから設定をプルし、パイプラインを初期化します。エラーが発生した場合は、[パラメーター付きでビルド] をクリックし、パラメーターを設定して再ビルドしてください。

  3. [コード パッケージング][イメージのビルドとリリース]、および [カナリア デプロイメント] ステージが完了するまで待ちます。 パイプラインは [カナリア デプロイメントの完了] ステージで一時停止し、確認待ちの状態になります。

ステップ 2:カナリアデプロイメントの検証

  1. ACK コンソールにログインします。クラスターに移動し、[ワークロード] > [Deployments] を選択します。

  2. spring-cloud-a-gray Deployment が存在し、spring-cloud-a:gray イメージを使用していることを確認します。

  3. [ネットワーク] > [サービス] に移動して名前空間を選択し、[zuul-slb] サービスの [パブリックエンドポイント] をクリックします。

  4. トラフィックルーティングをテストします:通常トラフィック (カナリアヘッダーなし) -- ベースバージョンにルーティングされます:期待される出力:カナリアトラフィック (カナリアタグ付き) -- カナリアノードにルーティングされます:期待される出力:

       curl http://<zuul-slb-public-endpoint>/A/a
       A[10.4.XX.XX] -> B[10.4.XX.XX] -> C[10.4.XX.XX]%
       curl http://<zuul-slb-public-endpoint>/A/a?name=xiaoming
       Agray[10.4.XX.XX] -> B[10.4.XX.XX] -> C[10.4.XX.XX]%
  5. MSE コンソールで、アプリケーション詳細ページを開き、カナリアトラフィックがカナリアノードにルーティングされていることを確認します。

フルリリースへの昇格

検証が合格した後、カナリアを本番環境に昇格させます。

  1. Jenkins ダッシュボードで、パイプライン名をクリックします。

  2. [カナリアリリースの完了] ステージをクリックし、[フルリリースを有効にしますか] ダイアログボックスに true を入力して、[OK] をクリックします。

  3. ACK コンソールで、以下を確認します。

    • spring-cloud-a-gray Deployment が削除されていること。

    • spring-cloud-a デプロイメントは、spring-cloud-a:gray イメージを使用するようになりました。

  4. MSE コンソールで、カナリアトラフィックが表示されなくなったことを確認します。

ロールバック

検証が失敗した場合、ベースバージョンにロールバックします。

  1. Jenkins ダッシュボードで、パイプライン名をクリックします。

  2. [カナリアデプロイメントの完了] ステージをクリックし、[フルリリースを有効にしますか] ダイアログボックスに false と入力し、[OK] をクリックします。

  3. ACK コンソールで、以下を確認します。

    • spring-cloud-a-gray Deployment が削除されていること。

    • spring-cloud-a Deployment が元のイメージバージョンをまだ使用していること。

  4. MSE コンソールで、カナリアトラフィックが表示されなくなったことを確認します。