Kubernetes基本機能の一つであるConfigMapのおさらい。
2022.12.08 Secretについての記事リンク追加 (末尾)
ConfigMapを作る
key=valueの形式をCLIから
--from-literal
でkey=valueを指定する。
複数設定可能。
$ kubectl create configmap key-value-sample -n configmap-example \ --from-literal=SAMPLE_HOST='10.0.0.2' \ --from-literal=SMAPLE_PORT='25'
--dry-run -o yaml
で実行すると以下のConfigMapが生成されることがわかる。
[zaki@cloud-dev configmap (master)]$ kubectl create configmap key-value-sample -n configmap-example \ > --from-literal=SAMPLE_HOST='10.0.0.2' \ > --from-literal=SMAPLE_PORT='25' \ > --dry-run -o yaml W1227 10:41:53.955673 60645 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 data: SAMPLE_HOST: 10.0.0.2 SMAPLE_PORT: "25" kind: ConfigMap metadata: creationTimestamp: null name: key-value-sample namespace: configmap-example
key=value形式のファイルから
HOST=10.0.0.2 PORT=25
こういうkey=value
という(デリミタが=
になっている)形式になっているファイルであれば、--from-env-file
で指定してConfigMapリソースを作成することができる。
上記の内容のsample.ini
ファイルがあるとして、以下を実行する。
$ kubectl create configmap key-value-sample -n configmap-example \ --from-env-file=sample.ini
--dry-run
すると以下の通り。
[zaki@cloud-dev configmap (master)]$ kubectl create configmap sample --from-env-file=sample.ini --dry-run -o yaml W1227 16:17:56.885645 115674 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 data: HOST: 10.0.0.2 PORT: "25" kind: ConfigMap metadata: creationTimestamp: null name: sample
以下の形式のファイルだと無効
KEY: VALUE
また、iniファイルのようにセクション名が入っていても無効。
[smtp] HOST=10.0.0.2 PORT=25
#
によるコメントは無視されるので期待通りに処理される。(;
によるコメントは無効)
#[config] HOST=10.0.0.2 PORT=25
ファイルの埋め込み
--from-file
でファイルを指定する。
複数指定可能。
$ kubectl create configmap file-sample -n configmap-example \ --from-file=/etc/hosts \ --from-file=/etc/resolv.conf
--dry-run -o yaml
を付与して実行すると以下の通り。
ConfigMap内におけるファイル名は作成時に指定するファイル名がそのまま使用される。
[zaki@cloud-dev configmap (master)]$ kubectl create configmap file-sample -n configmap-example \ > --from-file=/etc/hosts \ > --from-file=/etc/resolv.conf \ > --dry-run -o yaml W1227 10:50:53.399027 63085 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 data: hosts: | 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 resolv.conf: | # Generated by NetworkManager nameserver 192.168.0.19 kind: ConfigMap metadata: creationTimestamp: null name: file-sample namespace: configmap-example
指定ディレクトリ直下の全ファイルを指定
ファイル埋め込みは--from-file
を複数指定で複数ファイル指定が可能だが、--from-file
にディレクトリを指定すればそのディレクトリ直下の全ファイルがConfigMapに含めることができる。
$ kubectl create configmap dir-sample -n configmap-example \ --from-file=${HOME}/work/sample
以下のようなファイルがある状態で、
[zaki@cloud-dev configmap (master)]$ find ~/work/sample /home/zaki/work/sample /home/zaki/work/sample/sample1.txt /home/zaki/work/sample/sample2.txt /home/zaki/work/sample/.dot-file.txt /home/zaki/work/sample/subdir /home/zaki/work/sample/subdir/example.txt
--dry-run -o yaml
を付与して実行すると以下の通り。
[zaki@cloud-dev configmap (master)]$ kubectl create configmap dir-sample -n configmap-example \ > --from-file=${HOME}/work/sample \ > --dry-run -o yaml W1227 11:05:36.681042 67278 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 data: .dot-file.txt: | this is dot file. sample1.txt: | nya-n wanwan sample2.txt: | this file is sample file. curry tabetai! kind: ConfigMap metadata: creationTimestamp: null name: dir-sample namespace: configmap-example
指定ディレクトリ直下のドットファイルは含まれるが、サブディレクトリは無視される。
ハードタブを含むファイルの場合
YAML内にハードタブは含むことができないため、KYE-VALUE形式と同じように1行で記述され改行やハードタブはエスケープ文字が使われる。
以下はsample2.txt
の各行の先頭をハードタブ(\t
でインデントした場合)
apiVersion: v1 data: sample2.txt: "\tthis file is sample file.\n\tcurry tabetai!\n" kind: ConfigMap metadata: creationTimestamp: null name: dir-sample namespace: configmap-example
バイナリファイルの場合
バイナリ使えるのはSecretだけかと思ってたけど、ConfigMapも「UTF-8以外のデータを含む場合はバイナリとみなされBase64エンコード」されてリソースが作成される。
[zaki@cloud-dev configmap (master)]$ ls -l ~/src/usansible/src/icons/usansible.png -rw-rw-r--. 1 zaki zaki 5445 9月 26 00:21 /home/zaki/src/usansible/src/icons/usansible.png [zaki@cloud-dev configmap (master)]$ file ~/src/usansible/src/icons/usansible.png /home/zaki/src/usansible/src/icons/usansible.png: PNG image data, 128 x 128, 8-bit/color RGBA, non-interlaced
上記のデータでConfigMapを作ると、
[zaki@cloud-dev configmap (master)]$ kubectl create configmap binary-sample -n configmap-example \> --from-file=${HOME}/src/usansible/src/icons/usansible.png --dry-run -o yaml W1227 11:16:56.211264 70269 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client. apiVersion: v1 binaryData: usansible.png: iVBORw0KGgoAAAANSUhEUgAAAI ... kind: ConfigMap metadata: creationTimestamp: null name: binary-sample namespace: configmap-example
この通り、PNG画像ファイルがBase64エンコードされてConfigMapが作成される。
マウントすればデコードされて元のデータを使用できる。
YAMLのマニフェストで作成
0から作るよりは上記の出力を参考に--dry-run -o yaml
の結果をファイルリダイレクトすると簡単に作れる。
注意点として、data
に指定できるのは文字列のみのため、ポート番号のように数値(m/[0-9]+/
)のみの指定になる場合はクォートで囲まないとYAML的に数値とみなされてエラーとなる。
ConfigMapをPodから参照する
環境変数として参照
apiVersion: v1 data: SAMPLE_EDITOR: emacs SAMPLE_SERVER: 10.0.0.2 SAMPLE_PORT: '8080' SAMPLE_USERNAME: curry kind: ConfigMap metadata: name: configmap-key-value
こんなConfigMapがあるとして、、
ConfigMap内データ全てを環境変数として使用する
key=valueとして作成したConfigMapを環境変数に使用するには、対象のcontainers定義で以下のようにenvFrom:
を指定すれば、対象ConfigMapの全データが環境変数としてコンテナに設定される。
configmap-key-value
という名前のConfigMapリソースを参照する場合は以下の通り。
containers: - image: httpd name: httpd envFrom: - configMapRef: name: configmap-key-value
ConfigMapの指定キーのみを環境変数で使用する
全てのキーでなく、指定キーのみを参照したい場合は、env.[].valueFrom
を使用する。
configmap-key-value
というConfigMap内にあるSAMPLE_EDITOR
のみを使用する場合は以下の通り。
以下では、更に環境変数のキー名をコンテナ上ではPICKUPED_CONFIGMAP_KEYVAL
として使うような内容になっている。(env.[].name
は必須キー)
(configMapKeyRef.key
でConfigMapの指定キーを取り出して、env.[].name
の名前で環境変数名としている、ということ)
containers: - image: httpd name: httpd env: - name: PICKUPED_CONFIGMAP_KEYVAL valueFrom: configMapKeyRef: name: configmap-key-value key: SAMPLE_EDITOR
全体はこんな感じ
(参考) ConfigMapを使わない環境変数定義
Deploymentの場合はこんな感じ。
spec: containers: - image: httpd name: httpd env: - name: REMOTE_SERVER value: "10.0.0.2" - name: REMOTE_PORT value: "80"
注意点として、前述のYAMLでConfigMap作成時と同様に、環境変数で指定する値は全てYAML的には文字列である必要があるため、ポート番号のような値もYAMLでは文字列として記述しなければならないのでクォートで囲む必要がある。
上の定義でREMOTE_PORT
の値の80
でクォートが無いとエラーになる。
[zaki@cloud-dev deploy-env (master)]$ kubectl apply -f sample-http.yaml -n zzz Error from server (BadRequest): error when creating "sample-http.yaml": Deployment in version "v1" cannot be handled as a Deployment: v1.Deployment.Spec: v1.DeploymentSpec.Template: v1.PodTemplateSpec.Spec: v1.PodSpec.Containers: []v1.Container: v1.Container.Env: []v1.EnvVar: v1.EnvVar.Value: ReadString: expects " or n, but found 8, error found in #10 byte of ...|,"value":80}],"image|..., bigger context ...|value":"10.0.0.2"},{"name":"REMOTE_PORT","value":80}],"image":"httpd","name":"httpd"}]}}}} |...
ファイルシステムとしてマウント
前提としてConfigMapのデータをファイルシステムとしてマウントする場合はread onlyになる。
ボリュームやマウント関連の操作については基本的にはConfigMap特有の話ではなく、PersistentVolumeを使ったりする場合も同様。
また、ConfigMapのデータをPodからマウントしている状態で、ConfigMapのデータを更新した場合は、デフォルト60秒間隔で更新処理がKubernetesによって行われるため、Podの再作成無しにファイルの更新が反映される。
Mounted ConfigMaps are updated automatically
日本語ドキュメント マウントされたConfigMapは自動的に更新される
※ これはあくまでPod/コンテナにマウントされたファイルがConfigMapの更新によって動的に行われるのであって、コンテナ上で動いているプロセスが更新されたファイルを認識するかはプロセス次第。例えばApache Webサーバーなんかがhttpd.confの変更を再起動無しで認識するか?という話。
ただし、subPath
使用時にはこの動的反映は機能しない。(後述)
apiVersion: v1 data: sample1.txt: | nya-n wanwan sample2.txt: | this file is sample file. curry tabetai! kind: ConfigMap metadata: name: configmap-sample-data
例として上記のConfigMapがあるとして、、
ConfigMap内の全ファイルをマウント
上記ConfigMapの全データ(sample1.txt
とsample2.txt
の両方)をマウントするには、例えばDeploymentの定義であれば、
spec: containers: - image: httpd name: httpd volumeMounts: - name: configmap-volume mountPath: /var/tmp/configmap volumes: - name: configmap-volume configMap: name: configmap-sample-data
containersの定義でマウントするパスとボリューム設定名を記述。
volumesの定義で↑で使用するボリューム設定の実態として対象ConfigMapの名前(上記のconfigmap-sample-data
)を指定する。
[zaki@cloud-dev configmap (master)]$ kubectl exec -it -n cm-mount cm-mount-app-6474cfd495-cw6lj -c httpd -- bash root@cm-mount-app-6474cfd495-cw6lj:/usr/local/apache2# ls /var/tmp/configmap/ sample1.txt sample2.txt root@cm-mount-app-6474cfd495-cw6lj:/usr/local/apache2# cat /var/tmp/configmap/sample1.txt nya-n wanwan root@cm-mount-app-6474cfd495-cw6lj:/usr/local/apache2# cat /var/tmp/configmap/sample2.txt this file is sample file. curry tabetai!
この通り、sample1.txt
, sample2.txt
共にmountPath
に指定したディレクトリにConfigMapのデータがファイルシステムとしてマウントされることで参照できる。
ConfigMapの指定ファイルのみマウント
同じConfigMapのうち、sample1.txt
だけを参照したい場合(sample2.txt
は参照させない場合)は、volumes定義部分でitems
を使ってキーを指定する。
volumes: - name: configmap-volume1 configMap: name: configmap-sample-data items: - key: sample1.txt path: data1
※ container側は変更無し。
spec: containers: - image: httpd name: httpd volumeMounts: - name: configmap-volume1 mountPath: /var/tmp/configmap
この設定でデプロイすると、以下のように、「configmap-sample-data
リソース内のsample1.txt
キーのデータをdata1
というファイル名でマウント」という動きになる。
環境変数で指定キーのみの場合と同じように、ConfigMapにおけるキー名がそのままファイル名とはならない動作となる。(もちろんpath
にキー名と同じ文字列を指定すればConfigMap定義上のファイル名でマウントできる)
[zaki@cloud-dev configmap (master)]$ kubectl exec -it -n cm-mount file-mount-9c8d8f9df-twd9l -c httpd -- bash root@file-mount-9c8d8f9df-twd9l:/usr/local/apache2# ls /var/tmp/configmap/ data1 root@file-mount-9c8d8f9df-twd9l:/usr/local/apache2# cat /var/tmp/configmap/data1 nya-n wanwan
subPathを使ったマウント
通常のボリュームマウントでは、対象のルートディレクトリをmountPath
のパスにマウントする。なので対象ストレージの全体がマウントされる。
ストレージの全体は不要で、サブディレクトリ以下だけが欲しい場合はsubPath
を使うことで、サブディレクトリ以下をマウントすることもできる。
ConfigMapの場合もこの機能を使うことができ、でもConfigMapではディレクトリの概念がないため、「マウントポイントにファイルをマウント」という動作になる。
文書だとよくわからないので実際に(比較のために1Pod複数コンテナ構成で)やってみると、
spec: containers: - image: httpd name: httpd volumeMounts: - name: configmap-volume mountPath: /var/tmp/configmap/nyan subPath: sample1.txt - image: centos:7 name: centos7 command: [ "tail", "-f", "/dev/null"] volumeMounts: - name: configmap-volume mountPath: /tmp/configmap-file/wan subPath: sample1.txt volumes: - name: configmap-volume configMap: name: configmap-sample-data
containers.[]
のvolumeMounts
定義にsubPath:
でパスを指定。このパスというのはボリューム内のパスを指定するが、ConfigMapではファイルしかないのでConfigMap内のキー(つまりファイル名)指定となっている。
この設定でどうなるかというと、sample1.txt
のファイルの内容がhttpd
コンテナ内では/var/tmp/configmap/nyan
ファイルに、centos7
コンテナ内では/tmp/configmap-file/wan
ファイルにマウントされるという動作になる。
[zaki@cloud-dev configmap (master)]$ kc exec -it -n cm-mount cm-mount-subpath-64fd77d994-czddj -c httpd -- bash root@cm-mount-subpath-64fd77d994-czddj:/usr/local/apache2# cat /var/tmp/configmap/nyan nya-n wanwan
[zaki@cloud-dev configmap (master)]$ kc exec -it -n cm-mount cm-mount-subpath-64fd77d994-czddj -c centos7 -- bash [root@cm-mount-subpath-64fd77d994-czddj /]# cat /tmp/configmap-file/wan nya-n wanwan
subPath
指定時の動作として、ConfigMapの内容が更新されてもコンテナ内には反映されないので注意。
ストレージ上に/path/to/file
という構成のファイルがあったとすると、mountPath
で/var/tmp/hoge
を指定すると、コンテナ内では/var/tmp/hoge/path/to/file
というディレクトリ構成になる、というのが通常の使い方。
subPath
の本来の使い方としては、要件として/path/to
というディレクトリが不要でfile
だけを参照したい場合(任意のパスにfile
を置きたい場合)に、subPath: path/to
を記述することで、コンテナ内で/var/tmp/hoge/file
というパスで参照できるようになる、というもの。
一つのConfigMapデータに対してコンテナ毎にファイル名を変更して参照したいのであれば、記述量は増えるがitems
を使って別々のpath
によるファイル名設定を行い、それぞれのボリューム設定をマウントする方が(ConfigMap更新によるファイル変更を検知できるという点では)良い。
逆にデプロイ時のConfigMapの内容から不用意に変更されたくないような使い方をしたい場合は有効。
volumes: - name: configmap-volume1 # "wann"というファイル名を使いたいコンテナはこれを使う configMap: name: configmap-sample-data items: - key: sample1.txt path: wann - name: configmap-volume2 # "nyan"というファイル名を使いたいコンテナはこれを使う configMap: name: configmap-sample-data items: - key: sample1.txt path: nyan
なお、値を不変にしたいという目的であれば、Kubernetes 1.19時点ではbetaの「Immutable ConfigMaps」機能もある。(動作未検証)
そういえば--dry-run
じゃなくて--dry-run=client
って書かないといけなかったのか。忘れてた。
環境
[zaki@cloud-dev configmap (master)]$ kubectl version --short Client Version: v1.20.1 Server Version: v1.19.4
関連ドキュメント
(2022.12.08追記) Secretについても以下で少し作成