はじめに
HelmはKubernetesのエコシステムで非常に便利なパッケージマネージャーですが、「values.yamlだけでは設定できない項目があって困る…」「そのためだけにチャートをフォーク(コピーして改造)するのは、メンテナンスが大変…」と感じたことはありませんか?
この記事では、そんな悩みを解決する強力な手法を紹介します。Kustomizeのパッチ機能を使い、既存のHelmチャートをフォークすることなく、スマートにカスタマイズする方法です。
今回は、人気のプライベートCA(認証局)であるSmallstep step-certificatesを例に、Helmチャートには直接設定するオプションがないACMEプロビジョナーを動的に追加するという、実践的なカスタマイズに挑戦します。
やりたいこと:step-certificatesでACMEを使えるようにする
step-certificatesをKubernetesにデプロイし、内部向け証明書を発行するCAとして利用するケースは多いです。さらに、Let's EncryptでおなじみのACMEプロトコルに対応させれば、cert-managerなどと連携して証明書の自動発行・更新が可能になり、非常に便利です。
しかし、step-certificatesのHelmチャート(バージョン 1.28.4 時点)では、CAの初期設定時にACMEプロビジョナーを自動追加するための直接的なvaluesが用意されていません。
そこで今回は、以下の構成でこの課題を解決します。
- Kustomizeでstep-certificatesのHelmチャートをデプロイする。
- CAの初期化を行う**Bootstrap Jobを「ハイジャック」**する。
- オリジナルの初期化スクリプトに、ACMEプロビジョナーを追加するコマンドを動的に注入する。
全体の仕組み
このカスタマイズの核となるのは、KustomizeでHelmチャートが生成するリソースに「パッチを当てる」という考え方です。
- kustomization.yaml(司令塔):
step-certificatesのHelmチャートを読み込みます。
後述する2つのファイル(ConfigMapとパッチ)をリソースとして指定します。
Helmチャートが生成するJob(Bootstrap Job)に対して、パッチを適用するよう指示します。
- configmap-patch-bootstrap-script.yaml(改造スクリプトの素):
オリジナルの初期化スクリプトを改造するためのシェルスクリプト(patch_bootstrap.sh)を持つConfigMapです。
このスクリプトが、今回のカスタマイズの心臓部です。 3. patch-bootstrap-job.yaml(Jobを乗っ取るパッチ):
Helmチャートが生成するBootstrap Jobの定義を上書きします。
具体的には、Jobが実行するコンテナのコマンドを、我々が用意したpatch_bootstrap.shを実行するように変更します。
各ファイルの詳細解説
それでは、提供された3つのファイルがそれぞれ何をしているのかを詳しく見ていきましょう。
- kustomization.yaml:すべてを束ねる司令塔
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# ... (一部抜粋) ...
helmCharts:
- name: step-certificates
# ... (Helmチャートの指定) ...
version: 1.28.4
valuesInline:
# ...
bootstrap:
enabled: true # 初回起動用のJobを有効化
# ...
resources:
- ../../../../base/smallstep
- ./configmap-patch-bootstrap-script.yaml # 改造用スクリプトの読み込み
patches:
- path: patch-bootstrap-job.yaml # Jobへのパッチを適用
target:
kind: Job
name: step-certificates
- helmCharts:
step-certificatesのHelmチャートを指定しています。
ここで重要なのはbootstrap.enabled: trueです。
これにより、CAを初期化するためのJobリソースが作成されます。このJobこそが、我々のターゲットです。 - resources: configmap-patch-bootstrap-script.yamlを読み込み、改造用スクリプトをクラスタにデプロイできるようにしています。
- patches:
このKustomizationの最重要ポイントです。「step-certificatesという名前のJobリソースに、patch-bootstrap-job.yamlの内容でパッチを当てなさい」という指示を出しています。
- patch-bootstrap-job.yaml:Bootstrap Jobのハイジャック
# patch-bootstrap-job.yaml
---
apiVersion: batch/v1
kind: Job
metadata:
name: step-certificates # パッチを当てる対象のJob名
spec:
template:
spec:
containers:
- name: config # パッチを当てる対象のコンテナ名
command:
- /bin/sh
args:
- -c
- |
# オリジナルのコマンドを上書き!
sh /home/step/patch/patch_bootstrap.sh && sh /home/step/output/modified_bootstrap.sh && sleep 60
volumeMounts:
# ...
- name: bootstrap # Helmが作るオリジナルのスクリプト
mountPath: /home/step/bootstrap
readOnly: true
- name: patch-bootstrap # 我々が作った改造用スクリプト
mountPath: /home/step/patch
- name: output # 改造後のスクリプトを置くための一時領域
mountPath: /home/step/output
このパッチは、Helmが生成したJobのコンテナのcommandとargsを完全に上書きします。
実行されるコマンドの流れ:
- sh /home/step/patch/patch_bootstrap.sh: まず、我々が用意したスクリプトを実行します。このスクリプトは、オリジナルの初期化スクリプトを読み込み、ACMEプロビジョナー追加コマンドを挿入した新しいスクリプトを/home/step/output/modified_bootstrap.shに生成します。
- sh /home/step/output/modified_bootstrap.sh: 次に、動的に生成された改造版の初期化スクリプトを実行します。これにより、ACMEプロビジョナーを含んだ形でCAが初期化されます。
- sleep 60: 処理完了後、コンテナがすぐに終了しないように待機しています。これはデバッグやログ確認のために役立ちます。
volumeMountsで、オリジナルスクリプト、改造用スクリプト、そして改造後のスクリプトを置くための一時領域(emptyDir)をうまくマウントしている点もポイントです。
- configmap-patch-bootstrap-script.yaml:awkを使った華麗なスクリプト改造
# configmap-patch-bootstrap-script.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: patch-bootstrap-script
data:
patch_bootstrap.sh: |
#!/bin/sh
# ... (デバッグ出力など) ...
# 挿入したいコマンド
INSERT_CODE='# Add ACME provisioner with error handling
step ca provisioner add acme --type ACME
# ...'
# 挿入位置の目印となる行
MARKER='rm -f $TMP_CA_PASSWORD $TMP_CA_PROVISIONER_PASSWORD'
BOOTSTRAP_FILE="/home/step/bootstrap/bootstrap.sh" # オリジナル
MODIFIED_FILE="/home/step/output/modified_bootstrap.sh" # 改造後
# awkを使って、MARKERの直前にINSERT_CODEを挿入する
awk -v marker="$MARKER" -v insert="$INSERT_CODE" '
$0 == marker {
print insert
print
next
}
{ print }
' "$BOOTSTRAP_FILE" > "$MODIFIED_FILE"
# 実行権限を付与
chmod +x "$MODIFIED_FILE"
# ...
このシェルスクリプトが、この手法の魔法の正体です。
なぜ新しいスクリプトを生成するのか?: オリジナルのスクリプト(bootstrap.sh)はConfigMapからマウントされており、**読み取り専用(Read Only)**です。そのため、直接編集することはできません。そこで、一時的な書き込み可能領域(emptyDirボリューム)に、改造版のスクリプトを新規作成するというアプローチを取っています。
awkの妙技: awkという強力なテキスト処理コマンドを使い、オリジナルのスクリプト($BOOTSTRAP_FILE)を一行ずつ読み込みます。そして、MARKERとして指定した行(一時パスワードファイルを削除する行)を見つけたら、その直前にINSERT_CODE(ACMEプロビジョナーを追加するコマンド)を挿入し、新しいファイル($MODIFIED_FILE)に出力しています。
これにより、オリジナルの初期化処理の流れを壊すことなく、ピンポイントで目的の処理を追加できるのです。
この手法のメリット
- 宣言的な管理: すべてのカスタマイズがGitで管理されたマニフェストファイルに記述されるため、環境の再現性が高く、GitOpsとの相性も抜群です。
- 保守性の向上: Helmチャートをフォークする必要がありません。元のチャートがバージョンアップした際も、追従が容易になります。パッチが適用できなくなった場合はKustomizeがエラーを出すため、変更に気づきやすいのも利点です。
- 高い柔軟性: シェルスクリプトを使えるため、values.yamlの単純なキー・バリューでは実現できないような、複雑なロジックや動的な設定を初期化処理に組み込めます。
まとめ
今回は、Kustomizeのパッチ機能を使って、既存のHelmチャートをフォークせずに拡張する実践的なテクニックを紹介しました。
一見すると複雑に見えるかもしれませんが、やっていることは「Helmが作るリソースを、Kustomizeで後から上書きする」というシンプルなものです。特に、Bootstrap Jobのような一時的な初期化処理をカスタマイズしたい場合に、この「Jobハイジャック」の手法は非常に有効です。
HelmとKustomizeは競合するツールとして語られることもありますが、このように組み合わせることで、それぞれの長所を活かした、より洗練されたKubernetesの運用管理が可能になります。
皆さんの環境でも、ぜひこのスマートなカスタマイズ手法を試してみてはいかがでしょうか。