PipeCD で Prometheus と連携した Canary Release 分析と Slack 通知を試してみる

こちらは Kubernetes3 Advent Calendar 2020 16日目の記事です。

前回の 記事 では PipeCD の疑問点と回答についてまとめましたが、今回はデプロイと分析周りについてです。

尚、PipeCD 自体については非常に良い記事が公開されていたので、そちらを参考にすると良いかと思います。
GitOps を実現する CD ツール、PipeCD が良さそうという話

概要

現在 PipeCD を使った Kubernetes の GitOps について試しているのですが、今回は以下のようなデプロイの仕組みを構築して、検証してみたのでそれについてまとめてみます。

  • GitOps の Config Repository に変更がマージされたら、1 Pod だけ Canary Pod を Kubernetes 上にデプロイする
  • Canary Pod から取得された Prometheus のメトリクスを使ってエラーレートの分析をする
  • エラーレートが基準値を超えたら自動的にロールバックする
  • デプロイが終了したら Slack に通知する

自分は ArgoCD を使って同じような仕組みを作ったことがあるのですが、その場合は ArgoCD, Argo Rollouts, ArgoCD Notifications を組み合わせて使う必要がありました。

しかし、PipeCD の場合は単体で簡単に実現することができました。

前提

検証時のバージョンは以下のものを使っています。

  • PipeCD: v0.9.0
  • Kubernetes (GKE): v1.16.15
  • Prometheus: v2.18.1

Kubernetes 上には、PipeCD、gRPC Server App、Prometheus がデプロイ済みとします。

また gRPC Server App 上では、gRPC のリクエストを処理した時に grpc_server_handled_total というメトリクスを計測しています。

セットアップ

Piped の設定

Piped の設定ファイル (piped-values.yaml) は以下のように設定します。

args:
  insecure: true

config:
  data: |
    apiVersion: pipecd.dev/v1beta1
    kind: Piped
    spec:
      projectID: YOUR_PROJECT_ID
      pipedID: YOUR_PIPED_ID
      pipedKeyFile: /etc/piped-secret/piped-key
      apiAddress: pipecd:8080
      webAddress: http://pipecd:8080
      syncInterval: 1m
      repositories:
        - repoId: config
          remote: CONFIG_REPO_URL
          branch: master
      analysisProviders:
        - name: prometheus
          type: PROMETHEUS
          config:
            address: http://your-prometheus-address
      notifications:
        routes:
          - name: dev-slack
            events:
              - DEPLOYMENT_SUCCEEDED
              - DEPLOYMENT_FAILED
            envs:
              - dev
            receiver: dev-slack-channel
        receivers:
          - name: dev-slack-channel
            slack:
              hookURL: https://your-slack-hook-url

analysisProviders のセクションで、連携する Prometheus の設定を書いています。
https://pipecd.dev/docs/operator-manual/piped/adding-an-analysis-provider/

notifications のセクションでは、Slack 通知の設定を書いています。ここでは dev environment でデプロイが成功・失敗した場合に、dev-slack-channel に通知する設定となっています。
https://pipecd.dev/docs/operator-manual/piped/configuring-notifications/

設定できたら、helm upgrade で Piped の設定を更新します。
https://pipecd.dev/docs/operator-manual/piped/installation/

Analysis Templateの設定

PipeCD でデプロイ分析 (Automated deployment analysis (ADA)) をする際には、Analysis Template を書いて、これを Deploy Pipeline の設定から参照する形になります。

Analysis Template (analysis-template.yaml) は以下のように設定します。

apiVersion: pipecd.dev/v1beta1
kind: AnalysisTemplate
spec:
  metrics:
    grpc_error_rate:
      provider: prometheus
      # `>= 0` removes `NaN`.
      # `or on() vector(0)` returns `0` if the result is `no data`.
      query: |
        (
          (
            sum(rate(grpc_server_handled_total{pod=~"{{ .Args.serviceName }}-canary-[a-z0-9-]+",code="Internal"}[1m]))
            / 
            sum(rate(grpc_server_handled_total{pod=~"{{ .Args.serviceName }}-canary-[a-z0-9-]+"}[1m]))
          ) >= 0
        ) or on() vector(0)
      expected:
        max: 0.01
      interval: 60s
      failureLimit: 0

