デプロイし、壊し、戻す
目標
デプロイを元に戻せるものにします。デプロイして、わざと壊して、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
ステップ
helm create demo→helm install- releaseのSecretからマニフェストを取り出して
/root/helm/02-manifest.yaml --set replicaCount=4でリビジョン2- 存在しないイメージでアップグレード。成功したと出ることを確認
- 同じミスを
--atomicでもう一度 →/root/helm/05-atomic.txt helm rollback demo 2helm templateを2回diff →/root/helm/07-diff.txt- pending-upgradeに閉じ込められたreleaseを取り出す
参考
- このラボには、コマンドが失敗することが正解のステップがあります(ステップ5)。失敗の出力を保存することが目的です。
helm history demoを、よく見てください。何があったかが、すべてそこにあります。- 閉じ込められたreleaseは、実務で、helmプロセスが途中で死んだり、CIがキャンセルされたりしたときに生じます。
チャートを作ってデプロイする
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つもない必要があります。