DigitalOceanKubernetesでFlaggerを使用してリリースを段階的に配信する方法

提供:Dev Guides
移動先:案内検索

著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。

序章

Kubernetesでホストされているリソースの更新は、ほぼ即座に伝播されるようにスケジュールされています。 Kubernetesはクラスターの状態を監視し、必要に応じてコンテナーを再起動できますが、不良またはバグのあるコンテナーを処理するための戦略は含まれていません。 つまり、新しいコンテナリリースが適用されて予期しない動作が開始された場合、Kubernetesは、以前のバージョンへのロールバックを開始したり、伝播を完全に停止したりしても、状況を適切に解決できません。

Flagger は、Kubernetesのプログレッシブ配信オペレーターであり、構成されたメトリックを監視しながらトラフィックを新しいリリースに徐々にシフトすることで、概説された問題を解決します。 新しいリリースで自動分析とテストを実行し、クラスター全体に伝播するか、問題が見つかった場合に停止するかを決定できます。 Flaggerは、古いリリースを利用可能な状態に保ちながら、新しいリリースの負荷をゆっくりと増やし、ダウンタイムを最小限に抑えます。 Slack、Microsoft Teams、およびその他のプラットフォームに通知を送信して、発生したイベントをユーザーとチームに通知できます。

このチュートリアルでは、Flaggerをインストールし、それを使用して、DigitalOceanKubernetesクラスターへのpodinfoアプリのプログレッシブ配信を設定します。 podinfoは、実行中の環境に関する詳細を提供するWebアプリです。 デプロイされたリソースを監視し、新しいリリースを自動的にテストし、Webhookを使用してSlackで通知するようにFlaggerを設定します。 最終的に、クラスターデプロイメントを使用できない状態のままにすることなく、要求された変更に問題があるかどうかがすぐに通知されます。

前提条件

このチュートリアルを開始する前に、次のものが必要です。

  • 接続構成がkubectlのデフォルトとして構成されている、DigitalOceanKubernetesクラスターバージョン1.19以降。 kubectlの構成方法については、クラスターの作成時に表示されるクラスターへの接続の手順を参照してください。 DigitalOceanでKubernetesクラスタを作成する方法については、 KubernetesQuickstartをご覧ください。

  • ローカルマシンにインストールされているHelmパッケージマネージャー。 これを行うには、Helm3パッケージマネージャーを使用してKubernetesクラスターにソフトウェアをインストールする方法チュートリアルのステップ1を完了します。

  • クラスターにインストールされているNginxIngressControllerとCert-Manager。 これを行う方法のガイドについては、Helmを使用してDigitalOceanKubernetesでNginxIngressを設定する方法を参照してください。

  • メンバーになっているSlackワークスペース。 ワークスペースの作成方法については、公式ドキュメントにアクセスしてください。

  • Ingressが使用するDigitalOceanロードバランサーを指すDNSAレコードを持つドメイン名。 DigitalOceanを使用してドメインのDNSレコードを管理している場合は、DNSレコードの管理方法を参照してAレコードを作成してください。 このチュートリアルでは、Aレコードをapp.your_domainと呼びます。

    注:このチュートリアルで使用するドメイン名は、 DigitalOceanKubernetes前提条件チュートリアルでNginxIngressを設定する方法で使用するドメイン名とは異なる必要があります。

ステップ1—FlaggerのインストールとNginxIngressControllerの構成

このセクションでは、Helmを使用してFlaggerをクラスターにインストールします。 また、Nginx Ingress Controllerを構成して、内部メトリックを他のアプリケーションからアクセスできるようにします。Flaggerは、パフォーマンスに応じて、新しいリリースを許可するか拒否するかを決定するために使用します。

まず、次のコマンドを実行して、Flaggerを含むリポジトリをHelmに追加する必要があります。

helm repo add flagger https://flagger.app

出力は次のようになります。

Output"flagger" has been added to your repositories

Helmを更新して、Helmに何が含まれているかを知らせます。

helm repo update

次に、次のコマンドを実行してFlaggerをインストールします。

