ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

Argo Rollouts を使った Canary Release

はじめに

今年は Progressive Delivery をやっていくぞ!という気持ちでいろいろ調べたり試したりしています。その中で、試すのにもっともハードルが低い Argo Rollouts を使っていき、実際に導入するまでを説明していきます。

本当のところを言うと Argo Rollouts 良さそうっスよ、とか言ってたら速度で同僚の mtsm さんRails Upgrade の文脈で素振って使いはじめてあれよあれよと明日本番でやるということで、お任せしてもいいんですがまぁ一応ね、ちゃんと追いつくぐらいはしとかないとね、と思い慌ててまとめています。

Argo Rollouts

オフィシャルドキュメントがちゃんとしているのは最高ですね。

argoproj.github.io

Argo Family の1つで、Kubernetes Deployment の代替となるものです。Deployment と同様に Replicaset を子リソースとして持ちます。通常 Kubernetes Deployment は Replicaset の入れ替えに Recreate か Rolling Update といったStrategy によって行われますが、Rollouts はこの Strategy をより詳細に定義できるリソースです。

何ができるのか

strategy field で step を定義し、replicaset を移り変わる際の挙動を指定できます。

setWeight: 10

Canary 中に Update を進める割合です。これだと 10% を意味しますが、実態は replicaset なので、どう頑張っても pod の数の粒度でしか進めることができないことが注意点です。

argoproj.github.io

important note に書いてますが、round up されます。

pause

止まります。言い換えると、人間の判断を待ちます。

dashboard なのかなんなのかを見て、Yoshi! となってから、promote と呼ばれるコマンドを実行することで次の step に進みます。

なおこの Pause に Duration をつけることも可能で、つけた場合は指定した時間待機して、次の step に進むことになります。

その他の機能

ざっと見ていきましょう。

  • analysis: これは重要です。決められた条件を満たさなければ、rollout は abort となり、元に戻ります。これについてはあとで詳しく掘っていきましょう。
  • antiAffinity: 古い version の replicaset と新しい version の replicaset が同じ node に schedule されないように、RequiredDuringSchedulingIgnoredDuringExecution を set すればいいってやつ。なんでかというと古い version と 新しい version の pod が同一 node に混在していた場合、古い version がスケールインした場合、新しい pod がのっている node は Cluster Autoscaler によって縮退されてしまうから。でもそういうことあるかな。。。そもそも PodAntiAffinity を基本 Production では有効にしているので不要な気がする。
  • canaryService: 有効にすると canary 先の新しい replicaset にだけ traffic を流す。これ、なんのためかわかんなかったけど前方互換性がない場合のためかな?でもそれ割合によって capacity 激落ちするけどいいんだっけという。
  • stableService: stable, つまり canary 先ではないほうを常に参照するようにする。これもなんのためにやんだっけと思うんだがユーザに公開せず deploy して、canary の replicaset には何らかの方法で特別にアクセスするのか?traffic routing のところの header とか使って。
  • maxSurge: 各 step の setWeight した場合に遷移する際に作られる pod の maxSurge。意味あるんだろうか。。。
  • maxUnavailable: 上に同じ。default 0 だし、それでいいんではないか。
  • trafficRouting: 基本は新旧の replicaset の pod の割合で weighted loadbalancing されるが、特殊なルールを設定できる。が、これは Advanced かな。Pod 単位より小さい割合での Traffic Spliting だったり、Header Based routing だったり、Mirroed traffic だったりできる。が、これは他の Front Proxy(Istio, Nginx Ingress Controller, AWS ALB Ingress Controller, Service Mesh Interface)等との組み合わせで実現できるものなので、応用かなーと思っている。

HPA Support

argoproj.github.io

HPA と組み合わせたらどうなるの?ということだが、ちゃんとサポートしている。

HPA の target を rollout resource にしても動く。HPA は rollout の desired replicas を変化させる。

ただ Progressive State のときのロジックが新旧それぞれ Ceil になってるらしく、合計を上回ることはある。

github.com

このへんは同僚の mtsmfmd-kuro がちゃんとコード追っててさすがとなりました。見習おう。

実際にどうやるのか

Plugin いれましょう。

argoproj.github.io

Deployment からの書き換えはここを参照。

argoproj.github.io

あぁ、その前に Controller はいれておきましょう。Cluster Level で先にいれておいたら、あとは yaml 書くだけなので楽勝です。

