使用APISIX Ingress Controller和Flagger实现平滑的Canary发布
Hengliang Tan
January 19, 2023
著者: 譚恒亮, XPENG エンジニアリングマネージャー
プロジェクト開発の過程において、サービスの更新はしばしば課題となります。最高のユーザー体験を提供するためには、サービスの利用不可リスクを可能な限り回避する必要があります。そこで、継続的デリバリーが誕生し、企業のソフトウェアプラクティスとして受け入れられ、確立された継続的インテグレーションの原則の自然な進化となりました。しかし、管理の複雑さやデプロイ失敗がシステムの可用性に影響を与える恐れから、継続的デプロイメントはまだ非常に稀です。カナリアリリースは、おそらく継続的デリバリーシステムの中で最も古典的なシナリオです。これに基づいて、不健康で問題のあるサービスを迅速に発見し、前のバージョンに簡単にロールバックすることができます。
カナリアリリース
カナリアリリースは、グレイスケールリリースとも呼ばれます。一般的に、アプリケーションの新しいバージョンを「カナリア」としてリリースし、パフォーマンスをテストします。古いバージョンは、同じ段階で通常の操作を維持します。アップグレード中、一部のユーザーは新しいバージョンを使用するように誘導され、他のユーザーは古いバージョンを引き続き使用します。システム全体の安定性を確保する前提で、早期にバグを発見し、タイムリーに調整することが可能です。
カナリアリリースは、更新を直接リリースしません。少数のユーザーに一定の割合のトラフィックをゆっくりと誘導します。エラーが検出されない場合、すべてのユーザーに昇格し、古いバージョンは段階的に廃止されます。この方法により、新しい機能を本番環境に導入するリスクが低減されます。
本記事では、Apache APISIX IngressとFlaggerを使用してスムーズなカナリアリリースを実現し、リリース効率を向上させ、リリースリスクを低減する方法を紹介します。
Apache APISIX Ingressについて
Apache APISIX Ingressは、Apache APISIXをデータプレーンプロキシとして使用するKubernetes Ingress Controllerによって実現されます。ロードバランシング、動的なアップストリーム、カナリアリリース、細かいルーティング、レートリミット、サービスデグレード、サービスサーキットブレーカー、認証、可観測性など、数百の機能を提供します。Zoom、Tencent Cloud、Jiakaobaodian、Horizon Robotics、European Copernicus Reference Systemなど、国内外の企業や組織に採用されています。
Flaggerについて
Flaggerは、CNCF(Cloud Native Computing Foundation)プロジェクトであり、FluxファミリーのGitOpsツールの一部です。最近、CNCFはFluxの正式な卒業を発表し、これはクラウドネイティブ技術の成功と将来性を示す良い指標です。プログレッシブデリバリーツールとして、FlaggerはKubernetes上で実行されるアプリケーションのリリースプロセスを自動化します。新しいソフトウェアバージョンを本番環境に導入するリスクを低減するために、トラフィックを徐々に新しいバージョンにシフトしながら、分析メトリクスを測定し、適合性テストを実行します。
Apache APISIXとFluxコミュニティの継続的な努力の結果、Flaggerは最近v1.27.0をリリースし、Apache APISIX IngressとFlaggerを使用した自動カナリアリリースをサポートしています。
このスムーズなカナリアリリースプロセスを一緒に体験しましょう。
環境
v1.19以降のKubernetesクラスターが必要です。kindを使用してインストールできます。
コンポーネントのインストール
Helm V3を使用してApache APISIXとApache APISIX Ingress Controllerをインストールします。
helm repo add apisix https://charts.apiseven.com
kubectl create ns apisix
helm upgrade -i apisix apisix/apisix --version=0.11.3 \
--namespace apisix \
--set apisix.podAnnotations."prometheus\.io/scrape"=true \
--set apisix.podAnnotations."prometheus\.io/port"=9091 \
--set apisix.podAnnotations."prometheus\.io/path"=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.export_addr.ip=0.0.0.0 \
--set pluginAttrs.prometheus.export_addr.port=9091 \
--set pluginAttrs.prometheus.export_uri=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.metric_prefix=apisix_ \
--set ingress-controller.enabled=true \
--set ingress-controller.config.apisix.serviceNamespace=apisix
FlaggerとPrometheusコンポーネントをapisixネームスペースにインストールします。
helm repo add flagger https://flagger.app
helm upgrade -i flagger flagger/flagger \
--namespace apisix \
--set prometheus.install=true \
--set meshProvider=apisix
注: PrometheusまたはPrometheus Operatorをカスタマイズする必要がある場合は、関連記事を検索して変更してください。
アプリケーションの初期化
Flaggerは、Kubernetesデプロイメントやその他のワークロードに適用でき、HPAと組み合わせることもできます。Kubernetesデプロイメント、ClusterIPサービス、ApisixRouteなど、一連のオブジェクトを作成します。これらのオブジェクトは、アプリケーションを外部クラスターに公開してサービスを提供し、カナリアリリースプロセスの分析に使用されます。
新しいテストネームスペースを作成します:
kubectl create ns test
新しいデプロイメントとHPAを作成します。ここでは、Flaggerの公式コードサンプルを抽出します。
kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main
Flaggerの負荷テストサービスをデプロイし、カナリアリリース中にトラフィックを生成して分析します。
helm upgrade -i flagger-loadtester flagger/loadtester \ --namespace=test
Apache APISIXのApisixRoute
を作成し、Flaggerが作成したリソースを参照し、カナリアバージョンのApache APISIX IngressのApisixRoute
を生成します。(以下の例のapp.example.com
を実際のドメイン名に置き換えてください)
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: podinfo
namespace: test
spec:
http:
- backends:
- serviceName: podinfo
servicePort: 80
match:
hosts:
- app.example.com
methods:
- GET
paths:
- /*
name: method
plugins:
- name: prometheus
enable: true
config:
disable: false
prefer_name: true
これをpodinfo-apisixroute.yaml
として保存し、クラスターに提出します:
kubectl apply -f ./podinfo-apisixroute.yaml
FlaggerのカスタムリソースCanaryを作成します。(例のapp.example.com
を実際のドメイン名に置き換えてください)
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
namespace: test
spec:
provider: apisix
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
# Apisix routeを参照
routeRef:
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
name: podinfo
progressDeadlineSeconds: 60
service:
port: 80
targetPort: 9898
analysis:
interval: 10s
# ロールバックのための最大失敗数
threshold: 10
# カナリアバージョンへの最大トラフィック割合
# (0-100)
maxWeight: 50
# カナリア分析のステップサイズ
# (0-100)
stepWeight: 10
# Prometheusを使用してAPISIXのトラフィック情報を確認
metrics:
- name: request-success-rate
# 最小成功率(5xxレスポンスなし)
# (0-100)
thresholdRange:
min: 99
interval: 1m
- name: request-duration
# P99は最大リクエスト遅延(ms)
thresholdRange:
max: 500
interval: 30s
webhooks:
# カナリア分析のための自動トラフィック、実際のシナリオに基づいて変更
- name: load-test
url: http://flagger-loadtester.test/
timeout: 5s
type: rollout
metadata:
cmd: |-
hey -z 1m -q 10 -c 2 -h2 -host app.example.com http://apisix-gateway.apisix/api/info
これをpodinfo-canary.yaml
として保存し、クラスターに提出します:
kubectl apply -f ./podinfo-canary.yaml
Flaggerは自動的に関連リソースを生成します:
# 提出済み deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo
# 自動生成 deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary
この時点で、ドメイン名app.example.com(例のapp.example.com
を実際のドメイン名に置き換えてください)を介してアプリケーションにアクセスでき、現在のバージョンのアプリケーションが表示されます。
カナリアリリースの自動化
Flaggerは、カナリアノードにトラフィックを徐々にシフトしながら、HTTPリクエストの成功率、平均リクエスト時間、ポッドの健全性などの主要なパフォーマンスメトリクスを測定する制御ループを実装します。関連する指標の分析に基づいて、リリースまたはカナリアデプロイメントを停止し、分析結果をSlack、MS Teams、Prometheus Alert Managerなどの関連プラットフォームに公開します。
コンテナイメージのバージョンを更新してカナリアリリースをトリガーします
kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.1
Flaggerは、デプロイメントの新しいバージョンがあることを検出し、カナリア分析リリースの試行を開始します。
kubectl -n test describe canary/podinfo
Status:
Canary Weight: 0
Conditions:
Message: Canary analysis completed successfully, promotion finished.
Reason: Succeeded
Status: True
Type: Promoted
Failed Checks: 1
Iterations: 0
Phase: Succeeded
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Synced 2m59s flagger podinfo-primary.test not ready: waiting for rollout to finish: observed deployment generation less than desired generation
Warning Synced 2m50s flagger podinfo-primary.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available
Normal Synced 2m40s (x3 over 2m59s) flagger all the metrics providers are available!
Normal Synced 2m39s flagger Initialization done! podinfo.test
Normal Synced 2m20s flagger New revision detected! Scaling up podinfo.test
Warning Synced 2m (x2 over 2m10s) flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available
Normal Synced 110s flagger Starting canary analysis for podinfo.test
Normal Synced 109s flagger Advance podinfo.test canary weight 10
Warning Synced 100s flagger Halt advancement no values found for apisix metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found
Normal Synced 90s flagger Advance podinfo.test canary weight 20
Normal Synced 80s flagger Advance podinfo.test canary weight 30
Normal Synced 69s flagger Advance podinfo.test canary weight 40
Normal Synced 59s flagger Advance podinfo.test canary weight 50
Warning Synced 30s (x2 over 40s) flagger podinfo-primary.test not ready: waiting for rollout to finish: 1 old replicas are pending termination
Normal Synced 9s (x3 over 50s) flagger (combined from similar events): Promotion completed! Scaling down podinfo.test
カナリアリリースプロセス中、ドメイン名app.example.com(実際のドメイン名に置き換えてください)を介してアプリケーションにアクセスすると、異なるレスポンスを受け取ります。
Flaggerによって自動的に作成されたApache APISIXのApisixRoute
リソースpodinfo-podinfo-canary
を表示すると、サービスpodinfo-primary
とサービスpodinfo-canary
の重みがリリースプロセスに伴って変化していることがわかります。
spec:
http:
- backends:
- serviceName: podinfo-primary
servicePort: 80
# Flaggerによって自動調整
weight: 80
- serviceName: podinfo-canary
servicePort: 80
# Flaggerによって自動調整
weight: 20
最終リリースが完了すると、最新の安定バージョンが表示されます。
注: カナリアリリース中にデプロイメントを再度変更すると、Flaggerはカナリア分析を再実行します。
このコマンドで全てのカナリアリリースを観察できます:
watch kubectl get canaries --all-namespaces
NAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME
test podinfo-2 Progressing 10 2022-11-23T05:00:54Z
test podinfo Succeeded 0 2022-11-23T06:00:54Z
ロールバック
カナリアリリース分析中、HTTP 500 Bad Requestを生成してFlaggerがカナリアリリースを中断し、古いバージョンにロールバックすることをテストできます。
別のカナリアリリースをトリガーします:
kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.2
負荷テストコンテナに入ります
kubectl -n test exec -it deploy/flagger-loadtester bash
HTTP 500エラーを生成します:
hey -z 1m -c 5 -q 5 -host app.example.com http://apisix-gateway.apisix/status/500
サーバーの遅延をシミュレートします:
watch -n 1 curl -H \"host: app.example.com\" http://apisix-gateway.apisix/delay/1
検出された失敗の数がカナリア分析の閾値に達すると、トラフィックは自動的にマスターノードに戻り、カナリアノードはゼロにスケールダウンされ、カナリアリリースプロセスは失敗としてマークされます。
kubectl -n apisix logs deploy/flagger -f | jq .msg
"New revision detected! Scaling up podinfo.test"
"canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available"
"Starting canary analysis for podinfo.test"
"Advance podinfo.test canary weight 10"
"Halt podinfo.test advancement success rate 0.00% < 99%"
"Halt podinfo.test advancement success rate 26.76% < 99%"
"Halt podinfo.test advancement success rate 34.19% < 99%"
"Halt podinfo.test advancement success rate 37.32% < 99%"
"Halt podinfo.test advancement success rate 39.04% < 99%"
"Halt podinfo.test advancement success rate 40.13% < 99%"
"Halt podinfo.test advancement success rate 48.28% < 99%"
"Halt podinfo.test advancement success rate 50.35% < 99%"
"Halt podinfo.test advancement success rate 56.92% < 99%"
"Halt podinfo.test advancement success rate 67.70% < 99%"
"Rolling back podinfo.test failed checks threshold reached 10"
"Canary failed! Scaling down podinfo.test"
カナリア分析のためのカスタムメトリクス
Prometheusメトリクスをクエリすることで、カナリア分析を拡張できます。実際のビジネスシナリオに基づいてカスタマイズします。 メトリクステンプレートを作成し、クラスターに提出します。
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: not-found-percentage
namespace: test
spec:
provider:
type: prometheus
address: http://flagger-prometheus.apisix:9090
query: |
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+",
code!~"4.."
}[{{ interval }}]
)
)
/
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+"
}[{{ interval }}]
)
) * 100
# カナリアリリースの分析を変更し、上記で作成した指標テンプレートを追加します。
analysis:
metrics:
- name: "404s percentage"
templateRef:
name: not-found-percentage
thresholdRange:
max: 5
interval: 1m
上記の設定は、HTTP 404リクエストのQPS(1秒あたりのクエリ数)が総トラフィックの5%を超えているかどうかをチェックしてカナリアを検証します。HTTP 404リクエストが5%の閾値を超えると、カナリアロールアウトは失敗します。
まとめ
上記のプロセスは、さらに多くのカスタムメトリクスチェック、Webhook、手動承認、SlackまたはMS Teams通知で拡張できます。
Apache APISIXとFlaggerの統合により、非常にスムーズなカナリアリリースが実現され、リリース効率が向上し、リリースリスクが低減されます。今後、両コミュニティはより緊密に協力し、Blue/GreenミラーリングやA/Bテストなどのより多くのリリース機能を実現します。