helm install flagger flagger/flagger \
--set prometheus.install=true \
--set meshProvider=nginx

このコマンドは、追加したチャートリポジトリからFlaggerをインストールし、Helmリリースにflaggerという名前を付けます。 Webアプリを監視するため、flaggerリリースはNginxIngressコントローラーに関連付けられます。

出力は次のようになり、Flaggerがデプロイされていることを詳しく説明します。

OutputNAME: flagger
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Flagger installed

Nginx Ingress Controllerの指標を公開するには、すでに定義されている変数を保持したまま、Helmリリース内に追加の変数を設定する必要があります。 これを行うには、helm upgradeを実行し、--reuse-valuesパラメーターを新しい変数値とともに渡します。

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
--reuse-values \
--set controller.metrics.enabled=true \
--set controller.podAnnotations."prometheus\.io/scrape"=true \
--set controller.podAnnotations."prometheus\.io/port"=10254

このコマンドは、nginx-ingress Helmリリースを変更し、コントローラーとそのポッドでPrometheusメトリック収集を有効にします。

出力は次のようになります。

OutputRelease "nginx-ingress" has been upgraded. Happy Helming!
NAME: nginx-ingress
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
...

リビジョン番号が2になり、アップグレードが行われたことを示していることに注意してください。

このセクションでは、Flaggerをインストールし、内部メトリックを公開するようにNginxIngressControllerを構成しました。 次のステップでは、アプリをデプロイし、そのリリースを制御するようにFlaggerを設定します。

ステップ2—アプリをデプロイする

次に、podinfo Webアプリをデプロイし、カナリアリソースを作成してそのリリースを制御します。 カナリアリソースはFlaggerから提供されており、新しいリリースを適用または拒否する前に、どのように、いつ、どのくらいの期間テストするかを示しています。 また、古いリリースから新しいリリースにトラフィックを徐々に迂回させるフローも制御します。

podinfoアプリは、testという名前空間に保存されます。 次のコマンドを実行して作成します。

kubectl create ns test

次に、次のコマンドを実行してpodinfoをデプロイします。

kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main

このコマンドは、公式のFlaggerGitHubリポジトリからpodinfoマニフェストをプルし、それらをクラスターに適用します。

kubectlは、次の出力を表示します。

Outputdeployment.apps/podinfo created
horizontalpodautoscaler.autoscaling/podinfo created

デプロイされていることを確認するには、次のコマンドを実行します。

kubectl get pods -n test

次のような出力が表示されます。

OutputNAME                       READY   STATUS    RESTARTS   AGE
podinfo-78fd6c49bf-jsjm5   1/1     Running   0          18s
podinfo-78fd6c49bf-k2nh4   0/1     Running   0          3s

ポッドが実行されたので、ドメインでアプリを公開するためのIngressを作成します。 podinfo-ingress.yamlというファイルを編集用に開きます。

nano podinfo-ingress.yaml

次の行を追加します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: podinfo
  namespace: test
  labels:
    app: podinfo
spec:
  ingressClassName: nginx
  rules:
    - host: "app.your_domain"
      http:
        paths:
          - pathType: Prefix
            path: "/"
            backend:
              service:
                name: podinfo
                port:
                  number: 80

このイングレスは、app.your_domainドメインでpodinfoサービスを公開します。 忘れずに独自のドメインに置き換えてから、ファイルを保存して閉じてください。

podinfoサービスはまだクラスターに存在しないことに注意してください。 後で、カナリアの一部としてFlaggerによって自動的に作成されます。 これにより、Ingressの展開が妨げられることはありません。

次のコマンドを実行して、Kubernetesにイングレスを作成します。

kubectl apply -f podinfo-ingress.yaml

カナリアを作成する前に、Flaggerのロードテスターをデプロイする必要があります。これにより、カナリアリソースはHTTPリクエストを送信してリリースをテストできます。 次のコマンドを実行して、Helmを使用してtest名前空間にインストールします。

helm install flagger-loadtester flagger/loadtester -n test

Helmは次の出力を表示します。

OutputNAME: flagger-loadtester
LAST DEPLOYED: Thu Jan  6 11:37:45 2022
NAMESPACE: test
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Flagger's load testing service is available at http://flagger-loadtester.test/

