TT Lab
はじめる
学ぶ 学習パス コース

Helmチャートの作成とデプロイ

依存関係とフック — 組み立てと順序

TT Labで続きを見る

一言でいうと

依存関係はチャートを組み立てる文法で、フックは、その組み立てられたデプロイの中で「何を先にするか」を決める文法です。

なぜ必要なのか

サービス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を付けて、アンブレラのレンダリングレポートを作ります。