この設定ファイルでは grpc_error_rate を Prometheus Query で 60s ごとに取得して、その値が 0.01 を上回ったら失敗とするように設定しています。

Canary Pod には PipeCD が自動で -canary という名前を付与してくれるので、 pod=~"{{ .Args.serviceName }}-canary-[a-z0-9-]+" のように正規表現でマッチするようにしています。
(Args には Deploy Pipeline の設定から任意の文字列を渡すことができます。)

analysis-template.yaml は、Config Repository のルートに .pipe というディレクトリを作り、その下に配置します。

https://pipecd.dev/docs/user-guide/automated-deployment-analysis/#analysis-template

App のデプロイの設定

App のデプロイの設定ファイル (.pipe.yaml) は以下のように設定します。

apiVersion: pipecd.dev/v1beta1
kind: KubernetesApp
spec:
  ...
  pipeline:
    stages:
      - name: K8S_CANARY_ROLLOUT
        with:
          replicas: 1
      - name: WAIT
        with:
          duration: 10s
      - name: ANALYSIS
        with:
          duration: 130s
          metrics:
            - template:
                name: grpc_error_rate
                args:
                  serviceName: grpc-server
      - name: K8S_PRIMARY_ROLLOUT
      - name: K8S_CANARY_CLEAN

今回設定した Deploy Pipeline は以下の Stage で構成されています。

  • K8S_CANARY_ROLLOUT: Canary Pod を1つデプロイ
  • WAIT: デプロイされた Pod が Running になるまで適当に待つ
  • ANALYSIS: Analysis Template で設定した grpc_error_rate の分析を、duration で指定した期間実行
  • K8S_PRIMARY_ROLLOUT: 既存の Pod を新しいバージョンに更新
  • K8S_CANARY_CLEAN: Canary Pod を削除

ANALYSIS Stage で失敗した場合、PipeCD が自動でロールバックしてくれます。

.pipe.yaml は Config Repository に push し、PipeCD の WebUI から App の登録を行います。

動作確認

デプロイ成功したケース

Config Repository を更新して、デプロイを走らせてみます。 デプロイ成功したケースでは、Deploy Pipeline が最後まで実行され、終了後に Slack に通知がきました。

PipeCDのWebUI:

f:id:mura-s:20201215162716p:plain

Slack:

f:id:mura-s:20201215162751p:plain

※ 別の環境で撮った画像なので、今回設定した値とは異なっている部分があります。

デプロイ失敗したケース

ANALYSIS Stage の Prometheus Query が失敗したケースでは、自動的にロールバックが行われ、終了後に Slack に通知がきました。

PipeCDのWebUI:

f:id:mura-s:20201215162801p:plain

Slack:

f:id:mura-s:20201215162812p:plain

※ 別の環境で撮った画像なので、今回設定した値とは異なっている部分があります。

まとめ

PipeCD で Prometheus と連携した Canary Release 分析と Slack 通知が動作していることを確認できました。

概要でも書きましたが、ArgoCD で同じことを実現するためには、いくつか周辺ツールを組み合わせる必要があるので、導入や管理の手間が増えてしまいます。
また、Argo Rollouts を導入するためには Deployment を Rollouts という独自の Resource に変更する必要があり、Deployment に依存していた部分 (例えば Prometheus の Query など) を修正する必要がありました。

PipeCD ではこのような問題を解決できているのが良いなと思いました。

備考

Prometheus の代わりに Thanos に対して Query を投げるように変更してみる

Thanos についてはこちらを参照: https://thanos.io/

Thanos も Prometheus の Query を受けて実行できるはずなので試してみました。
(使用している Thanos のバージョンは v0.13.0 です。)

設定ファイルの変更点は以下の部分です。

piped-values.yaml:

      ...
      analysisProviders:
        - name: thanos
          type: PROMETHEUS
          config:
            address: http://your-thanos-address
      ...

analysis-template.yaml:

apiVersion: pipecd.dev/v1beta1
kind: AnalysisTemplate
spec:
  metrics:
    grpc_error_rate:
      provider: thanos
      ...

これで問題なく動作していました。

Automated deployment analysis (ADA) 周りの Issue について

この検証をしている際にバグっぽい挙動を見つけたので Issue を上げておきました。

後者については ANALYSIS Stage の duration と Query の interval をずらすという回避策がありますし、どちらもクリティカルな問題ではないと思います。