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

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

--atomicと--waitが実際にやっていること

TT Labで続きを見る

一言でいうと

--waitは「すべて起動するまで待つ」、--atomicは「すべて起動できなければ元に戻す」です。この2つを使わないと、失敗したデプロイが成功として報告されます。

なぜ必要なのか

helm upgradeは、デフォルトでは、マニフェストをAPIサーバーに送って、すぐに成功を返します。Podが実際に起動するかどうかは見ません。イメージタグを間違えてImagePullBackOffになっても、helmはSTATUS: deployedを出力します。CIのログは緑色で、ユーザーだけが障害を経験します。

--waitを付けると、helmがDeployment・StatefulSet・DaemonSetの準備状態をポーリングします。--timeout(デフォルトは5分)の間に準備ができなければ、失敗として扱います。これで、CIが赤になります。

ところが、失敗したまま放置すると、問題が残ります。新しいリビジョンはすでに作られていて、リソースは半分だけ変わった状態です。--atomicは、ここで自動的にhelm rollbackを掛けて、以前の状態に戻します。--atomicは--waitを含みます。待たなければ失敗がわからないので、当然です。

どう動くのか

helm upgrade demo ./chart \
  --atomic \
  --timeout 5m \
  --history-max 10

この1行が、デプロイスクリプトの基本形であるべきです。そして、timeoutの値は、最も遅いPodの起動時間+余裕で決めます。短すぎると、問題のないデプロイがロールバックされ、長すぎると、障害に気づくのが遅れます。

よくある勘違い

--atomicがあれば安全だという勘違いです。atomicは、Kubernetesのリソースだけを元に戻します。フックで実行したマイグレーションのJobがDBをすでに変えていたなら、それはそのまま残ります。そのため、スキーマの変更は、前後のバージョンがどちらも耐えられる形に分けてデプロイします(拡張 → デプロイ → 整理)。

timeoutを延ばせば解決するという勘違いです。ImagePullBackOffは、待っても直りません。30分のtimeoutは、障害を30分遅れて知らせるだけです。

releaseがpendingに閉じ込められたら

デプロイが途中で死ぬと、releaseがpending-upgradeやpending-installのまま残ります。この状態では、次のデプロイが、次のように拒否されます。

Error: another operation (install/upgrade/rollback) is in progress

Helm 3は、releaseの状態をネームスペースのSecretに保存していて、ロックが別にないので、「進行中」の表示がそのまま残るのです。プロセスはすでに死んでいるのに、表示だけが残っています。

解く順序は、次のとおりです。

helm history demo                    # 1) 마지막 리비전의 상태를 본다
helm rollback demo <직전 성공 리비전>  # 2) 대개 이걸로 풀린다

# 롤백도 거절되면 마지막 수단 — 갇힌 리비전의 Secret 을 지운다
kubectl -n <ns> get secret -l owner=helm,name=demo
kubectl -n <ns> delete secret sh.helm.release.v1.demo.v<갇힌 번호>

最後の方法は、そのリビジョンの記録を消すことなので、元に戻せません。消す前に、helm get manifest demo --revision <n>で、内容を残しておきます。

ロールバックが元に戻せないもの

helm rollbackは、releaseのマニフェストを元に戻します。それ以外のものは、そのままです。

元に戻る 元に戻らない
Deployment・Service・ConfigMapのspec フックが実行したDBマイグレーション
イメージタグ、環境変数、replicas PVCの中のデータ
リソースのリクエスト・上限 他のシステムに送ったイベント・通知
削除されたリソースが持っていた状態

特に最後の行に注意します。チャートからリソースを1つ外してデプロイすると、Helmがそれを削除します。ロールバックすると、また作られますが、中にあったものは新しいものです。StatefulSetを一時的に外して元に戻す作業が、データ損失につながる経路です。

デプロイパイプラインの基本形

helm upgrade --install demo ./chart   -f values/prod.yaml   --set image.tag="$GIT_SHA"   --atomic --timeout 5m --history-max 10   --wait-for-jobs

# helm 이 초록불을 준 뒤에 바깥에서 확인한다
curl -fsS --retry 5 --retry-delay 3 https://demo.example.com/healthz

--wait-for-jobsを忘れることが、よくあります。--waitは、DeploymentとStatefulSetは待ちますが、Jobは待ちません。マイグレーションのJobが終わる前に、新しいPodがトラフィックを受ける事故が、ここで起きます。

実務で本当に大切なこと

--waitが見るのは、ワークロードの準備状態であって、「サービスが正常」ではありません。PodがReadyでも、応答が500のことがあります。そのため、デプロイパイプラインの最後には、常に外から叩いてみるスモークテストが必要です。helmがグリーンを返したことと、ユーザーが使えることは、別の命題です。