次に、カナリアを定義して、podinfo-canary.yamlというファイルに保存します。 次のコマンドを実行して、編集用に開きます。

nano podinfo-canary.yaml

次の行を追加します。

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  provider: nginx
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  ingressRef:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: podinfo
  progressDeadlineSeconds: 60
  service:
    port: 80
    targetPort: 9898
  analysis:
    interval: 10s
    threshold: 10
    maxWeight: 50
    stepWeight: 5
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99
      interval: 1m
    webhooks:
      - name: acceptance-test
        type: pre-rollout
        url: http://flagger-loadtester.test/
        timeout: 30s
        metadata:
          type: bash
          cmd: "curl -sd 'test' http://podinfo-canary/token | grep token"
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://app.your_domain/"

まず、カナリアが存在する名前と名前空間を設定します。 specで、最初にtargetRefを定義します。これは、監視する展開を指定するpodinfoです。 同様に、作成したばかりの付随するIngressは、ingressRefで指定されます。

progressDeadlineSecondsを使用すると、新しい変更が完全に元に戻される前に、カナリアをいつでも最大60秒間アイドル状態にすることができます。 これにより、ストールが防止され、実行の期限が設定されます。 次に、Ingressが使用するpodinfoサービスを定義します。 Flaggerは、カナリアの実行中に複数の一時的なサービスを作成する場合もありますが、メインのサービスはカナリアの存続期間中は常に利用可能です。

analysisブロックは、FlaggerがNginxIngressControllerから受信したメトリックをどのように確認するかを定義します。 intervalは、10秒ごとにそれらを確認するように指示し、thresholdは、新しいリリースがロールバックされる前にメトリックチェックが失敗または使用できなくなる回数を制限します。 maxWeightで指定されているように、新しいリリースにルーティングできるトラフィックの最大パーセンテージは50です。 stepWeightは、テストステップごとにカナリアへのトラフィックがどれだけ増加するかを制御します。

次の2つのセクション、metricswebhooksは、以前にデプロイしたロードテスターを使用してトラフィックを作成し、要求の成功率を監視することによって、新しいリリースをテストする方法を定義します。 成功したリクエストの割合が99% or高い場合、リリースはテストに合格します。

強調表示されたドメインを独自のドメインに置き換えてから、ファイルを保存して閉じることを忘れないでください。

kubectlで展開します。

kubectl apply -f podinfo-canary.yaml

カナリアが作成されているのがわかります。

Outputcanary.flagger.app/podinfo created

これで、app.your_domainに移動できます。 podinfoアプリが表示されます。

メインページには、提供されたpodinfoのバージョンとそのポッドが表示されます。 Ping ボタンを押すと、他のポッドのバージョン番号を更新できます。

Flaggerがカナリアで概説されている構成に従って展開を更新するプロセスを引き継ぐことを確認するには、次のコマンドを実行して、podinfoの別のバージョンを設定します。

kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:6.0.3 -n test

展開が更新されます。

Outputdeployment.apps/podinfo image updated

Flaggerは、デプロイメントリビジョン番号が変更されたことを検出します。これは、podinfoカナリアに関連付けられたイベントを一覧表示することで確認できます。

kubectl describe canary/podinfo -n test

しばらくすると、出力は次のようになります。

OutputEvents:
  Type     Reason  Age                From     Message
  ----     ------  ----               ----     -------
  Normal   Synced  117s               flagger  New revision detected! Scaling up podinfo.test
  Warning  Synced  107s               flagger  canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 2 (readyThreshold 100%) updated replicas are available
  Warning  Synced  97s                flagger  canary deployment podinfo.test not ready: waiting for rollout to finish: 1 of 2 (readyThreshold 100%) updated replicas are available
  Normal   Synced  87s                flagger  Starting canary analysis for podinfo.test
  Normal   Synced  87s                flagger  Pre-rollout check acceptance-test passed
  Normal   Synced  87s                flagger  Advance podinfo.test canary weight 5
  Warning  Synced  67s (x2 over 77s)  flagger  Halt advancement no values found for nginx metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found
  Normal   Synced  57s                flagger  Advance podinfo.test canary weight 10
  Normal   Synced  47s                flagger  Advance podinfo.test canary weight 15
  Normal   Synced  37s                flagger  Advance podinfo.test canary weight 20
  Normal   Synced  27s                flagger  Advance podinfo.test canary weight 25
  ...

Flaggerは、カナリアの定義に従って実行するすべてのアクションをログに記録します。 新しいリビジョンを検出すると、そこからテストポッドを起動し、カナリアウェイトを進めることで分析を開始します。これは、より多くのトラフィックが新しいポッドに転送されていることを意味します。

ブラウザに戻り、アプリが継続的に更新されるときにバージョン番号がちらつくのを確認します。 Flaggerがテスト中の新しいリリースにルーティングされるトラフィックの量を増やしているため、バージョンが変更されています。

Flaggerは、Advance podinfo.test canary weightで始まり、その後に迂回されるトラフィックの割合が続くイベントでトラフィックシフトを示します。

Output...
  Normal   Synced  116s                  flagger  Advance podinfo.test canary weight 10
  Normal   Synced  106s                  flagger  Advance podinfo.test canary weight 15
...

しばらくすると、カナリアの展開が成功し、バージョン番号が安定します。

カナリアの最終的なイベントログは次のようになります。

OutputEvents:
  Type     Reason  Age                   From     Message
  ----     ------  ----                  ----     -------
  Normal   Synced  2m56s                 flagger  New revision detected! Scaling up podinfo.test
  Warning  Synced  2m46s                 flagger  canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 2 (readyThreshold 100%) updated replicas are available
  Warning  Synced  2m36s                 flagger  canary deployment podinfo.test not ready: waiting for rollout to finish: 1 of 2 (readyThreshold 100%) updated replicas are available
  Normal   Synced  2m26s                 flagger  Starting canary analysis for podinfo.test
  Normal   Synced  2m26s                 flagger  Pre-rollout check acceptance-test passed
  Normal   Synced  2m26s                 flagger  Advance podinfo.test canary weight 5
  Warning  Synced  2m6s (x2 over 2m16s)  flagger  Halt advancement no values found for nginx metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found
  Normal   Synced  116s                  flagger  Advance podinfo.test canary weight 10
  Normal   Synced  106s                  flagger  Advance podinfo.test canary weight 15
  Normal   Synced  96s                   flagger  Advance podinfo.test canary weight 20
  Normal   Synced  86s                   flagger  Advance podinfo.test canary weight 25
  Normal   Synced  76s                   flagger  Advance podinfo.test canary weight 30
  Warning  Synced  16s                   flagger  podinfo-primary.test not ready: waiting for rollout to finish: 1 old replicas are pending termination
  Normal   Synced  6s (x6 over 66s)      flagger  (combined from similar events): Routing all traffic to primary

最後のイベントは、トラフィックがプライマリサービスにルーティングされることを示しています。これは、カナリアの展開が完了したことを意味します。

この手順では、podinfoアプリをデプロイし、ドメインで公開するためのIngressを作成しました。 また、新しいデプロイメントリビジョンを制御およびテストするためのカナリアリソースを作成しました。 次に、可視性を高めるためにカナリアイベントをSlackに報告するようにFlaggerを構成します。

ステップ3—Slackへのレポート

これで、ログをSlackワークスペースに送信するようにFlaggerを設定するので、あなたとあなたのチームはいつでもイベントの完全なログをいつでも見ることができます。

Slack統合を使用するには、ワークスペースのSlack着信Webhookが必要です。 着信Webhookは、アプリケーションが他のアプリケーションからのリアルタイム情報を提供するための簡単な方法です。 Webhookを作成したことがない場合は、最初にワークスペース用のアプリを作成する必要があります。

これを行うには、最初にSlackにログインし、アプリ作成ページに移動します。 わかりやすい名前を選び、目的のワークスペースを選択して、アプリの作成をクリックします。

新しいアプリの設定ページにリダイレクトされます。 左側のナビゲーションバーにあるIncomingWebhooksをクリックします。

