設定:ConfigMap と Secret
設定と認証情報をイメージの外に置き、Pod に注入し、よくある落とし穴を避けます。
データベースの URL やログレベルがコンテナイメージに埋め込まれていると、それを変更するには、イメージの再ビルド、プッシュ、再デプロイが必要になります。Kubernetes は、設定とイメージを 2 つのオブジェクトで分離します。通常の設定用の ConfigMap と、機密性のある値用の Secret です。このガイドでは、両方の作成方法、Pod に取り込む方法、そして Secret が何を守り、何を守らないかを説明します。
ConfigMap を作成する
ConfigMap は、キーと値のペアの集合です。値は短い文字列でも、ファイル全体でも構いません。
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
LOG_LEVEL: info
API_URL: http://api.internal:8080
motd.txt: |
Welcome to the demo environment
コマンドラインからも作成でき、ファイルには便利です。
kubectl create configmap web-config \
--from-literal=LOG_LEVEL=info \
--from-file=motd.txt
kubectl describe configmap web-config
ConfigMap は、小さく機密性のないデータ向けで(上限は 1 MiB)、namespace に属します。Pod は、自分の namespace の ConfigMap しか使えません。
環境変数またはファイルとして使う
同じ Pod が、ConfigMap を両方の方法で利用できます。
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: web
image: nginx:1.25
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: LOG_LEVEL
volumeMounts:
- name: config
mountPath: /usr/share/nginx/html/motd.txt
subPath: motd.txt
volumes:
- name: config
configMap:
name: web-config
ここでは 2 つのことが起きています。env のエントリは、1 つのキーを環境変数にコピーします。(envFrom は、すべてのキーを一度にインポートできますが、有効な変数名ではないキーはスキップされます。)volumes と volumeMounts のエントリは、ConfigMap をファイルとしてマウントし、キーごとに 1 つのファイルになります。
ConfigMap 全体を、このようなディレクトリにマウントすると、そのディレクトリはマウントされたファイルに置き換えられます。
volumeMounts:
- name: config
mountPath: /etc/web
自分が所有するディレクトリなら問題ありませんが、そのパスにすでにあったものが隠されます。/etc/nginx のような既存の設定ディレクトリにマウントすると、アプリケーションが壊れる可能性があり、コンテナが「file not found」エラーでクラッシュループに入ることがあります。そのために subPath があります。最初の例のように、単一のキーを単一のファイルとしてマウントし、ディレクトリの残りには手を付けません。トレードオフは、subPath でマウントされたファイルには、その後の ConfigMap の更新が反映されないことです。
コンテナに何が入ったかを確認します。
kubectl exec web -- ls /usr/share/nginx/html
kubectl exec web -- env | grep LOG_LEVEL
認証情報を Secret に保存する
Secret は ConfigMap に似ていますが、パスワード、トークン、鍵のためのものです。
kubectl create secret generic db-credentials \
--from-literal=username=app \
--from-literal=password='S3cr3t-value'
YAML では、stringData を使ってプレーンテキストで書き、エンコードを Kubernetes に任せます。
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: app
password: S3cr3t-value
エンコードされた data フィールドを自分で書く場合は、echo -n 'value' | base64 でエンコードします。-n がないと、末尾の改行がパスワードの一部になり、認証が分かりにくい形で失敗します。Secret は ConfigMap と同じように使います。
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
実際の値が入った Secret のマニフェストを Git にコミットするのは避けてください。Sealed Secrets、External Secrets Operator、SOPS などのツールは、暗号化された、あるいは参照のみのシークレットをリポジトリに保管できるようにするために存在します。
Secret が守るものと守らないものを知る
Base64 はエンコードであって、暗号化ではありません。API 経由で Secret を読める人は誰でも、デコードできます。
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
デフォルトでは、Secret は etcd にも暗号化されずに保存されます。実際に保護するには、次のようにします。
- RBAC で Secret を読める人を制限します。また、namespace に Pod を作成できる人は誰でも、その Secret をマウントできることを忘れないでください。
- etcd の保存時の暗号化を有効にするか、クラウドプロバイダーのキー管理を使います。
- 要件が厳しい場合は、外部のシークレットマネージャーを検討します。
環境変数は便利ですが漏洩しやすく、kubectl exec ... env、クラッシュダンプ、ときにはログに現れます。機密性のある値は、Secret をファイルとしてマウントするほうが、より良い選択であることがよくあります。
設定の更新を意図的に行う
環境変数はコンテナの起動時に一度だけ読み込まれるため、変更された ConfigMap や Secret は、実行中の Pod には届きません。変更を反映するには、再起動してください。
kubectl rollout restart deployment/web
ディレクトリ全体をマウントした場合のファイルは、いずれ更新されますが、多くのアプリケーションは、どのみち起動時にしか設定を読み込みません。自動化された構成では、設定が変わるたびに Pod テンプレートが変わるようにします。Argo CD の Helm と Kustomize のガイドの、設定ハッシュの手法は、そのためのものです。
人気のガイド
-
Kubernetes とは何か、そしてそれが解決する問題 コンテナだけではスケールしなくなる理由と、Kubernetes がマシンの集まりを 1 つのプラットフォームに変える方法。 -
Kubernetes クラスターの仕組み:コントロールプレーンとノード クラスターを動かすコンポーネントと、kubectl apply から実行中のコンテナまでの間に何が起きるか。 -
Deployment:スケーリング、自己修復、ローリングアップデート Pod のレプリカを実行し、ダウンタイムなしで更新し、リリースがうまくいかなかったときにロールバックします。 -
Service:短命な Pod のための安定したネットワーキング Pod に安定したアドレスを与え、クラスターの内外に公開し、誰が誰と通信できるかを制限します。 -
失敗する Pod をデバッグする:describe、logs、exec、port-forward Pod が Pending のまま、クラッシュする、応答しない原因を突き止めるための、繰り返し使えるチェックリスト。