2026年7月1日
2026年7月1日
KubernetesのConfigMapとSecretの使い分けと管理方法|作成・Podへの渡し方・更新の反映
Kubernetesでは、アプリケーションの設定をコンテナイメージに埋め込まず、ConfigMap(一般の設定)とSecret(パスワードやAPIキーなどの機密情報)として別に管理し、Podに渡します。こうすると、同じイメージを開発・検証・本番で使い回し、環境ごとに設定だけを変えられます。
この記事では、2つの違い、作り方、Podへの渡し方、更新したときの反映のされ方、Secretを守るための注意点を説明します。内容は2026年10月時点のKubernetes公式ドキュメント(kubernetes.io)に合わせています。
ConfigMapとSecretの違い
| 項目 | ConfigMap | Secret |
|---|---|---|
| 用途 | 機密でない設定(ログレベル、接続先のホスト名、設定ファイル) | パスワード、APIキー、TLSの証明書と鍵、レジストリの認証情報 |
data の値 |
そのままの文字列 | base64でエンコードした文字列(stringData なら平文で書ける) |
| 大きさの上限 | 1MiB | 1MiB |
| 暗号化 | されない | 既定ではされない(後述の保存時の暗号化を設定した場合のみ) |
| 種類 | なし | Opaque(汎用)、kubernetes.io/tls、kubernetes.io/dockerconfigjson など |
注意したいのは、Secretのbase64はエンコードであって暗号化ではないことです。公式ドキュメントでも、Secretは既定ではAPIサーバーのデータストア(etcd)に暗号化されずに保存され、APIにアクセスできる人やetcdにアクセスできる人は読み書きできると説明しています。Secretという名前だけで守られるわけではないので、後半の設定もあわせて行います。
どちらも名前空間(namespace)ごとのリソースで、Podが参照できるのは同じ名前空間のConfigMapとSecretだけです。
ConfigMapを作る
kubectlのコマンドで作る
# キーと値を直接指定する
kubectl create configmap app-config \
--from-literal=LOG_LEVEL=info \
--from-literal=API_HOST=api.example.com
# ファイルの中身を1つのキーとして登録する(キー名はファイル名になる)
kubectl create configmap nginx-conf --from-file=default.conf
# 内容を確認する
kubectl get configmap app-config -o yaml
YAMLで作る
設定をGitで管理する場合はYAMLで書きます。複数行の設定ファイルは | を使ってそのまま書けます。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
API_HOST: "api.example.com"
app.json: |
{
"featureX": true,
"timeoutSeconds": 30
}
kubectl apply -f configmap.yaml
Secretを作る
kubectlのコマンドで作る
kubectl create secret generic を使うと、base64へのエンコードは自動で行われます。
kubectl create secret generic db-secret \
--from-literal=DB_USER=appuser \
--from-literal=DB_PASSWORD='change-me'
コマンドラインに書いた値はシェルの履歴に残ります。本番の値は、ファイルから読み込む(--from-file)か、履歴に残らない方法で渡してください。
YAMLで作る
data に書く値はbase64でエンコードしたものです。
echo -n 'appuser' | base64
# YXBwdXNlcg==
-n を付けないと改行までエンコードされ、パスワードの末尾に改行が入ってしまいます。手作業のエンコードを避けたい場合は、stringData に平文で書けます(保存時に data に変換されます)。
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
DB_USER: YXBwdXNlcg==
stringData:
DB_PASSWORD: change-me
同じキーが data と stringData の両方にある場合は、stringData の値が使われます。平文のパスワードを書いたYAMLをそのままGitに入れないでください。
中身の確認は次のとおりです。-o yaml で見えるのはbase64の値なので、デコードして確かめます。
kubectl get secret db-secret -o jsonpath='{.data.DB_USER}' | base64 -d
Podに渡す
渡し方は主に「環境変数」と「ファイル(ボリューム)」の2つです。
環境変数として渡す
キーを1つずつ指定する方法(valueFrom)と、全部のキーをまとめて渡す方法(envFrom)があります。
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: nginx:1.27
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
envFrom:
- configMapRef:
name: app-config
envFrom を使うと、ConfigMapのキー名がそのまま環境変数名になります。この例では app.json のような設定ファイル用のキーまで環境変数になるので、必要なキーだけを渡したい場合は env で1つずつ指定します。
確認は次のとおりです。
kubectl exec app -- printenv LOG_LEVEL
ファイルとして渡す
ボリュームとしてマウントすると、キーごとに1つのファイルができます。ファイル名がキー名、中身が値です。
apiVersion: v1
kind: Pod
metadata:
name: app-files
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
- name: secret
mountPath: /etc/app-secret
readOnly: true
volumes:
- name: config
configMap:
name: app-config
items:
- key: app.json
path: app.json
- name: secret
secret:
secretName: db-secret
defaultMode: 0400
items を書くと、指定したキーだけがファイルになります(この例では /etc/app/app.json だけ)。省略すると全部のキーがファイルになります。Secretの defaultMode はファイルの権限で、YAMLでは先頭に 0 を付けた8進数で書けます。
kubectl exec app-files -- cat /etc/app/app.json
kubectl exec app-files -- ls -l /etc/app-secret/
SecretがPod内のどこに置かれるかは、mountPath で指定した場所です。マウントしていないSecretは、Pod内のファイルとしては存在しません。
更新したときの反映のされ方
ConfigMapやSecretを書き換えても、使い方によって反映のされ方が違います。
| 渡し方 | 更新後の動き |
|---|---|
| ボリュームとしてマウント | kubeletが定期的に確認し、少し遅れてファイルが新しい内容に置き換わる |
subPath でマウント |
更新されない |
環境変数(env・envFrom) |
更新されない。Podを作り直す必要がある |
ファイルが置き換わっても、アプリケーションが起動時に1回だけ設定を読む作りなら、再読み込みしない限り反映されません。環境変数で渡した値を反映させるには、Deploymentの場合は次のようにPodを順に作り直します。
kubectl rollout restart deployment/app
変更しないものはimmutableにする
immutable: true を付けたConfigMapとSecretは、内容を変更できなくなります(Kubernetes 1.21で正式機能)。誤って書き換えて障害になるのを防げるほか、kubeletが変更を監視しなくてよくなるので、大量に使うクラスターではAPIサーバーの負荷が下がります。
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v2
data:
LOG_LEVEL: "warn"
immutable: true
一度immutableにすると元に戻せず、変更するには削除して作り直します。運用では、app-config-v2 のように名前に版を付けて新しいものを作り、Podの参照先を切り替える方法が扱いやすくなります。
Secretを守るための設定
公式ドキュメントでは、Secretを安全に使うために少なくとも次を行うよう求めています。
- 保存時の暗号化(Encryption at Rest)を有効にする: kube-apiserverに
EncryptionConfigurationを設定すると、etcdに保存されるSecretが暗号化されます。マネージドサービス(EKS、GKE、AKSなど)では各サービスの設定方法に従います。 - RBACで最小権限にする: Secretの
get・list・watchを許可するロールは、必要な人とサービスアカウントに限ります。listでも中身まで取得できる点に注意します。 - Secretを使うコンテナを限定する: 必要なコンテナだけにマウントや環境変数で渡します。
- 外部のシークレットストアの利用を検討する: クラウドのシークレット管理サービスなどと連携させる方法があります。
あわせて、公式ドキュメントには、名前空間の中でPodを作成できる人は、その名前空間のSecretを(Deploymentの作成などを通じて間接的にも)読めるという注意があります。Podを作れる権限もSecretへのアクセス権の一部として扱ってください。
よくあるつまずき
- Podが起動しない: 参照しているConfigMap・Secret、またはそのキーが存在しない。環境変数で参照している場合は
CreateContainerConfigError、ボリュームの場合はContainerCreatingのまま止まる。kubectl describe pod <Pod名>のEventsに、見つからない名前が表示される。存在しなくても起動させたい参照にはoptional: trueを付ける - パスワードが合わない: YAMLに書くbase64を
echoの-nなしで作り、末尾に改行が入っている - 値を変えたのに反映されない: 環境変数や
subPathで渡している(上の表を参照)
まとめ
- 機密でない設定はConfigMap、機密情報はSecretに入れ、どちらも1MiBまで
- Secretのbase64は暗号化ではない。保存時の暗号化とRBACで守る
- Podへは環境変数(
env・envFrom)かボリュームで渡す - ボリュームで渡した値は少し遅れて更新されるが、環境変数と
subPathは更新されない - 変更しない設定は
immutable: trueにして、名前に版を付けて切り替える
関連記事: