ConfigMap: Kubernetes で Pod に渡す設定値

公開

アプリには、動かす環境によって変えたい値がある。接続先のホスト名やログの出力レベルなど。こうした値をコンテナイメージの中に書き込むと、値を変えるたびにイメージを作り直すことになる。

ConfigMap は、設定の値をキーと値の組で保存するリソース。設定をコンテナイメージから切り離しておける。Pod は、ConfigMap の値を環境変数やファイルとして受け取れる。

この記事では、ConfigMap をローカルのクラスタに作り、Pod に環境変数とファイルの2通りで渡して、ConfigMap を書き換えたときの動きを確認する。

この記事でやること:

  • ConfigMap の YAML の確認
  • ConfigMap の作成と中身の確認
  • 環境変数としての受け取り
  • ファイルとしての受け取り
  • ConfigMap を書き換えたときの動き
  • Pod を作り直したときの動き
  • ConfigMap がない状態での Pod の起動

環境

kind で作ったクラスタ(Control Plane 1台 + Worker 2台)を使う。(作り方は「Kubernetes の Pod とは?コンテナを動かす最小単位を整理する」を参照)

  • 環境: macOS(Apple Silicon)、Docker Desktop 29.8.0、kind v0.33.0、Kubernetes v1.37.0、kubectl v1.36.1

ConfigMap の YAML

app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  color: blue
  message.txt: |
    Hello from ConfigMap
    This is line 2
場所 意味
metadata.name ConfigMap の名前。Pod からは、この名前で参照する
data 設定の本体。キーと値の組を並べる
  • Pod や Deployment の YAML にある spec は、ConfigMap にはない。代わりに data を持つ
  • color は1行の値、message.txt は複数行の値(| は、続く字下げした行をまとめて1つの値にする YAML の書き方)
  • ConfigMap は、1行の値と複数行の値を区別しない。違いが出るのは、Pod がその値をどう受け取るか

ConfigMap を作る

$ kubectl apply -f app-config.yaml

# => configmap/app-config created

$ kubectl get configmaps

NAME               DATA   AGE
app-config         2      15s
kube-root-ca.crt   1      4d10h
  • app-config が作った ConfigMap。kube-root-ca.crt は最初からあるもの
  • DATA の 2 は、キーの数

中身は kubectl describe で確認できる。

$ kubectl describe configmap app-config

Name:         app-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
color:
----
blue

message.txt:
----
Hello from ConfigMap
This is line 2



BinaryData
====

Events:  <none>

Data に、YAML に書いたキーと値がそのまま入っている。

ConfigMap はどこにあるか

ConfigMap は、動いているプログラムではなく、YAML に書いた内容が記録されたデータ(オブジェクト)。Service や Deployment と同じく、Control Plane で動いている etcd に保存される。(「Service: Kubernetes で Pod への宛先を固定する」の「Service や Deployment はどこにあるか」を参照)

flowchart TB
    subgraph CP["Control Plane: k8s-study-control-plane"]
        subgraph ETCD["etcd(保存されたデータ)"]
            S["Service"]
            CM["ConfigMap<br/>app-config"]
            D["Deployment<br/>demo-app"]
            RS["ReplicaSet<br/>demo-app-6bbfb9c47b"]
        end
    end

    subgraph W1["Node: k8s-study-worker"]
        P1(["Pod demo-app-...-cptw4"])
    end

    S -.->|"届け先の Pod の条件"| P1
    CM -->|"Pod に渡す設定の値"| P1

    D -->|"ReplicaSet の元になる定義"| RS
    RS -.->|"Pod の数と中身の定義"| P1
  • ConfigMap、Service、Deployment、ReplicaSet は、Control Plane の etcd に保存されたデータ。Control Plane で動いているプログラムではない
  • 図のリソースのうち、Node の上にあるのは Pod だけ
  • 矢印は、そのデータが何についての定義かを示す。データ自身が何かを作ったり渡したりするわけではない
  • 保存されたデータを読んで実際に動くのは、別のプログラム。Deployment や ReplicaSet のデータを読んで Pod を作るのは Control Plane の kube-controller-manager、ConfigMap のデータを読んでコンテナに渡すのは Node の kubelet
  • Deployment demo-app と Pod は、このあと作るもの
  • ConfigMap を作っただけでは、Pod は増えない。どの Node の上でも何も動かない
  • ConfigMap の値が使われるのは、ConfigMap を参照する Pod のコンテナが起動するとき。その Pod が置かれた Node の kubelet が、ConfigMap のデータを使ってコンテナを起動する

Pod から ConfigMap を参照する

どの ConfigMap を使うかは、Deployment の YAML に書く。

Pod を1つ動かす Deployment を用意する。(Deployment については「Deployment: Kubernetes で Pod の数と更新を管理する」を参照)

demo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-app
  template:
    metadata:
      labels:
        app: demo-app
    spec:
      containers:
        - name: nginx
          image: nginx:1.16.1
          env:
            - name: APP_COLOR
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: color
          volumeMounts:
            - name: config-volume
              mountPath: /config
              readOnly: true
      volumes:
        - name: config-volume
          configMap:
            name: app-config

ConfigMap を参照しているのは、env と、volumeMounts・volumes の2か所。コンテナの image は nginx だが、nginx の機能は使わない。動き続けるコンテナとして使っている。

$ kubectl apply -f demo-deployment.yaml

# => deployment.apps/demo-app created

$ kubectl get pods -o wide

NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE               NOMINATED NODE   READINESS GATES
demo-app-6bbfb9c47b-cptw4   1/1     Running   0          5s    10.244.1.2   k8s-study-worker   <none>           <none>

環境変数として受け取る

          env:
            - name: APP_COLOR
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: color
場所 意味
env.name コンテナに設定する環境変数の名前
configMapKeyRef.name 参照する ConfigMap の名前
configMapKeyRef.key その ConfigMap の中のキー。このキーの値が、環境変数の値になる

Pod のコンテナの中で、環境変数を表示する。

$ kubectl exec deploy/demo-app -- printenv APP_COLOR

# => blue
部分 意味
kubectl exec Pod のコンテナの中でコマンドを実行する
deploy/demo-app Deployment demo-app の Pod を対象にする。Pod の名前を指定しなくて済む
-- printenv APP_COLOR コンテナの中で実行するコマンド。環境変数 APP_COLOR の値を表示する
  • ConfigMap の color の値(blue)が、コンテナの環境変数 APP_COLOR に入っている
  • 環境変数の名前は、ConfigMap のキーと別の名前にできる

ファイルとして受け取る

          volumeMounts:
            - name: config-volume
              mountPath: /config
              readOnly: true
      volumes:
        - name: config-volume
          configMap:
            name: app-config

Pod のコンテナの中で、/config を見る。

$ kubectl exec deploy/demo-app -- ls /config

color
message.txt

$ kubectl exec deploy/demo-app -- cat /config/message.txt

Hello from ConfigMap
This is line 2

$ kubectl exec deploy/demo-app -- cat /config/color

# => blue
  • ConfigMap のキーがファイル名、値がファイルの中身になっている
  • キーが2つあるので、ファイルも2つ

volumes と volumeMounts

ファイルとして受け取る指定は、volumes と volumeMounts の2か所に分かれている。

volume は、Pod の中のコンテナからアクセスできるディレクトリ。ConfigMap を元にした volume の場合、Pod が置かれた Node の kubelet が ConfigMap のデータを取得し、その Node の上でファイルにする。kubelet は、その volume をコンテナの中にマウントする。

volumes volumeMounts
内容 Pod に用意する volume の指定 volume を、コンテナの中のどこにマウントするかの指定
YAML の場所 Pod の spec の直下 各コンテナの中
今回の指定 ConfigMap app-config を元にした volume を、config-volume という名前で用意する config-volume を、コンテナの中の /config にマウントする
  • 2か所は、volume の名前(config-volume)で対応している
  • volume は Pod に用意されるもので、コンテナの外にある。Pod の中のコンテナは、マウントすることで volume にアクセスできる
  • volume の実体は、Pod が置かれた Node の上のディレクトリ
  • Pod にコンテナが複数ある場合、volumeMounts はコンテナごとに書く。volumes は ConfigMap ごとに1つでよい

ConfigMap と Pod の関係

flowchart TB
    CM["ConfigMap<br/>app-config<br/>color / message.txt"]

    subgraph W1["Node: k8s-study-worker"]
        subgraph P["Pod demo-app-6bbfb9c47b-cptw4"]
            V["volume<br/>config-volume<br/>color / message.txt"]
            subgraph C["コンテナ nginx"]
                ENV["環境変数<br/>APP_COLOR=blue"]
                F["ディレクトリ /config<br/>color / message.txt"]
            end
        end
    end

    CM -->|"env の configMapKeyRef"| ENV
    CM -->|"volumes"| V
    V -->|"volumeMounts"| F
  • ConfigMap は、どの Node にも属していない。Node の上にあるのは、Pod とその volume
  • 環境変数は、ConfigMap のキー color の値だけを受け取っている
  • volume は、ConfigMap のすべてのキーをファイルとして持つ

ConfigMap を書き換える

app-config.yaml の color を blue から green に書き換えて、apply する。

data:
  color: green
$ kubectl apply -f app-config.yaml

# => configmap/app-config configured

Pod には何もせずに、環境変数とファイルをもう一度見る。

$ kubectl exec deploy/demo-app -- printenv APP_COLOR

# => blue

$ kubectl exec deploy/demo-app -- cat /config/color

# => green
受け取り方 ConfigMap を書き換えた後
環境変数 blue のまま
ファイル green に変わった
  • ファイルは、Pod を作り直さなくても更新される。ただし apply の直後には変わらず、今回は数秒程度かかった
  • 更新までの時間は、最大で「kubelet の同期の間隔 + キャッシュの伝播にかかる時間」
  • 環境変数として受け取った値は、自動では更新されない
  • ファイルが更新されても、起動時に一度だけ設定を読み込むアプリは、変更に気づかない