タイトルActivateIncoming Webhooks の横にあるスイッチボタンを切り替えて、Webhookを有効にします。

ページのさらに下にある新しいセクションが明らかになります。 下にスクロールして、新しいWebhookをワークスペースに追加ボタンをクリックします。 次のページで、レポートの送信先のチャネルを選択し、[許可]をクリックします。

Webhookの設定ページにリダイレクトされ、新しいWebhookが表に表示されます。 コピーをクリックしてクリップボードにコピーし、後で使用できるようにメモしておきます。

ログをSlackに送信するようにFlaggerを構成するには、次のコマンドを実行してHelmリリースを更新する必要があります。

helm upgrade flagger flagger/flagger \
--reuse-values \
--set slack.url=your_hook_URL \
--set slack.channel=your_channel_name \
--set slack.user=username

your_hook_URLを前述のWebhookURLに、your_channel_nameを目的のチャネルの名前に、usernameをWebhookを作成したユーザーのユーザー名に置き換えることを忘れないでください。

--reuse-valuesが渡されるため、Helmは既存のFlaggerリリースに基づいて新しいFlaggerリリースを作成します。 これは、このチュートリアルの最初のステップでNginx Ingress Controllerを再構成したときと同じように、設定された変数の既存の値は変更されないままであることを意味します。

出力は次のようになります。

OutputRelease "flagger" has been upgraded. Happy Helming!
NAME: flagger
LAST DEPLOYED: ...
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
Flagger installed

これで、次のコマンドを実行して、新しいpodinfoデプロイメントのリリースを試みることができます。

kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.1 -n test

間もなくSlackにメッセージが表示されます。

Slackメッセージは、期限や展開を中止する前にテストが失敗する可能性がある回数など、カナリア分析に関する基本的な情報を示しています。 トラフィックルーティングで、表示されている制限に達するまで、各反復中にルーティングされたトラフィックの割合がどの程度増加するかを確認できます。

このリリースがデプロイされると、成功メッセージが表示されます。

Flaggerがどのように失敗を報告するか見てみましょう。 カナリアはすべてのHTTPリクエスト(Nginx Ingress Controllerから読み取る)に対して99 % sの成功率を必要とするため、テスト中に新しいリリースを作成し、そこからHTTP500エラーを生成します。

新しいリリースの場合は、次のコマンドを実行して、6.0.3バージョンを再度デプロイします。

kubectl set image deployment/podinfo podinfod=stefanprodan/podinfo:6.0.3 -n test

FlaggerからのSlackに関する新しいメッセージが表示され、新しいリビジョンが検出されたことを示します。 障害をシミュレートするには、podinfostatus APIを使用します。これにより、指定したHTTPステータスレポートを生成できます。

次のコマンドを実行して、多数のHTTP500ステータスを作成します。

watch curl http://app.your_domain/status/500

しばらくすると、HTTPリクエストの成功率が10回連続で許容できないほど低いため、Flaggerが新しいリリースを適用しないことを決定したことがわかります。

curlを終了するには、CTRL+Cを押します。

これで、podinfoデプロイメントの新しいリビジョンが検出されるたびに、FlaggerがSlackにレポートするようになりました。 また、新しいリリースの結果が通知されるので、あなたとあなたのチームは、アプリのリリースの成功に関して常にループになります。

デプロイしたリソースを破棄するには、次のコマンドを実行します。

kubectl delete -f podinfo-ingress.yaml
kubectl delete -f podinfo-canary.yaml

結論

これで、既存のデプロイに影響を与えることなく、Flaggerを使用してKubernetesクラスターにプッシュされた新しいリリースのテストを自動化する方法を学習しました。 また、Slackへのアラートを設定したので、どのデプロイメントがリアルタイムで行われているかを常に把握でき、新しいリリースに存在する問題について事前に通知されます。

カナリア分析プロセスは、高度なPrometheusクエリで拡張できます。たとえば、HTTPリクエストのレイテンシに応じて動作します。 これについて詳しくは、Flaggerの公式ドキュメントをご覧ください。