手で直したフィールドがアップグレードで消えた
目標
クラスターで手で直した値とラベルが、helm upgradeのあとでどうなるかを自分で作って確認し、以前のユーザー値を引き継ぐ3つのオプションの違いを、releaseの記録で比較します。
なぜ重要なのか
Helm 3は、アップグレードするとき、古いマニフェスト・新しいマニフェスト・クラスターの実物の3つを置いて、パッチを作ります。この規則1つで、現場で繰り返される2つの現象が説明できます。障害中にkubectl scaleで上げておいたレプリカ数は、次のデプロイで元に戻り、急いで付けておいたラベルは、そのまま残ります。チャートが宣言したフィールドは、宣言が勝ち、チャートが知らないフィールドには、手を付けないからです。ここに、値の側の規則がもう1つあります。helm upgradeは、デフォルトでは、以前のreleaseのユーザー値を引き継ぎません。そのため、デプロイスクリプトが--setを1つ忘れると、その値は黙ってチャートのデフォルト値に戻ります。--reuse-valuesは、この問題を解決しますが、値がreleaseの中にだけ残って、リポジトリから見えなくなります。どちらを使うかは、好みではなく、「デプロイを再現できるか」で決める必要があり、そのためには、3つのオプションが実際に何をするのかを、一度見る必要があります。
ステップ
/root/hc-upgrade/ledgerチャート(名前ledger、バージョン0.1.0)を作成してください。values.yamlは、replicas: 1、image: "registry.local/ledger:1.0.0"、extraLabel: ""の3つの値です。templates/deployment.yamlは、名前が<릴리스이름>-ledger(プレースホルダーはrelease名です)のDeploymentで、metadata.labelsにapp: ledgerを置き、extraLabelが空でないときだけtier: <그 값>(プレースホルダーはその値です)を加えます。release名booksでインストールしたあと、helm get manifest booksを/root/hc-upgrade/out/rev1-manifest.yamlに保存してください。kubectlで、books-ledgerDeploymentのレプリカ数を5に上げ、ラベルowner=opsを付けてください。その状態を、/root/hc-upgrade/out/before-upgrade.jsonに、{"replicas": …, "owner": …, "tier": …}の3つのキーのJSONで保存します(ないラベルはnull)。- チャートも値もまったく変えないまま、
helm upgrade books /root/hc-upgrade/ledgerを実行してください。そのあと、同じ3つのキーのJSONを/root/hc-upgrade/out/after-upgrade.jsonに保存し、手で直した2つのうち、何が生き残り、何が元に戻ったかを確認してください。 --set extraLabel=goldでアップグレードして、tierラベルが付いた状態を/root/hc-upgrade/out/label-added.jsonに保存してください。続けて、extraLabelを空の文字列で渡してもう一度アップグレードし、tierラベルが消えた状態を/root/hc-upgrade/out/label-removed.jsonに保存します。2つのファイルとも、同じ3つのキーのJSONです。このとき、ownerラベルがどうなるかも、一緒に見てください。--set replicas=4 --set extraLabel=silverでアップグレードして、helm get values books -o jsonを/root/hc-upgrade/out/values-1.jsonに保存してください。続けて、--set replicas=6を1つだけ渡して、もう一度アップグレードしたあと、同じコマンドの結果を/root/hc-upgrade/out/values-2.jsonに保存してください。extraLabelがどうなるかが、答えです。- 以前のreleaseのユーザー値を引き継ぎながら、
--set extraLabel=bronzeだけを加えてアップグレードしてください。helm get values books -o jsonの結果を/root/hc-upgrade/out/values-reuse.jsonに保存します。replicasは前のステップの6が残り、extraLabelはbronzeである必要があります。 - まず
--set replicas=4 --set extraLabel=silverでアップグレードして、基準を作ってください。そこから、--set replicas=7に、チャートのデフォルト値に戻してから、前回のユーザー値をもう一度載せるオプションを付けてアップグレードし、結果を/root/hc-upgrade/out/values-rtr.jsonに保存してください。続けて、--set replicas=9に、前回の値を捨てるオプションを付けてアップグレードし、結果を/root/hc-upgrade/out/values-reset.jsonに保存してください。 --set replicas=3でサーバー側のプレビューを実行して、出力を/root/hc-upgrade/out/dryrun.yamlに保存してください(releaseは変わらない必要があります)。そのあと、同じ値で--forceを付けて、実際にアップグレードし、そのあとの状態を、ステップ2と同じ3つのキーのJSONで/root/hc-upgrade/out/after-force.jsonに保存してください。手で付けたownerラベルがどうなるかを、確認してください。helm history books -o jsonを/root/hc-upgrade/out/history.jsonに保存し、/root/hc-upgrade/out/merge-report.jsonに、manual_scale_kept・manual_label_kept・chart_removed_label_deleted・default_upgrade_reuses_values・manual_label_survives_forceの5つのブール値と、final_replicasの数値を書いてください。値は、前のステップで保存したファイルから読み取ります。
参考
helm get values <릴리스> -o json(プレースホルダーはreleaseです)は、ユーザーが渡した値だけを、--allは、チャートのデフォルト値まで見せますkubectl get deploy <이름> -o json | jq '{...}'(プレースホルダーは名前です)で、必要なフィールドだけを抜き出して比較しますhelm upgrade --dry-run=serverは、APIサーバーまで送って検証だけを行い、releaseは作りません- よくある間違い: 障害中に
kubectl scaleで上げた値を、次のデプロイが元に戻すことです - よくある間違い: デプロイスクリプトで
--setを1つ忘れて、その値だけがデフォルト値に戻ることです - 公式ドキュメント: https://helm.sh/docs/helm/helm_upgrade/ ・ https://helm.sh/docs/faq/changes_since_helm2/
元に戻してみるものを先にデプロイする
/root/hc-upgrade/ledgerチャート(名前ledger、バージョン0.1.0)を作成してください。values.yamlは、replicas: 1、image: "registry.local/ledger:1.0.0"、extraLabel: ""の3つの値です。templates/deployment.yamlは、名前が<릴리스이름>-ledger(プレースホルダーはrelease名です)のDeploymentで、metadata.labelsにapp: ledgerを置き、extraLabelが空でないときだけtier: <그 값>(プレースホルダーはその値です)を加えます。release名booksでインストールしたあと、helm get manifest booksを/root/hc-upgrade/out/rev1-manifest.yamlに保存してください。
kwokクラスターでは、Podが実際には動きませんが、Deploymentオブジェクトは正常に作られます。このラボはオブジェクトのフィールド値だけを見ます。ラベルを条件付きで付ける部分は、{{- if .Values.extraLabel }}ブロックで囲み、前の-で、条件が偽のときに空行が残らないようにしてください。
クラスターで手で直す
kubectlで、books-ledgerDeploymentのレプリカ数を5に上げ、ラベルowner=opsを付けてください。その状態を、/root/hc-upgrade/out/before-upgrade.jsonに、{"replicas": …, "owner": …, "tier": …}の3つのキーのJSONで保存します(ないラベルはnull)。
kubectl scale deploy/books-ledger --replicas=5とkubectl label deploy/books-ledger owner=ops --overwriteの2つのコマンドです。障害対応中によくやることで、問題は、そのあとのデプロイで生じます。JSONで抜き出すときは、kubectl get deploy books-ledger -o json | jq '{...}'を使ってください。
チャートを1つも変えずにアップグレードする
チャートも値もまったく変えないまま、helm upgrade books /root/hc-upgrade/ledgerを実行してください。そのあと、同じ3つのキーのJSONを/root/hc-upgrade/out/after-upgrade.jsonに保存し、手で直した2つのうち、何が生き残り、何が元に戻ったかを確認してください。
Helm 3は、古いマニフェスト・新しいマニフェスト・クラスターの実物の3つを置いて、パッチを作ります。チャートが値を宣言したフィールドは、クラスターの実物が違っていても、宣言側に合わされます。チャートがまったく知らないフィールドには、手を付けません。2つの規則で、結果を説明できる必要があります。
チャートから外したフィールドは、クラスターからも消える
--set extraLabel=goldでアップグレードして、tierラベルが付いた状態を/root/hc-upgrade/out/label-added.jsonに保存してください。続けて、extraLabelを空の文字列で渡してもう一度アップグレードし、tierラベルが消えた状態を/root/hc-upgrade/out/label-removed.jsonに保存します。2つのファイルとも、同じ3つのキーのJSONです。このとき、ownerラベルがどうなるかも、一緒に見てください。
条件が偽になると、新しいマニフェストにはそのラベルがありません。Helmは、古いマニフェストと比べて、抜けたフィールドを消すパッチを作ります。一方、ownerは、どちらのマニフェストにもなかったフィールドなので、パッチの対象ではありません。チャートが管理するものと、人が付けたものの境界が、ここで分かれます。注意: 値を1つも渡さずにアップグレードすると、Helmは直前のreleaseのユーザー値をそのまま使います。そのため、--setを抜くだけでは、goldは消えません。自分でやってみて、違いを確認してください。
アップグレードは前回のユーザー値を捨てる
--set replicas=4 --set extraLabel=silverでアップグレードして、helm get values books -o jsonを/root/hc-upgrade/out/values-1.jsonに保存してください。続けて、--set replicas=6を1つだけ渡して、もう一度アップグレードしたあと、同じコマンドの結果を/root/hc-upgrade/out/values-2.jsonに保存してください。extraLabelがどうなるかが、答えです。
helm get valuesは、ユーザーが渡した値だけを見せます(チャートのデフォルト値まで見るには--all)。デフォルトの動作では、アップグレードは以前のreleaseのユーザー値を引き継がず、今回渡したものだけを使います。デプロイスクリプトが、毎回すべての--setを書き直す必要がある理由が、ここにあります。
前回の値を引き継いで、1つの値だけを変える
以前のreleaseのユーザー値を引き継ぎながら、--set extraLabel=bronzeだけを加えてアップグレードしてください。helm get values books -o jsonの結果を/root/hc-upgrade/out/values-reuse.jsonに保存します。replicasは前のステップの6が残り、extraLabelはbronzeである必要があります。
引き継ぎのオプションが別にあります(helm upgrade --helpで、reuseが入ったもの)。楽そうに見えますが、落とし穴があります。引き継がれた値は、コマンドラインにもリポジトリにも見えず、releaseの中にだけあります。そのため、古いreleaseほど、「今どんな値で動いているのか」を、誰もわからなくなります。
3つの引き継ぎオプションを並べる
まず--set replicas=4 --set extraLabel=silverでアップグレードして、基準を作ってください。そこから、--set replicas=7に、チャートのデフォルト値に戻してから、前回のユーザー値をもう一度載せるオプションを付けてアップグレードし、結果を/root/hc-upgrade/out/values-rtr.jsonに保存してください。続けて、--set replicas=9に、前回の値を捨てるオプションを付けてアップグレードし、結果を/root/hc-upgrade/out/values-reset.jsonに保存してください。
3つのオプションの名前が互いに似ていて混乱します。helm upgrade --helpで、3つを並べて読んでみてください。1つは前回の値をそのまま引き継ぎ、1つはデフォルト値に戻してから前回のユーザー値をもう一度載せ、1つは前回の値をそもそも捨てます。保存された2つのファイルのキーの数の違いで、区別できます。
プレビューして、置き換えで適用して、規則を整理する
--set replicas=3でサーバー側のプレビューを実行して、出力を/root/hc-upgrade/out/dryrun.yamlに保存してください(releaseは変わらない必要があります)。そのあと、同じ値で--forceを付けて、実際にアップグレードし、そのあとの状態を、ステップ2と同じ3つのキーのJSONで/root/hc-upgrade/out/after-force.jsonに保存してください。手で付けたownerラベルがどうなるかを、確認してください。helm history books -o jsonを/root/hc-upgrade/out/history.jsonに保存し、/root/hc-upgrade/out/merge-report.jsonに、manual_scale_kept・manual_label_kept・chart_removed_label_deleted・default_upgrade_reuses_values・manual_label_survives_forceの5つのブール値と、final_replicasの数値を書いてください。値は、前のステップで保存したファイルから読み取ります。
--dry-run=serverは、APIサーバーまで送って検証だけを行い、releaseは作りません。--forceは、パッチの代わりに置き換えの方式で適用します。パッチでは変更できない不変フィールドがあるときに使いますが、置き換えなので、オブジェクトがまるごと新しいマニフェストに差し替えられます。そうすると、ステップ3で生き残っていたものが、今回はどうなるかを、考えて確認してください。5つのブール値は、ステップ2–5と、今保存したJSONを見比べれば、そのまま出ます。