リリースを開けてみる — 保存場所・保持ウィンドウ・復活
目標
Helmのreleaseが、クラスターのどこに何として保存されるかを自分で解いてみて、保持範囲がどれほど狭いか、削除したreleaseをどう復活させるかまで、一巡します。
なぜ重要なのか
helm rollbackが何を元に戻し、何を元に戻せないかは、すべて保存の構造から出てきます。releaseはネームスペースの中のSecret1枚で、その中に、レンダリングされたマニフェストがまるごと圧縮されて入っています。そのため、マニフェストに書かれていたものは元に戻り、外で起きたことは元に戻りません。
同じ構造から導かれることが、あと2つあります。release名がネームスペースの中でだけ一意であること、そして、保持されるリビジョンの数に上限があることです。「半年前にロールバック」がたいてい不可能な理由が、ここにあります。事故が起きたときにhelm get valuesで「どんな値で起動したのか」を先に確認する習慣も、この構造を知ってはじめて身につきます。
環境
このPodは、kwokで本物のkube-apiserverを立ち上げます。Podが実際に実行されるわけではありませんが、releaseのSecretとリビジョン、オブジェクトの変更は、すべて本物です。そのため、採点もファイルではなく、helmとapiserverに改めて問い合わせて行います。作業ディレクトリは/root/hs-relで、出力物は/root/hs-rel/outの下に置きます。
ステップ
/root/hs-relでチャートを作成し、rel-aにshopとしてインストールします。- リビジョン1のreleaseのSecretを解いて、
/root/hs-rel/out/release-v1.jsonに保存します。 - 同じ名前の
shopを、rel-bにもインストールします。 --history-max 3で4回アップグレードして、古いリビジョンが消えるのを見ます。helm get valuesとhelm get manifestの結果を、/root/hs-rel/outに保存します。rel-bのreleaseを--keep-historyで削除して、記録を保存します。- 削除したreleaseを、ロールバックで復活させます。
/root/hs-rel/out/report.txtに、7行でまとめます。
参考
- Secretを解くとき、
base64 -dは2回です。Kubernetesが1層、helmがもう1層エンコードします。 helm listは、デフォルトではdeployedだけを見せます。削除されたものや閉じ込められたものを見るには、-aを付けます。- よくある間違いの1つは、ステップ6で
--keep-historyを忘れることです。そうすると、ステップ7で復活させるものがありません。 - もう1つは、ステップ5で
--allを付けて受け取ることです。そうすると、チャートのデフォルト値が混ざり込んで、「人が何を入れたのか」がわからなくなります。
チャートを作って名前を付けてデプロイする
/root/hs-relでhelm create webappでチャートを作成し、rel-aネームスペースに、shopという名前でインストールしてください。ネームスペースは--create-namespaceで一緒に作ります。
helm install <릴리스이름> <차트경로> -n <네임스페이스> --create-namespace(プレースホルダーは順にrelease名、チャートのパス、ネームスペースです)です。インストールが終わったら、kubectl -n rel-a get deployで、作られたDeploymentの名前を確認してください。チャートが決めた名前ではなく、release名が前に付きます。このクラスターはkwokなので、Podが実際には実行されませんが、releaseとオブジェクトはすべて本物です。
releaseが保存されたSecretを解いてみる
rel-aのhelmのreleaseのSecretのうち、リビジョン1のものを選んで内容を解き、release JSON全体を/root/hs-rel/out/release-v1.jsonに保存してください。
kubectl -n rel-a get secret -l owner=helm,name=shopで名前を確認します。-o jsonpath='{.data.release}'で値を取り出したあと、base64 -dを2回行い、gzip -dを行うと、release JSONが出ます。Kubernetesが1層、helmがもう1層エンコードしておいたからです。レンダリングされたYAMLは、そのJSONの.manifestフィールドに文字列として入っているので、今回はJSONをまるごと保存してください。
同じ名前のreleaseを、別のネームスペースにもう1つ
同じチャートをrel-bネームスペースにも、やはりshopという名前でインストールしてください。2つのreleaseが、衝突なくそれぞれ生きている必要があります。
release名は、クラスター全体ではなく、ネームスペースの中でだけ一意です。記録が、そのネームスペースのSecretに入るからです。helm list -Aで全体を見て、kubectl -n rel-b get secret -l owner=helmで、記録がどこにできたかを確認してください。
保持範囲を狭めて、古いリビジョンが消えるのを見る
rel-aのshopを、--history-max 3を付けて4回アップグレードしてください。最後のアップグレードで、replicaCountは5になっている必要があります。
helm upgrade shop ./webapp -n rel-a --set replicaCount=<값> --history-max 3(プレースホルダーは値です)を、replicaCount 2、3、4、5で4回実行します。そのあと、helm history shop -n rel-aとkubectl -n rel-a get secret -l owner=helm,name=shopを並べて見てください。リビジョン番号は5まで上がるのに、残っているのは3つだけです。元に戻せる範囲が思ったより狭いというのが、このステップの要点です。
このreleaseに実際に入った値とマニフェストを取り出す
helm get valuesをJSONで受け取って/root/hs-rel/out/values.jsonに、helm get manifestの結果を/root/hs-rel/out/manifest.yamlに保存してください。値は、ユーザーが渡したものだけが入っている必要があります。
helm get values shop -n rel-a -o jsonは、ユーザーが渡した値だけを見せ、--allを付けると、チャートのデフォルト値まで合わせて見せます。事故の調査で先に見るのは、前者です。helm get manifestは、そのreleaseが実際に適用したYAMLなので、そこに書かれたreplicasと、kubectl get deployが答えるreplicasが同じなら、正常です。
記録を残して削除する
rel-bのshopを--keep-historyを付けて削除し、helm list -n rel-b -aとhelm history shop -n rel-bの出力を、一緒に/root/hs-rel/out/uninstalled.txtに保存してください。
helm uninstall shop -n rel-b --keep-historyです。ただhelm uninstallすると、releaseのSecretまで消えて、復活させられません。削除したあと、helm list -n rel-bは何も見せませんが、-aを付けると、uninstalled状態で残っているものが見えます。helm listのデフォルトが、削除されたreleaseを隠すという点を、目で確認してください。
削除したreleaseを復活させる
rel-bのshopを、リビジョン1にロールバックして復活させてください。復活させたあとも、uninstalledのリビジョンは、記録に残っている必要があります。
helm rollback shop 1 -n rel-bです。記録を残しておいたので、もう一度インストールしなくても、戻ってこられます。もう一度helm installをすると、履歴が1番から新しく始まり、何があったかが消えます。ロールバックのあとhelm historyを見ると、uninstalledのリビジョンの上に、「Rollback to 1」と書かれた新しいリビジョンが付いています。
7つのステップを数字でまとめる
/root/hs-rel/out/report.txtに7行を書いてください。RELEASES_TOTAL、STORAGE、HISTORY_MAX、REL_A_KEPT、REL_A_LATEST、RESOURCE_PREFIX、SCOPEです。
値は推測せず、クラスターで数えて書きます。helm list -A -aでshopがいくつあるか、helm history shop -n rel-aで残ったリビジョンの数と最も大きい番号がいくつかを確認してください。STORAGEは、helm 3がreleaseをどこに置くか、SCOPEは、release名がどこまで一意かを、1つの単語で書きます。RESOURCE_PREFIXは、ステップ1で見たDeploymentの名前です。