目次
はじめに
Continuous Deliveryの次のステップだと言われているProgressive Deliveryについて
そもそもContinuous Deliveryとは
継続的デリバリとは、新機能、構成変更、バグ修正、実験など、あらゆる種類の変更を、安全かつ迅速に、持続可能な方法で本番環境やユーザーの手元に届ける能力のことです。 私たちの目標は、大規模な分散システム、複雑な本番環境、組み込みシステム、アプリケーションなどのデプロイメントを、必要に応じて実行できる、予測可能な日常業務にすることです。 何千人もの開発者が毎日のように変更を加えても、コードが常にデプロイ可能な状態であることを保証することで、これを実現しています。これにより、従来のように "dev complete "の後に続く統合、テスト、ハードニングのフェーズや、コードのフリーズを完全に排除することができます。 ソフトウェアをより頻繁にデプロイするためには、システムの安定性や信頼性が低くても仕方がないと思われがちです。実際、査読付きの研究によると、そうではないことがわかっています。ハイパフォーマンスのチームは、パフォーマンスの低い競合他社よりも常に速く、信頼性の高いサービスを提供しています。これは、金融サービスや政府機関など、規制の厳しい分野でも同じです。この能力は、それを追求するための努力を惜しまない組織にとって、驚くべき競争上の優位性をもたらします。
- メリット
- Low risk releases
- Faster time to market
- Higher quality
- Lower costs
- Better products
- Happier teams
デプロイ方法の種類
そもそも代表的なデプロイ方法についてまとめ
Rolling Update
デフォルトでk8sがサポート、名前の通り稼働中のPodを随時新しいPodに置き換えていく
(もう一つはRecreateだが多分基本使わない)
シンプルではあるが、全断なしでPodの更新が行えるので、ツール系や重要度の低いシステムのデプロイはRolling Updateで十分
ただ以下のようなデメリットもあるため、他デプロイ手法と比較すると一部システムにおいてはリスクは高くなる
- デプロイにかかる時間が長くなる
- 基本的に1つずつPodを更新するので、Podが大量に存在する場合は完了までに非常に時間がかかる場合がある
- maxSurge maxUnavailableを変更する事で同時に更新を行うPodの割合を設定することも出来るのである程度の時間短縮は出来る
- 例えばPodを半分に減らす事を許容したいとして、アップデート中にリクエストが跳ねるなどがあった場合に捌けるのかどうかの確認が別途必要
- そんなに余裕のある状態で運用できているケースがあるのかもわからないが
- prod環境での一台目動作確認が出来ない
- stg環境で動作確認は出来るが、1podだけ反映して動作確認、ログ確認したいなどの要求には答えられない
- 異なるバージョンが混在する瞬間が発生する
- 新旧を切り替えて互換性をなくすようなデプロイは行えない
- 例えば、新しいバージョンで書き込まれたデータが、古いバージョンでは扱えずにエラーとなるような修正を行ってしまうと、Rolling Update完了までの間に新→旧の順でリクエストを受け付けたユーザーはエラーとなってしまう
- アプリケーション側でハンドリングするなら別
- Blue/Green Deploymentなら綺麗に切り替えられるがロールバックも難しくなる
- そもそもアプリケーションでハンドリングしないでこれを行うなら、デプロイ方法をどうするかよりもシステム毎分けるなりした方が良さそう
- 新旧を切り替えて互換性をなくすようなデプロイは行えない
Blue/Green Deployment
新しいバージョンのアプリケーションが起動する環境を作成し、通信の向き先を新環境に切り替えることでデプロイを行う
API Gatewayなどが前段にあれば、向き先を変えるだけで即座に反映、ロールバックが行える
Rolling Updateと違い、リクエストは受け付けていない新環境が事前に作成されるので、事前に本番環境での動作確認などが行いやすい
主なデメリットとしては
- 必要なリソース量が多い
- 単純に2環境分デプロイするためのリソース容量が必要
- spring bootで構築してるアプリケーションで数十Pod用意しないといけないシステムでブルーグリーンデプロイメントを行う際のリソースの使い具合はなかなかに贅沢
- Goがマイクロサービスやコンテナ環境で愛用されるのを実感
- 単純に2環境分デプロイするためのリソース容量が必要
Canary Release
一部環境orユーザーにだけ新しいバージョンをまず提供し、問題なければ全環境orユーザーに新バージョンを適応する
ローリングアップデートと異なり、最初に一部の環境、リクエストのみ新バージョンを反映する事で、本番環境での確認を可能にしつつ、エラー発生時のリスクを減らすことも出来る
またブルーグリーンデプロイメントのようにリソースを大量に使用する必要もなくなる
ABテストとの違いとして、機能を試したい、調査したいのではなく、リリースに関わるトラブルのリスク軽減が目的
何かツールやサービスメッシュを入れて実現する例もあるが、シンプルにk8sのマニフェストファイルの作り方を工夫する形でも実現できる
- canary用のdeploymentをアプリケーション用とは別に作る
Progressive Deliveryとは
Progressive DeliveryはContinuous Deliveryの次のステップだとされている
様々なデプロイフローや考え方があるが、Progressive Deliveryは更にもう一歩進んだデプロイメントフローだと言える(はず)
従来のContinuous Deliveryはこんな感じ
引用: Leveling Up Your CD: Unlocking Progressive Delivery on Kubernetes – Daniel Thomson & Jesse Suen, Intuithttps://static.sched.com/hosted_files/kccncna19/f2/Progressive Delivery %26 Argo Rollouts.pdf
Progressive Deliveryになるとこうなる 引用: Leveling Up Your CD: Unlocking Progressive Delivery on Kubernetes – Daniel Thomson & Jesse Suen, Intuit
新しいバージョンをリリースする際には、まずカナリーデプロイを行って、一部のユーザー、リクエストに対して反映を行う。ここまでは一般的なカナリーデプロイと同様
異なる点として、全ユーザー、リクエストに反映する前にデプロイしたアプリケーションに対して、メトリクスなどを用いた分析(analyze)を行い、問題なければデプロイの継続、基準を満たさなければロールバックを実行するアクションが明示的に追加されている
今までのデプロイフローと比べると、Analyze、自動ロールバックが追加されてる点が大きな差分
Progressive Deliveryでは従来のデプロイフローの中に明示的に分析や自動ロールバックという観点を加えることで、パイプラインによるデプロイスピードと、デプロイに伴うリスクの軽減を両立することが期待出来る
Progressive Deliveryの説明として、以下のように紹介されていたり
- Progressive delivery is the logical next step for teams who have already implemented agile development, scrums, a CI/CD pipeline, and DevOps. It includes many modern software development processes, including canary deployments, A/B testing, and observability.
- プログレッシブデリバリは、アジャイル開発、スクラム、CI/CDパイプライン、DevOpsをすでに導入しているチームにとって、論理的な次のステップです。カナリーデプロイメント、A/Bテスト、観測性など、多くの最新のソフトウェア開発プロセスが含まれています。
どうやって実現するか
業務で触ったことのあるArgo Rolloutsについて触れる
Argo Rollouts
https://argoproj.github.io/argo-rollouts/
Argo Rollouts is a Kubernetes controller and set of CRDs which provide advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes. Argo Rollouts (optionally) integrates with ingress controllers and service meshes,leveraging their traffic shaping abilities to gradually shift traffic to the new version during an update. Additionally, Rollouts can query and interpret metrics from various providers to verify key KPIs and drive automated promotion or rollback during an update.
Argo Projectsの中の一つであり、Argo RolloutsはBlue/Green Deployment、Canary Release、Progressive Deliveryなどのデプロイ機能をKubernetes上で提供してくれる
Argo Projects → Open source Kubernetes native workflows, events, CI and CD
istioなどのサービスメッシュの導入が不要で、KubernetesのDeploymentをArgo Rolloutsの定義するRolloutリソースに置き換えることで導入が可能なので比較的取り入れやすいのが良い点
さらに、様々なプロバイダー(Prometheusとか)からのメトリクスを用いた検証を組み込んだ上でデプロイフローを構築できるので問題発生時のリカバリも迅速に行える
- Argo Rolloutsで出来ること
- Blue/Green Deployment・Canary Deploymentの利用
- Rolloutというリソースをマニフェストファイルで定義し、その中でリリース方法や設定などを記述することで複数のデプロイパターンを採用することが可能
- カナリーの場合は
pause
を使って、リリースステップをコントロール出来たりもする - https://argoproj.github.io/argo-rollouts/features/bluegreen/
- https://argoproj.github.io/argo-rollouts/features/canary/
- デプロイ状況の分析に応じた継続の判断/自動ロールバック
- 前述したProgressive DeliveryのAnalyzeの部分
- Rollout中に利用するAnalysisを指定し、その結果によってデプロイ・リリースを進行したり、中断して自動的にロールバックすることが可能
- メトリクスや成功/失敗を判定する値を指定してどのような分析をするかを定義したり
- デプロイ状況の分析に使用できるデータとして現状あるのは以下
- Prometheus
- Datadog
- NewRelic
- Job
- Kubernetesジョブ
- Kayenta
- GoogleとNetflixが開発したカナリアリリース分析ツール
- Web
- HTTPリクエスト
- Argo Rolloutsは上記のデータを使用してデプロイを継続するか、中断してロールバックすることができる
- Prometheusを例として上げると、Prometheusからデプロイ対象のingressのhttp_status _codeを用いてHTTP success rateを算出してこの値を閾値として、0.90より上だとデプロイ継続、0.90以下だと中止してロールバックなど
- Experiments
- Canalyデプロイの前段階にExperimentsを実行することもできる
- 本番環境での動作テストを行なったのちに問題がなければ新しいバージョンを展開する。などといったロジック付きのデプロイが実現できそう
- https://argoproj.github.io/argo-rollouts/features/experiment/
- https://qiita.com/inajob/items/1baf2a53581c7a6a9df7
- トラフィックコントロール
- istioなどのservice meshリソースを使う
- https://argoproj.github.io/argo-rollouts/features/traffic-management/
- Blue/Green Deployment・Canary Deploymentの利用
CI/CDフロー例
- DevelopブランチにPR作成
- devクラスタにPRの内容を反映
- Developブランチにマージ
- dev,stg環境に反映
- 各環境に対してintegration-testの実行
- MasterブランチにPR作成
- stg環境に対してintegration-testの実行
- Masterブランチにマージ → カナリアパイプラインが動作
- argo-rolloutsを利用してcanaryリリース
- 全pod数の10%がカナリー対象
- argo rolloutsのexperimentを用いて、サービスイン前に宣言的に動作確認
- カナリー環境に対する動作確認は特定のヘッダーを載せることで行う
- argo-rolloutsのtrafic managementでやる
- argo rolloutsのanalysisを用いて特定の条件に合致した場合は自動ロールバックが行われる
- ルール例
- 5分間の5xxエラーの割合が1%を超えていた場合
- レイテンシーの悪化
- ルール例
- コマンドで明示的に次のステップに進めない限り、全台反映は行われない
- 明らかに全ての障害が補足されるだけの時間でカナリーリリースを行っていると良い(引用: プロダクションレディマイクロサービス)
- テストや外形監視が機能しているのであれば1hや2hたったら自動反映とかでも良いかも
- argo-rolloutsを利用してcanaryリリース
- 全台反映コマンドを実行
- 全podに修正を反映
CI充実させて、experimentにanalysisやk8sのreadinessProbとか外形監視含めた監視周りとかを充実される事でリスクの高いリリースや定義済の検証内容では担保できないリリース以外は自動でデプロイ完了することも目指せそう
導入手順(メモベースで不正確な可能性があるので別途追記)
namespaceを作成してapply
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
Argo Rolloutsを操作するためにkubectl argo pluginのインストール
brew install argoproj/tap/kubectl-argo-rollouts
kubectl argo rollouts version
Rolloutリソースの定義
ほとんど通常のDeploymentと同じ構成で定義可能
Rolloutではspec.strategyにcanaryまたはblueGreenを指定することができるようになる
以下canaryの例
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
strategy:
canary:
maxSurge: 1
maxUnavailable: 1
steps:
- setWeight: 1
- pause: {}
template:
# template以下は通常のtemplateを定義する
このようにsetWeightでCanaryに流すトラフィックを指定し、pauseで条件を満たすまで停止させるといった流れを記述する
pauseではdurationを指定して一定期間待機するといったことができるが、今回のように指定しない場合は先に紹介したpluginのコマンドである kubectl argo rollouts promoteを受け付けるまで停止する
setWeight、pauseは複数書けるので例えばsetWeightを指定した後promoteコマンドを受け付けるまで待機し、その後はduration指定により徐々にデプロイを拡大していくといったより細かい設定も可能
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
strategy:
canary:
maxSurge: 1
maxUnavailable: 1
steps:
- setWeight: 1
- pause: {} # promoteを待機
- setWeight: 10
- pause: { duration: 1m } # 1分待機
- setWeight: 50
- pause: { duration: 10s } # 10秒待機
template:
# template以下は通常のtemplateを定義する
- https://argoproj.github.io/argo-rollouts/features/canary/
- https://argoproj.github.io/argo-rollouts/features/bluegreen/
デプロイ
デプロイ方法の詳細は省略。ローカルで試すだけなのでシンプルにkubectl apply
kubectl pluginのgetコマンドで状態を可視化できる
$ kubectl argo rollouts get rollout sample-api --watch
Name: samle-api
Namespace: default
Status: ✔ Healthy
Strategy: Canary
Step: 2/2
SetWeight: 100
ActualWeight: 100
Images: sample-api:latest (stable)
Replicas:
Desired: 2
Current: 2
Updated: 2
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ sample-api Rollout ✔ Healthy 2m53s
└──# revision:1
└──⧉ sample-api-6968f97dbf ReplicaSet ✔ Healthy 2m53s stable
├──□ sample-api-6968f97dbf-97fs7 Pod ✔ Running 2m53s ready:4/4
└──□ sample-api-6968f97dbf-zgbwt Pod ✔ Running 2m53s ready:4/4
イメージタグを変更してみる
$ kubectl argo rollouts set image sample-api sample-api=sample-api:20210121-072400
rollout "sample-api" image updated
結果
$ kubectl argo rollouts get rollout sample-api --watch
Name: sample-api
Namespace: default
Status: ॥ Paused
Message: CanaryPauseStep
Strategy: Canary
Step: 1/2
SetWeight: 50
ActualWeight: 50
Images: sample-api:20210121-072400 (canary)
sample-api:latest (stable)
Replicas:
Desired: 2
Current: 2
Updated: 1
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ sample-api Rollout ॥ Paused 8m35s
├──# revision:2
│ └──⧉ sample-api-56fcdff5bf ReplicaSet ✔ Healthy 2m8s canary
│ └──□ sample-v2-56fcdff5bf-8mhcm Pod ✔ Running 2m8s ready:4/4
└──# revision:1
└──⧉ sample-api-6968f97dbf ReplicaSet ✔ Healthy 8m35s stable
└──□ sample-api-6968f97dbf-zgbwt Pod ✔ Running 8m35s ready:4/4
100%デプロイ
kubectl argo rollouts promote sample
Kustomizeを使う場合
まず以下のconfigを設定する必要がある
https://argoproj.github.io/argo-rollouts/features/kustomize/
また加えて、kustomizeはcustom resourceの場合はうまくパッチマージできないらしい
https://github.com/argoproj/argo-rollouts/issues/538
https://github.com/jessesuen/kustomize-examples/tree/master/strategic-merge-patch-crd-fail
なのでjson形式でpatchを書く必要がある
https://github.com/kubernetes-sigs/kustomize/blob/master/examples/jsonpatch.md
patchesJson6902を使う
kind: Kustomization
namespace: sample-api
bases:
- ../../../base
patchesStrategicMerge:
- deployment.yaml
patchesJson6902:
- path: transform_to_rollout.json
target:
group: apps
version: v1
kind: Deployment
name: sample-api
[
{
"op": "replace",
"path": "/apiVersion",
"value": "argoproj.io/v1alpha1"
},
{
"op": "replace",
"path": "/kind",
"value": "Rollout"
},
{
"op": "add",
"path": "/spec/strategy",
"value": {
"canary": {
"steps": [
{
"setWeight": 10
},
{
"pause": {}
}
]
}
}
}
]
Analysisを指定してみる
追記
まとめ
目指せオール自動デプロイ
参考
Leveling Up Your CD: Unlocking Progressive Delivery on Kubernetes
Progressive Delivery
Argo Rollouts
What Is Progressive Delivery All About?
GKE + Istio + FlaggerによるProgressive Delivery
Argo Rolloutsに入門する
Argo RolloutsによるProgressive Delivery
Delivering progressive delivery with service mesh
https://devopsinstitute.com/progressive-delivery/
https://www.split.io/glossary/progressive-delivery/