フックがリリースの外に住んでいることを確認する
目標
フックのリソースがreleaseの外にあるという事実を、手で確認します。アノテーションを3つ付け、削除ポリシーを2つ並べ、実行順序を計算し、ロールバックしてもフックが残したものがそのままであることまで見ます。
なぜ重要なのか
DBマイグレーションをデプロイに組み込む最もよくある方法が、pre-upgradeフックです。ところが、フックで作ったオブジェクトは、releaseのSecretに入りません。結果が2つです。ロールバックしても、フックがやったことは残り、削除ポリシーを掛けないと、オブジェクトが積み上がり続けます。
ここから、実務の規則が導かれます。成功したフックは片づけ、失敗したフックは次のデプロイまで残して、ログを見られるようにすること、元に戻せないスキーマ変更は、デプロイと分離して、何回かに分けること、そして、Jobのフックには、helmのタイムアウトより短い、自分の上限を掛けておくことです。最後のものは、helmが待つのをやめても、Jobは動き続けるからです。
環境
このPodは、kwokで本物のkube-apiserverを立ち上げますが、コンテナは実際には実行されません。そのため、Jobのフックは終わらず、releaseを閉じ込めます。最初の6つのステップは、すぐに準備完了と判定されるConfigMapでフックを扱い、Jobは、ステップ7で、値1つでオフにしたまま、レンダリング結果だけを見ます。作業ディレクトリは/root/hs-hookで、出力物は/root/hs-hook/outの下に置きます。
ステップ
- チャートを作成して、
hook-migrate.yamlにフックのアノテーションを3つ付けます。 hook-labにpayとしてインストールして、クラスターとマニフェストの両方を見ます。hook-scratch.yamlを加えて、削除ポリシーの2種類を比較します。hook-early.yamlを加えて、実行順序を/root/hs-hook/out/order.txtに書きます。tests/smoke.yamlにtestフックを作って、デプロイのときに動かないことを確認します。--no-hooksのレンダリングを/root/hs-hook/out/nohooks.yamlに保存します。hook-migrate-job.yamlに安全装置を備えたJobフックを作りますが、デフォルトはオフにしておきます。- アップグレードしてロールバックしたあと、
/root/hs-hook/out/residue.txtに4行でまとめます。
参考
- アノテーションの値は文字列です。
hook-weightを引用符なしで書くと、数値としてレンダリングされて、フックとして認識されません。 - ステップ7で、
migrationJob.enabledをオンにしたままアップグレードしないでください。Jobが終わらず、releaseがpending-upgradeに閉じ込められます。 - よくある間違いは、削除ポリシーに
hook-failedを入れることです。失敗した瞬間にオブジェクトが消えて、原因を見るログがなくなります。
フックのアノテーションを3つ付ける
/root/hs-hookでhelm create svcでチャートを作成し、svc/templates/testsディレクトリは削除してください。そのあと、svc/templates/hook-migrate.yamlに{{ .Release.Name }}-migrateConfigMapを作成し、helm.sh/hookはpre-install,pre-upgrade、helm.sh/hook-weightは-5、helm.sh/hook-delete-policyはbefore-hook-creationと書いてください。
フックは、別のリソースの種類ではなく、アノテーションが付いた普通のリソースです。実務ではJobを使いますが、このクラスターは、コンテナを実際には実行しないので、Jobのフックが終わりません。そのため、最初の6つのステップは、すぐに準備完了と判定されるConfigMapで、フックを扱います。アノテーションの値は必ず文字列である必要があるので、weightは引用符で囲んでください。
フックはクラスターにあるのに、マニフェストにはない
チャートをhook-labネームスペースに、payという名前でインストールし、kubectlとhelm get manifestの2か所で、フックのConfigMapを探してみてください。
helm install pay ./svc -n hook-lab --create-namespaceです。インストールが終わると、kubectl -n hook-lab get cmには、フックのConfigMapが見えますが、helm get manifest pay -n hook-labにはありません。フックのリソースは、releaseが管理しないからです。この1つのことが、ロールバックがフックを元に戻せない理由のすべてです。
削除ポリシー2つを並べて、違いを見る
svc/templates/hook-scratch.yamlに{{ .Release.Name }}-scratchConfigMapを作成してください。フックのタイミングは前と同じで、weightは0、削除ポリシーはhook-succeededです。そのあと、アップグレードを1回行ってください。
hook-succeededは、成功したらすぐにオブジェクトを削除し、before-hook-creationは、次のデプロイで同じフックを作る直前まで残します。アップグレードが終わったあと、kubectl -n hook-lab get cmを見ると、2つのうち1つだけが残っています。失敗したフックのログを見られるかどうかが、ここで分かれます。
weightで実行順序を決める
svc/templates/hook-early.yamlに{{ .Release.Name }}-earlyConfigMapのフックを、weight -10で加えてください。そのあと、pre-upgradeの段階で動くフックの実行順序を計算して、/root/hs-hook/out/order.txtに、名前だけを1行ずつ書いてください。
hook-weightは、文字列ですが、数値でソートされます。小さいほど先に動き、値が同じなら、リソースの種類と名前の順で分かれます。そのため、実務では、基本を-5にして、さらに先に動く必要があるものに-10を与えます。順序は推測せず、helm templateの結果からアノテーションを抜き出して、ソートして確認してください。
testフックはデプロイのときには動かない
svc/templates/tests/smoke.yamlに{{ .Release.Name }}-smokePodを作成し、helm.sh/hookをtestに、削除ポリシーをhook-succeededにしてください。そのあと、アップグレードをもう1回行ってください。
testフックは、デプロイの過程に割り込まず、helm testを呼んだときだけ動きます。そのため、アップグレードが終わったあとも、そのPodはクラスターになく、helm get manifestにもありません。レンダリング結果には出ます。この3つの違いを、自分で確認するのが、このステップです。デプロイの過程にテストを混ぜると、テストが不安定になるたびにデプロイが止まるので、場所を分けておいた設計です。
--no-hooksが何を外すかを見る
helm templateに--no-hooksを付けてレンダリングした結果を、/root/hs-hook/out/nohooks.yamlに保存してください。フックだけが抜けて、本体のマニフェストはそのままである必要があります。
--no-hooksは、helm install・upgrade・templateのすべてに付けられます。障害対応中に、フックを飛ばして、リソースだけを押し込む必要があるときに使いますが、マイグレーションを飛ばすことになるので、結果を理解して使う必要があります。保存したあと、フックが付いたリソースが1つもなく、残りの数はそのままかを確認してください。
マイグレーションのJobに安全装置を掛ける
svc/templates/hook-migrate-job.yamlに、pre-upgradeのJobフックを作成してください。values.yamlのmigrationJob.enabledでオンオフし、デフォルトはfalseである必要があります。Jobには、activeDeadlineSeconds(300未満)、backoffLimit: 0、restartPolicy: Neverを置き、削除ポリシーはbefore-hook-creation,hook-succeededにしてください。
helmの--timeoutのデフォルトは5分ですが、タイムアウトになっても、Jobはクラスターで動き続けます。helmは、待つのをやめるだけです。そのため、Jobが自分で先に終わるように、activeDeadlineSecondsを、それより短く掛けます。削除ポリシーにhook-failedを入れると、失敗した瞬間にログが消えるので、入れないでください。このクラスターでは、Jobのフックが終わらないので、デフォルトをオフにしておく必要があります。オンにした状態でアップグレードすると、releaseがpendingに閉じ込められます。
ロールバックしても、フックがやったことは残る
アップグレードをもう1回行ってから、helm rollbackで元に戻し、フックのConfigMapがそのまま残っているかを確認してください。確認結果を/root/hs-hook/out/residue.txtに4行で書きます。HOOK_ROLLED_BACK、HOOK_IN_MANIFEST、MIGRATION_UNDONE、SAFE_PATTERNです。
ロールバックは、releaseが管理するオブジェクトを、以前のマニフェストでもう一度適用することです。フックが作ったものは、そのマニフェストにないので、手を付けません。そのため、マイグレーションが変えたスキーマも、そのまま残ります。最初の3行は、はい/いいえをyesかnoで書き、最後の行には、元に戻せないスキーマ変更を安全に出すパターンの名前を書いてください。理論で、拡張と縮小と呼んだものです。