ConfigMapとSecretで設定を注入する
目標
同じイメージを環境ごとに異なる動作をさせる4つの注入経路(全体の環境変数、個別の環境変数、ファイルボリューム、subPathファイル)を使い分け、SecretとConfigMapの違いをフィールドレベルで扱えるようになります。
なぜ重要なのか
設定の注入で実務の事故が起きるのは、ほとんどが「更新が反映されるか」という点です。環境変数で入れた値はプロセスの開始時に1回読まれて終わりなので、ConfigMapを修正してもPodを作り直すまでは決して変わりません。ボリュームで入れたファイルはkubeletが定期的に更新してくれますが、subPathでマウントしたファイルだけは例外で、更新されません。この3つの動作の違いを知らないと、「設定を変えたのになぜ効かないのか」で時間を使い果たします。
defaultModeも実務でよく引っかかります。Secretをマウントするとデフォルトの権限が0644なので、同じノードの他のプロセスが読めてしまいます。TLSキーのように機密性の高いファイルは0400に絞ります。YAMLで0400を引用符なしで書くと8進数として解釈されますが、400だけを書くと10進数の400として読まれ、意図しない権限になります。
immutable: trueはセキュリティ機能ではなくパフォーマンス機能です。kubeletはマウントされたConfigMap/Secretの変更を監視するためにAPIサーバーを叩き続けますが、immutableなら監視をやめます。数千Pod規模では、apiserverの負荷が目に見えて減ります。
ステップ
- ネームスペース
ckad-configを作成し、その中にConfigMapapp-configをリテラルで作成してください。キーはAPP_MODE=production、LOG_LEVEL=infoです。 - ディレクトリ
/root/ckad-configを作成し、ファイル/root/ckad-config/app.propertiesにtimeout=30を1行書いたうえで、そのファイルからConfigMapapp-propsを作成してください(キー名はapp.propertiesです)。 - Pod
cfg-envを作成してください。イメージはbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"]です。envFromでapp-config全体を注入し、さらにenvにLOGという名前でapp-configのLOG_LEVELキーを参照してください。 - Secret
db-secretを作成してください。タイプはgeneric(Opaque)、キーはDB_USER=appuser、DB_PASSWORD=s3cr3tです。 - Pod
secret-consumerを作成してください。イメージはbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"]です。環境変数DB_PASSWORDをdb-secretのDB_PASSWORDキーから取得し、同じSecretをボリュームdbcredsとして/etc/dbにマウントして、defaultModeを0400にしてください。 - Pod
cfg-volを作成してください。イメージはnginx:1.27です。ConfigMapapp-propsをボリュームpropsとして2回マウントします。1つは/etc/appにディレクトリごと、もう1つはsubPath: app.propertiesで/opt/app/app.propertiesにマウントしてください。 - ConfigMap
feature-flagsを作成してください。キーはNEW_UI=onで、immutable: trueを指定します。Podoptional-cmを作成し(イメージbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"])、存在しないConfigMapmaybe-configをenvFromで参照して、optional: trueを指定してください。 - Deployment
web-configを作成してください。レプリカは2、ラベルはapp=web-config、イメージはnginx:1.27です。envFromにapp-config(configMapRef)とdb-secret(secretRef)の両方を入れ、ConfigMapapp-propsをボリュームpropsとして/etc/appにマウントしてください。
参考
kubectl create configmap app-config -n ckad-config --from-literal=APP_MODE=production --from-literal=LOG_LEVEL=infokubectl create secret generic db-secret -n ckad-config --from-literal=DB_USER=appuser --from-literal=DB_PASSWORD=s3cr3t- YAMLで直接書くときに平文を入れるには、
dataではなくstringDataを使います。保存されると自動的にdataに変換されます。 - よくある間違い1:
defaultModeをコンテナのvolumeMountsの下に書くことです。ボリューム定義(spec.volumes[].secret.defaultMode)の側に書きます。 - よくある間違い2:
immutableをdataの中に入れることです。ConfigMapの最上位のフィールドです。 - 確認:
kubectl get secret db-secret -n ckad-config -o jsonpath='{.data.DB_USER}' | base64 -d
リテラルでConfigMapを作成する
ネームスペースckad-configを作成し、その中にConfigMap app-configをリテラルで作成してください。キーはAPP_MODE=production、LOG_LEVEL=infoです。
kubectl create configmapには、--from-literal=키=값を複数回指定できます(プレースホルダーはキーと値です)。ネームスペースを先に作成しておき、-nを忘れないようにします。
ファイルからConfigMapを作成する
ディレクトリ/root/ckad-configを作成し、ファイル/root/ckad-config/app.propertiesにtimeout=30を1行書いたうえで、そのファイルからConfigMap app-propsを作成してください(キー名はapp.propertiesです)。
--from-file=경로を使うとファイル名がキーになり、ファイルの内容全体が値になります(プレースホルダーはパスです)。キー名を変えたい場合は、--from-file=키이름=경로の形式を使います(プレースホルダーはキー名とパスです)。
envFromとconfigMapKeyRefを併用する
Pod cfg-envを作成してください。イメージはbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"]です。envFromでapp-config全体を注入し、さらにenvにLOGという名前でapp-configのLOG_LEVELキーを参照してください。
envFrom[].configMapRefはすべてのキーをそのまま変数名にし、env[].valueFrom.configMapKeyRefはキーを1つ選んで別の名前で入れます。2つの方式を、1つのコンテナで併用できます。
Secretを作成してエンコードを確認する
Secret db-secretを作成してください。タイプはgeneric(Opaque)、キーはDB_USER=appuser、DB_PASSWORD=s3cr3tです。
kubectl create secret genericの--from-literalの値は、自動的にbase64でエンコードされます。YAMLで直接書くときに平文を入れたい場合は、dataの代わりにstringDataを使います。
Secretを環境変数とファイルの両方で注入する
Pod secret-consumerを作成してください。イメージはbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"]です。環境変数DB_PASSWORDをdb-secretのDB_PASSWORDキーから取得し、同じSecretをボリュームdbcredsとして/etc/dbにマウントして、defaultModeを0400にしてください。
環境変数はenv[].valueFrom.secretKeyRef、ファイルはvolumes[].secret.secretNameとボリュームマウントです。ファイルの権限はボリューム側のdefaultModeで決めます。YAMLでは8進数の先頭の0を落としやすいので、注意してください。
ConfigMapボリュームとsubPath
Pod cfg-volを作成してください。イメージはnginx:1.27です。ConfigMap app-propsをボリュームpropsとして2回マウントします。1つは/etc/appにディレクトリごと、もう1つはsubPath: app.propertiesで/opt/app/app.propertiesにマウントしてください。
ディレクトリに丸ごとマウントすると、そのディレクトリの元の内容が隠れます。ファイル1つだけを載せたい場合は、volumeMounts[].subPathにキー名を書きます。subPathで載せたファイルは、ConfigMapを修正しても更新されません。
optional参照とimmutableなConfigMap
ConfigMap feature-flagsを作成してください。キーはNEW_UI=onで、immutable: trueを指定します。Pod optional-cmを作成し(イメージbusybox:1.36、command: ["/bin/sh","-c","sleep 3600"])、存在しないConfigMap maybe-configをenvFromで参照して、optional: trueを指定してください。
immutable: trueはConfigMapの定義の最上位のフィールドです(dataの中ではありません)。存在しないConfigMapを参照してもPodが起動するようにするには、参照する側にoptional: trueを指定します。
Deploymentで3つを一度に使う(総合)
Deployment web-configを作成してください。レプリカは2、ラベルはapp=web-config、イメージはnginx:1.27です。envFromにapp-config(configMapRef)とdb-secret(secretRef)の両方を入れ、ConfigMap app-propsをボリュームpropsとして/etc/appにマウントしてください。
前に作成したConfigMap 2つとSecret 1つを、1つのDeploymentで使います。envFromの配列には、configMapRefとsecretRefを並べて入れられます。ボリュームマウントも忘れないでください。