Pod を作り直す

環境変数に新しい値を渡すには、Pod を置き換える。Deployment の Pod は、kubectl rollout restart で新しい Pod に入れ替えられる。

$ kubectl rollout restart deployment demo-app

# => deployment.apps/demo-app restarted

$ kubectl rollout status deployment demo-app

# => deployment "demo-app" successfully rolled out

$ kubectl get pods

NAME                        READY   STATUS    RESTARTS   AGE
demo-app-67cf57bf8f-sfcfd   1/1     Running   0          14s

$ kubectl exec deploy/demo-app -- printenv APP_COLOR

# => green
コマンド 意味
kubectl rollout restart deployment demo-app Deployment demo-app の Pod を、新しい Pod に入れ替える
kubectl rollout status deployment demo-app 入れ替えが終わるまで待つ

上の kubectl get pods と printenv の結果からわかること:

入れ替える前(Deployment を作ったとき) 入れ替えた後
Pod の名前 demo-app-6bbfb9c47b-cptw4 demo-app-67cf57bf8f-sfcfd
環境変数 APP_COLOR blue green
  • kubectl get pods に出ている Pod は、Deployment を作ったときの Pod とは名前が違う。別の Pod に入れ替わっている
  • 入れ替わった後の Pod では、printenv APP_COLOR の結果が green になっている
環境変数 APP_COLOR ファイル /config/color
最初 blue blue
ConfigMap を書き換えた後 blue green
Pod を作り直した後 green green

ConfigMap と Deployment を消す

Deployment と ConfigMap は別々のリソースなので、それぞれ消す。

$ kubectl delete -f demo-deployment.yaml

# => deployment.apps "demo-app" deleted from default namespace

$ kubectl delete -f app-config.yaml

# => configmap "app-config" deleted from default namespace

$ kubectl get configmaps

NAME               DATA   AGE
kube-root-ca.crt   1      4d10h

ConfigMap がない状態で Pod を起動する

ConfigMap を作らずに、Deployment だけを apply する。

$ kubectl apply -f demo-deployment.yaml

# => deployment.apps/demo-app created

$ kubectl get pods

NAME                        READY   STATUS              RESTARTS   AGE
demo-app-6bbfb9c47b-lhjpg   0/1     ContainerCreating   0          5s

STATUS は ContainerCreating のままで、Running にならない。kubectl describe pod の Events: は次のとおり。

$ kubectl describe pod -l app=demo-app

(省略)
Events:
  Type     Reason       Age               From               Message
  ----     ------       ----              ----               -------
  Normal   Scheduled    21s               default-scheduler  Successfully assigned default/demo-app-6bbfb9c47b-lhjpg to k8s-study-worker
  Warning  FailedMount  5s (x6 over 21s)  kubelet            MountVolume.SetUp failed for volume "config-volume" : configmap "app-config" not found
  • Pod は Node(k8s-study-worker)に割り当てられている
  • その Node の kubelet が volume config-volume を用意しようとして、ConfigMap app-config が見つからずに失敗している(FailedMount)
  • 参照先の ConfigMap が存在しない場合、その参照を optional にしていなければ、Pod は起動しない

機密情報は ConfigMap に入れない

ConfigMap は、機密性や暗号化を提供しない。パスワードのような機密情報には、ConfigMap ではなく Secret を使う。

用語メモ

用語 読み方 意味
ConfigMap コンフィグマップ 機密性のない設定の値を、キーと値の組で保存するリソース
configMapKeyRef コンフィグマップ キー レフ 環境変数の値として、ConfigMap の特定のキーを参照する指定
volume ボリューム Pod の中のコンテナからアクセスできるディレクトリ
volumeMounts ボリュームマウンツ volume を、コンテナの中のどこにマウントするかの指定
kubelet キューブレット 各 Node で動き、Pod のコンテナを起動するコンポーネント

まとめ

  • ConfigMap は、設定の値をキーと値の組で保存するリソース。設定をコンテナイメージから切り離しておける
  • ConfigMap は動いているプログラムではなく、保存されたデータ。値が使われるのは、参照する Pod のコンテナが起動するとき
  • どの ConfigMap を使うかは、Deployment の YAML に書く
  • 環境変数として受け取るには、env の configMapKeyRef で ConfigMap の名前とキーを指定する
  • ファイルとして受け取るには、volumes で ConfigMap を元にした volume を用意し、volumeMounts でコンテナの中にマウントする。キーがファイル名、値がファイルの中身になる
  • ConfigMap を書き換えると、ファイルは Pod を作り直さなくても更新される。環境変数は、Pod を作り直すまで変わらない
  • 参照先の ConfigMap が存在しないと、Pod は起動しない
  • 機密情報には、ConfigMap ではなく Secret を使う

参考 URL

Ritolabo

100%