依存関係とフック — 組み立てと順序
一言でいうと
依存関係はチャートを組み立てる文法で、フックは、その組み立てられたデプロイの中で「何を先にするか」を決める文法です。
なぜ必要なのか
サービス1つにキャッシュが必要になったとします。キャッシュのマニフェストを同じチャートの中にそのまま入れると、当面は楽です。ところが、2つ目のサービスも同じキャッシュを欲しがった瞬間にコピーが始まり、キャッシュの設定を直す必要が出たとき、何か所を直さなければならないのか、誰にもわかりません。逆に、キャッシュを完全に別のreleaseとして切り離すと、今度は「アプリをデプロイする前にキャッシュがなければならない」という順序を、人が覚えておく必要があります。
依存関係は、この間の折衷です。キャッシュを独立したチャートとして置きつつ、親チャートがそれを宣言的に引き込んで使います。親は自分のvaluesで子の値を上書きでき、条件1つで子をまるごとオフにできます。それでいて、子のチャートは、単独でもインストールできるものとして残ります。
どう動くのか
依存関係は、親のChart.yamlのdependenciesリストに書きます。各項目はname、version、repositoryを持ち、任意でconditionとtagsを持ちます。repositoryはリモートURLでもよいですが、file://で始まるローカルパスでもよいです。ローカルパスは、親チャートのディレクトリを基準にした相対パスとして解釈され、インターネットが遮断された環境や、1つのリポジトリにチャートを一緒に置く構成で、特に便利です。
helm dependency updateを実行すると、2つのことが起こります。依存チャートがパッケージの形でcharts/に置かれ、Chart.lockが作られます。ロックファイルには、実際に確定したバージョンとdigestが入り、このダイジェストが「宣言した依存関係の一覧」のフィンガープリントの役割を果たします。そのため、CIではupdateではなくhelm dependency buildを使います。buildは、ロックファイルに書かれたとおりを再現し、宣言が変わったのにロックファイルが変わっていなければ、その場で失敗します。この区別は、アプリケーションの世界のlockファイルとまったく同じ発想です。
サブチャートに値を渡す規則は単純です。親のvaluesで、サブチャート名と同じキーの下に書いたものが、子の.Valuesの最上位になります。cache:の下にreplicaCount: 3を書くと、子はそれを自分の.Values.replicaCountとして見ます。子のチャートのvalues.yamlには手を付けないまま、親が上書きするのが要点です。逆に、親と子の両方に届く必要がある値は、globalの下に置きます。イメージレジストリのアドレスや環境名のように、システム全体が共有する値が、その場所です。
オンオフの方法は2つです。conditionは、特定の値が真のときだけ子を有効にし、tagsは、タグでまとめられた複数の子を一括で扱います。2つが衝突すると、conditionが勝ちます。
フックは性格が違います。フックはreleaseのライフサイクルの特定の時点に割り込むリソースで、アノテーションで宣言します。
| アノテーション | 意味 |
|---|---|
helm.sh/hook |
いつ実行するか(pre-install、post-install、pre-upgrade、pre-rollbackなど) |
helm.sh/hook-weight |
同じ時点のフック同士の順序。小さい値が先 |
helm.sh/hook-delete-policy |
いつ片づけるか(before-hook-creation、hook-succeeded、hook-failed) |
ここで最もよく間違えるのが、削除ポリシーです。フックのリソースは、releaseが所有しません。そのため、ポリシーを書かないと、アップグレードのたびに、完了したJobがネームスペースにそのまま積み上がり、次のフックが同じ名前で作られようとして衝突します。
現場での姿
1つ目は、オフにしたのに残っているものです。サブチャートを条件でオフにしたのに、レンダリングにまだその名前が見えるなら、親チャートが自分のテンプレートで、子に関連するリソースを直接作っているということです。条件は子のチャートだけをオフにし、親のテンプレートはオフにしません。
2つ目は、アンブレラチャートの代償です。複数のサービスを1つのアンブレラチャートにまとめると、一度にデプロイされて楽ですが、サービス1つを直そうとしても、全体をデプロイしなければなりません。1つのreleaseが失敗したときの影響範囲が、それだけ広がります。独立したデプロイが重要なら、サブチャートとして置いて、それぞれreleaseするほうがよいです。
3つ目は、フックはロールバックされないということです。マイグレーションのJobをフックで実行したあと、デプロイが失敗してロールバックしたからといって、スキーマが元に戻るわけではありません。フックで行う作業は、できるだけ元に戻せるか、何回実行しても安全な作業である必要があります。
次のラボですること
/root/helm/deps/cacheサブチャートと/root/helm/deps/platform親チャートを作り、file://のローカルリポジトリで接続します。ロックファイルが作られることを確認し、親から子の値を上書きし、条件で子をオフにしたりオンにしたりしてみます。globalの値が両方に届くことをラベルで確認し、最後に、フックのJobを付けて、アンブレラのレンダリングレポートを作ります。