まぁ例えばこんな感じの差分になる。

f:id:take_she12:20200616043137p:plain

で、もともと Deployment があった場合、Rollout と二重になる。selector も同じなので、ClusterIP の Service からどちらも Traffic は流されるはずだ。

実際の手順は以下のようになるだろう。

  1. Deployment を Rollout Resource に書き換え、Apply
  2. Cluster 上の Deployment を削除する
  3. Canary Release する

この場合、1 と 2 の間では実際に指定した割合以上に、すでに存在している旧バージョンである Deployment にも Traffic は流される。が、まぁ悪いことではない。

もっとも原始的にやるなら、SetWeight と Pause を交互に書けば良い。Promote は CLI で Web Engineer がやる想定。なお RBAC で権限絞ってる場合は変更が必要。

また、待ち時間によって自動的に次の step に進めたいなら Duration を指定すれば良い。かんたん。

Analysis

どうせやるなら自動で戻ったり進んだりしたいよね。Analysis 見ていきましょう。

argoproj.github.io

4つの CRD

  • Rollout: これまで説明したやつ
  • AnalysysTemplate: その Analysis が成功したか判断するロジックとかどの metrics 使うかとかが書いてあるやつ。引数も受け取れる。全体の中での条件( Background Analysis )として使われることもできて、この Step 以降でみる、みたいなのもできる。( startingStep ) また、Step の一部として Analysis を実行する場合でも使える。( Analysis at a Predefined Step
  • AnalysisRun: 複数の Analysys Template を、Step の一部として実行する場合に使われる( Analysis with Multiple Templates
  • Experiment: 解析のために限定的に Analysis を実行する。

その他

  • BlueGreen Pre Promotion Analysis: Blue/Green の事前 Analysis
  • BlueGreen Post Promotion Analysis: Blue/Green の事後 Analysis
  • Failure Conditions: Analysis の失敗条件
  • Inconclusive Runs: 解析結果が決定的でない場合がある:成功条件にも失敗条件にもひっかからない場合など。この場合、その Step で止まってしまう。
  • Delay Analysis Runs: initialDelaystartingStep で解析開始までに遅延をいれること。
  • Referencing Secrets: 外部 Provider へ metrics を収集するときに必要になりそうな Token のような秘匿情報を同じ namespace から arg として渡すことができる
  • Experimentation (e.g. Mann-Whitney Analysis): Stable と Canary 両方に Traffic 流して、どっちも Analysis やる的な。たぶん。
  • Run Experiment Indefinitely: Pause のように Duration を指定しなければずっと Experiment させることができる
  • Job Metrics: Analysis は Kubernetes Job として実行もできる
  • Wavefront Metrics: 知らぬ
  • Web Metrics: 外部の web service の metrics を使う。datadog の場合はこれ使うしかないんかな。

metrics provider 何があるんだろうか。

github.com

ここぽい。うーん web 使うしかないかあ。

とすると datadog api 叩くための secret 作って、それを arg で渡して get する analysis 書いて、arg でサブドメとか渡して前段の nginx の http status の 5xx / 2xx rate でいい気がする。

気をつけるべきこととか

  • 前方互換性:Canary Release するなら、これは守らないとダメ
  • branch が1本しかないことを許容する:つまり Progressing のときに HOTFIX を当てるとかはできない。したがって analysys と組み合わせて比較的短時間、例えば1時間とか。であげきる必要がある。
  • Rollback & HOTFIX: 基本的に途中でダメなら Abort で Rollback して、それに HOTFIX をあてて前に進むという戦略を取る。あげきったあとは戻れない。(し、戻る必要はない)
  • Deployment から Rollout というリソースに変わるので、アラートや Dashboard が死ぬ。やむなし。
  • 毎回 Strategy を選択するのは理想的ではない:
    • いや、リリースのたびStrategy 部分のコードを変更すればいいんだが
    • やる?それ、という
    • 基本的にはすべてのリリースで毎回通る Strategy を指定するしかないんでは
    • あるいは Analysis 付きの場合は対象の Analysis を変更することでスッと行くようにすることはできると思うが
    • そこに気を使わないといけない状況嫌じゃない?

おわりに

この記事が出る本日 Production でやっていくようです。やっていきましょう。

次は Traffic Management を読んで、ALB Ingress を利用したパターンを理解しておく。