値がマージされる順序をレンダーで確認する
目標
値がマージされる順序を暗記する代わりに、レンダリングして確認する習慣を作ります。ローカルのサブチャートを依存関係として掛け、値ファイル2枚と--setを重ねて、誰が勝つかを見て、スキーマで誤った値をデプロイ前に防ぐところまで進みます。
なぜ重要なのか
本番のデプロイでは、valuesファイルが、たいてい2–3層になります。チャートのデフォルト値、環境別の値、そしてCIが注入するイメージタグです。どれが勝つのかが混乱すると、ステージングの値が本番に漏れ込みます。ここに、落とし穴がもう2つあります。マップはマージされるが、リストはまるごと置き換えられること、そして、サブチャートに渡す値は、サブチャート名をキーにして囲まないと伝わらないことです。
依存関係も、同じ種類の問題を起こします。Chart.yamlに書くバージョンは範囲で、実際に何が取得されたかは、Chart.lockに書かれます。このファイルをコミットしないと、人ごとに異なる依存関係を受け取り、そのときから「自分のPCでは動くのに」が始まります。
環境
インターネットがないので、チャートリポジトリから取得できません。その代わり、サブチャートを隣のディレクトリに作って、file://で指します。helm dependency updateは、この方式で正常に動作します。作業ディレクトリは/root/hs-valで、出力物は/root/hs-val/outの下に置きます。採点は、ファイルを文字として見るのではなく、helm templateを直接実行して、結果を読みます。
ステップ
- サブチャート
cacheと親のplatformを作り、file://の依存関係を掛けてロックします。 platform/values.yamlで、cacheキーを使ってサブチャートに値を渡します。global.envを置いて、両方のチャートが一緒に読むことを確認します。values/base.yamlとvalues/prod.yamlを重ねてレンダリングし、/root/hs-val/out/render.yamlに保存します。- リストが置き換えられることを確認して、
/root/hs-val/out/list-note.txtに書きます。 cache.enabled: falseで、サブチャートをまるごとオフにします。values.schema.jsonで範囲を超える値を防ぎ、拒否の出力を保存します。val-labにインストールして、helm get valuesの結果を保存します。
参考
- サブチャートのテンプレートを直したら、
helm dependency updateをもう一度実行してください。charts/の中のパッケージは、自動では更新されません。 --setのカンマは、キーの区切りです。値の中にカンマが必要なら、バックスラッシュでエスケープするか、一時的な値ファイルに入れてください。- よくある間違いは、サブチャートの値を最上位に書くことです。そうすると、親チャートの値になるだけで、helmは何も警告しません。
- スキーマに
requiredを入れるときは、値ファイルなしでレンダリングする場合まで、考えてください。
ローカルのサブチャートを依存関係として掛けて、ロックする
/root/hs-valにチャートを2つ作成してください。サブチャートはcache、親はplatformです。platform/Chart.yamlに、cacheの依存関係をfile://../cacheリポジトリで書き、condition: cache.enabledを付けたあと、helm dependency updateを実行してください。
インターネットがないので、リポジトリのアドレスとしてfile://を使います。helm dependency update <부모차트>(プレースホルダーは親チャートです)を実行すると、サブチャートがパッケージとしてまとめられてplatform/charts/cache-0.1.0.tgzとして入ってきて、取得されたバージョンがplatform/Chart.lockに書かれます。このロックファイルをリポジトリにコミットしてはじめて、他の人とCIが同じものを取得します。CIではhelm dependency buildを使い、範囲を解決し直すupdateは、意図したときだけ使います。
サブチャートに値を渡す
platform/values.yamlの末尾にcacheキーを作り、その下にenabled: trueとreplicaCount: 3を置いてください。親自身のreplicaCountは、デフォルトの1のままにします。
サブチャートに値を渡すには、親のvaluesで、サブチャート名をキーにして囲む必要があります。最上位にそのまま書くと、親チャートの値になるだけです。直したら、helm template plat ./platformを実行して、2つのDeploymentのreplicasが、それぞれ3と1に分かれるかを確認してください。
globalの下の値だけを、すべてのチャートが一緒に見る
platform/values.yamlにglobal.envを置き、親とサブチャートの両方に、その値を入れるConfigMapテンプレートを作成してください。名前はそれぞれ{{ .Release.Name }}-platform-envと{{ .Release.Name }}-cache-envで、data.envに.Values.global.envを入れます。
サブチャートは、親の最上位の値を見られませんが、globalの下の値は一緒に見られます。落とし穴が1つあります。サブチャートのテンプレートを直しても、platform/charts/の中のパッケージは古いままなので、helm dependency updateをもう一度実行しないと、レンダリングに反映されません。レンダリング結果で、2つのConfigMapのdata.envが同じ値なら、成功です。
2つの値ファイルと--setを重ねて、誰が勝つかを見る
/root/hs-val/values/base.yamlとprod.yamlを作成し、tierとimage.tagを、互いに違う値で書いてください。親チャートに{{ .Release.Name }}-settingsConfigMapテンプレートを作って、tier・tag・envNamesを入れ、-f base.yaml -f prod.yaml --set image.tag=ci-42でレンダリングした結果を、/root/hs-val/out/render.yamlに保存してください。
優先度は、低いものから、チャートのvalues.yaml、-fで渡したファイル(先に来たもの → あとのもの)、そして--setです。base.yamlにはtier・replicaCount・image.tag・extraEnvを置き、prod.yamlにはtier・image.tag・extraEnvを置きます。replicaCountは、prodには書かないでください。あとのファイルにないキーがどうなるかを、ステップ8でもう一度使います。採点ツールは、同じコマンドをもう一度実行して、あなたのファイルと突き合わせます。
リストはマージされず、まるごと変わる
ステップ4で作った2つの値ファイルのextraEnvはそのままにして、レンダリング結果のenvNamesが、どちらの一覧かを確認してください。確認した規則を/root/hs-val/out/list-note.txtの1行目にLIST_MERGE=replaceと書き、その下に、なぜそうなるのかを1–2文で付け加えてください。
マップはキー単位でマージされますが、リストは、あとのものが前のものをまるごと上書きします。-f base.yaml -f prod.yamlでレンダリングすると、baseの項目が1つも残りません。環境別に分けておいたextraEnvが1つだけ残る事故が、ここで起きます。マージしたいなら、リストではなく、マップで設計する必要があります。
条件が偽なら、サブチャートはレンダリングされない
prod.yamlにcache.enabled: falseを置き、その値を渡したレンダリングと、渡さないレンダリングを、比べてください。オフにしたほうには、サブチャートのリソースが1つもない必要があります。
Chart.yamlのconditionが指す値が偽なら、そのサブチャートは、そもそもレンダリングされません。そのため、そのサブチャートの値が間違っていても、デプロイは通り、オンにした瞬間に、はじめて発覚します。サブチャートが出力したリソースかどうかは、レンダリング結果の# Source: platform/charts/cache/というコメントで区別できます。
スキーマで誤った値をデプロイ前に防ぐ
/root/hs-val/platform/values.schema.jsonを作成して、replicaCountを1以上5以下の整数に制限してください。そして、上限を超える値でレンダリングを試み、拒否された出力を/root/hs-val/out/schema-reject.txtに保存してください。
Helmは、チャートのルートのvalues.schema.jsonで、マージされた値を検査します。タイプミスのキーをデプロイ前に捕まえることが目的です。注意することが1つあります。環境ファイルにだけあるキーをrequiredに入れると、値ファイルなしでレンダリングする場合まで止まって、前のステップが壊れます。拒否の出力は標準エラー出力に出るので、2>&1で受けないと、ファイルに残りません。
デプロイされたreleaseに実際に入った値を確認する
platformをval-labネームスペースに、platという名前で、-f base.yaml -f prod.yaml --set image.tag=ci-42をそのまま渡してインストールしてください。そのあと、helm get valuesをJSONで受け取って、/root/hs-val/out/user-values.jsonに保存してください。
helm get valuesは、ユーザーが渡した値だけを、--allは、チャートのデフォルト値まで合わせた全体を見せます。事故の調査で先に見るのは、前者です。保存したあと、3つを確認してください。image.tagが--setの値か、tierがあとに渡したファイルの値か、そしてprodにないreplicaCountが、baseの値のまま残っているかです。最後のものが、マップのマージの証拠です。