TT Lab
はじめる
学ぶ 学習パス コース

Helmのデプロイとロールバック

デプロイし、壊し、戻す

TT Labで続きを見る

目標

デプロイを元に戻せるものにします。デプロイして、わざと壊して、2つの方法で元に戻し、閉じ込められたreleaseを取り出すところまで、一巡します。

なぜ重要なのか

デプロイ自動化の成否は、成功したときではなく、失敗したときにどんな状態で残るかで分かれます。helm upgradeは、デフォルトでは、Podが起動するかを見ずに、成功を返します。そのため、CIはグリーンなのに、ユーザーだけが障害を経験する状況が作られます。

このラボでは、その状況を自分で作ってみます。ステップ4で、存在しないイメージでデプロイすると、helmがSTATUS: deployedと言うのを、目で見ることになります。そのあと、--atomicを付けると、何が変わるかを比べます。

環境

このPodは、kwokで本物のkube-apiserverを立ち上げます。Podが実際に実行されるわけではありませんが、releaseのSecret・リビジョン・リソースの変更は、すべて本物です。そのため、採点も、ファイルではなく、クラスターの状態を改めて読んで行います。

kubectl get nodes            노드 2대가 Ready
helm version                 v3.16

ステップ

  1. helm create demo → helm install
  2. releaseのSecretからマニフェストを取り出して/root/helm/02-manifest.yaml
  3. --set replicaCount=4でリビジョン2
  4. 存在しないイメージでアップグレード。成功したと出ることを確認
  5. 同じミスを--atomicでもう一度 → /root/helm/05-atomic.txt
  6. helm rollback demo 2
  7. helm templateを2回diff → /root/helm/07-diff.txt
  8. pending-upgradeに閉じ込められたreleaseを取り出す

参考

チャートを作ってデプロイする

helm create demo → helm install

helm create demoでスケルトンを作り、helm install demo ./demoでデプロイします。helm listにdeployedと出ればよいです。このクラスターはkwokなので、Podが実際には実行されませんが、release・リビジョン・リソースはすべて本物です。

releaseが保存されたSecretを直接見る

releaseのSecretからマニフェストを取り出して/root/helm/02-manifest.yaml

kubectl get secret -l owner=helmで名前を確認します。-o jsonpath='{.data.release}' → base64 -d → base64 -d → gzip -dの順に解くと、release JSON全体が出ます(マニフェストではありません)。レンダリングされたYAMLは、そのJSONの.manifestフィールドに文字列として入っているので、jq -r .manifestで取り出して、/root/helm/02-manifest.yamlに保存してください。

replicasを上げてリビジョン2を作る

--set replicaCount=4でリビジョン2

helm upgrade demo ./demo --set replicaCount=4。そのあと、helm history demoで、リビジョンが2つになったか、1番がsupersededになったかを確認してください。

わざと壊す

存在しないイメージでアップグレード。成功したと出ることを確認

存在しないイメージでアップグレードしてみてください: --set image.repository=nope/nothing --set image.tag=v0。--waitなしで行うと、helmが成功したと言います。それが、このステップで見るものです。後のステップで元に戻すので、採点は今の状態ではなく、リビジョンの記録を見ます。

--atomicで失敗を捕まえる

同じミスを--atomicでもう一度 → /root/helm/05-atomic.txt

今回は、スケジュールできないPodを作ってみます: helm upgrade demo ./demo --set nodeSelector.disktype=nope --atomic --timeout 30s。存在しないノードのラベルなので、PodがPendingのままとなり、--atomicがタイムアウトを捕まえて、自動で元に戻します。コマンドが失敗することが正解です。出力を/root/helm/05-atomic.txtに保存してください(2>&1 | tee)。

なぜ壊れたイメージではなくnodeSelectorなのか: このラボのクラスターはkwokなので、Podを実際には実行せず、Readyとして表示します。そのため、イメージが間違っていても、--waitが通過します。スケジュール自体ができない条件でないと、本当には止まりません。

手で元に戻す

helm rollback demo 2

helm rollback demo 2で、リビジョン2の内容に戻します。helm historyに「Rollback to 2」と書かれた新しいリビジョンができ、kubectl get deploy demo -o jsonpath='{.spec.replicas}'が4である必要があります。

何が変わるかを事前に見る

helm templateを2回diff → /root/helm/07-diff.txt

適用の前に差分を見る習慣が、事故を防ぎます。helm-diffプラグインがないので、helm template2回の結果を、diffで比べてください。結果を/root/helm/07-diff.txtに保存します。差分がある必要があります。

pendingに閉じ込められたreleaseを取り出す

pending-upgradeに閉じ込められたreleaseを取り出す

まず閉じ込められた状況を本当に作ります。スケジュールできないPodを--waitで待たせておいて、そのhelmプロセスを途中で殺してください。

helm upgrade demo ./demo --set nodeSelector.disktype=nope --wait --timeout 300s &
sleep 12
kill -9 $!

実務で、helmプロセスが途中で死んだりCIがキャンセルされたりすると、まさにこの状態になります。確認はhelm list -aで行います。helm listは、デフォルトでpendingを隠します。この状態でhelm upgradeをもう一度掛けると、another operation (install/upgrade/rollback) is in progressで止められます。

(Secretにkubectl label ... status=pending-upgradeだけを掛けても、閉じ込められません。helmは、状態をラベルではなく、Secretの中のrelease JSONから読むので、ラベルだけを変えても、helm listは相変わらずdeployedと答え、次のデプロイもそのまま通ります。)

取り出す手順: helmは、閉じ込められたリビジョンのSecretを、自分では片づけません。kubectl get secret -l owner=helm,name=demo,status=pending-upgradeで探して、kubectl deleteで削除し、最後の正常なリビジョンにhelm rollbackします。終わったら、helm listがdeployedで、pendingラベルが付いたSecretが1つもない必要があります。