[Kubernetes]ConfigMapの作成方法と使用方法を確認する

#はじめに
今回はConfigMapの作成方法と使用方法を確認したいと思います。
ConfigMapは設定情報を保存するリソースです。Secretと似ていますが、Secretは機密情報を扱うのに対して、ConfigMapは機密ではない設定情報を扱います。

#ConfigMapの作成
Secretと同様の方法でConfigMapも作成できます。作成方法にはいくつかありますので、それぞれ試してみたいと思います。

##--from-file
Secretでは1つのKey（ファイル）に1つのValueを指定しましたが、ConfigMapでは1つのKey（ファイル）に複数のValueを指定できます。

```redis.conf
maxmemory=2mb
maxmemory-policy=allkeys-lru
```
このコンフィグファイルからConfigMapを作成します。

```
$ kubectl create configmap --save-config sample-configmap1 --from-file=./redis.conf
configmap/sample-configmap1 created
$ kubectl get configmaps
NAME                DATA   AGE
sample-configmap1   1      11s
$ kubectl describe configmaps sample-configmap1
Name:         sample-configmap1
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"sample-configmap1","creationTimestamp":null},"data":{"redis.conf":"maxmemory=2mb...

Data
====
redis.conf:
----
maxmemory=2mb
maxmemory-policy=allkeys-lru

Events:  <none
```
##--from-env-file
今度は同じredis.confをenvfileとして使用します。

```
$ kubectl create configmap sample-configmap2 --from-env-file=redis.conf
configmap/sample-configmap2 created
$ kubectl describe configmaps sample-configmap2
Name:         sample-configmap2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
maxmemory:
----
2mb
maxmemory-policy:
----
allkeys-lru
Events:  <none>
```

同じredis.confからConfigMapを作成しましたが、--from-fileでは1つのKey（redis.conf）に対して、2つのValue（maxmemory=2mb, maxmemory-policy=allkeys-lru）が設定されています。
対して、--from-env-fileでは、それぞれKey（maxmemory, maxmemory-policy）とValue（2mb, allkeys-lru）が1対1で設定されています。


##--from-literal
今度は各KeyとValueを直接指定して作成します。

```
$ kubectl create configmap --save-config sample-configmap3 --from-literal=maxmemory=2mb --from-literal=maxmemory-policy=allkeys-lru
configmap/sample-configmap3 created
```
```
$ kubectl describe configmaps sample-configmap3
Name:         sample-configmap3
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"sample-configmap3","creationTimestamp":null},"data":{"maxmemory":"2mb","maxmemor...

Data
====
maxmemory-policy:
----
allkeys-lru
maxmemory:
----
2mb
Events:  <none>
```
順番が異なりますが、--from-env-fileと同様にKeyとValueが1対1の関係ですね。


##マニフェストから作成する
最後にマニフェストから作成してみたいと思います。

```configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap4
data:
  maxmemory: 2mb
  maxmemory-policy: allkeys-lru
```
このマニフェストをapplyします。

```
$ kubectl apply -f configmap.yaml
configmap/sample-configmap4 created
$kubectl describe configmaps sample-configmap4
Name:         sample-configmap4
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"maxmemory":"2mb","maxmemory-policy":"allkeys-lru"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"sam...

Data
====
maxmemory:
----
2mb
maxmemory-policy:
----
allkeys-lru
Events:  <none>
```

この場合も--from-env-fileと同様にKeyとValueが1対1の関係ですね。

#ConfigMapの使用
作成したConfigMapの使用方法を確認していきます。こちらもSecretと同様にいくつか方法がありますので、それぞれ確認したいと思います。

##環境変数として特定のKeyを使用する。
同じredis.confから2通りのConfigMapができましたので、それぞれ確認したいと思います。

###KeyとValueが1対n
まずは--from-fileで作成したConfigMapです。このConfigMapは1つのKeyに2つのValueが設定されています。

以下のマニフェストを作成しました。

```redis1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis1
spec:
  containers:
  - name: redis1
    image: redis:latest
    env:
      - name: redis_conf
        valueFrom:
          configMapKeyRef:
            name: sample-configmap1
            key: redis.conf
```

このマニフェストをapplyして、設定されている環境変数を確認します。

```
$ kubectl apply -f redis1.yaml
pod/redis1 created
$ kubectl exec -it redis1 /bin/bash
root@redis1:/data# printenv | grep maxmemory
redis_conf=maxmemory=2mb
maxmemory-policy=allkeys-lru
root@redis1:/data# echo $maxmemory

root@redis1:/data# echo $maxmemory-policy
-policy
root@redis1:/data# echo $redis_conf
maxmemory=2mb maxmemory-policy=allkeys-lru
```
環境変数には設定されていますが、echoでそれぞれ確認してみると、何と言うか変ですね。
使えるのかな？これ・・

###KeyとValueが1対1
今度は--from-env-fileで作成したConfigMapです。このConfigMapはKeyとValueが1対1で設定されています。

以下のマニフェストを作成しました。
2つのKey-Valueのうち、maxmemoryのみを設定してみます。

```redis2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis2
spec:
  containers:
  - name: redis2
    image: redis:latest
    env:
      - name: MAX_MEMORY
        valueFrom:
          configMapKeyRef:
            name: sample-configmap2
            key: maxmemory
```

このマニフェストをapplyして、設定されている環境変数を確認します。

```
$ kubectl apply -f redis2.yaml
pod/redis2 created
$ kubectl exec -it redis2 /bin/bash
root@redis2:/data# printenv | grep MAX
MAX_MEMORY=2mb
root@redis2:/data# echo $MAX_MEMORY
2mb
```

今度は想定通りに設定されていますね。

##環境変数として全てのKeyを使用する
envFrom配下にConfigMapのみを指定して、全てのKeyを使用します。

まずは、KeyとValueが1対nのConfigMapから確認してみます。
以下のマニフェストをapplyして確認します。

```redis3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis3
spec:
  containers:
  - name: redis3
    image: redis:latest
    envFrom:
    - configMapRef:
        name: sample-configmap1
```

```
$ kubectl apply -f redis3.yaml
pod/redis3 created
$ kubectl exec -it redis3 /bin/bash
# printenv
redis.conf=maxmemory=2mb
maxmemory-policy=allkeys-lru
・・・
root@redis3:/data# echo $maxmemory

root@redis3:/data# echo $maxmemory-policy
-policy
root@redis3:/data# echo $redis.conf
.conf
```
やっぱり変ですね。

------

次にKeyとValueが1対1のConfigMapを確認します。
以下のマニフェストをapplyして確認します。

```redis4.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis4
spec:
  containers:
  - name: redis4
    image: redis:latest
    envFrom:
    - configMapRef:
        name: sample-configmap2
```

```
$ kubectl apply -f redis4.yaml
pod/redis4 created
$ kubectl exec -it redis4 /bin/bash
root@redis4:/data# printenv
maxmemory-policy=allkeys-lru
・・・
HOSTNAME=redis4
・・・
root@redis4:/data# echo $maxmemory-policy
2mb-policy
root@redis4:/data# echo $maxmemory
2mb
```
printenvでは設定されているように見えますが、echoで確認するとmaxmemory-policyの方が変ですね。
どうも、環境変数名に「.」「-」「改行」が含まれていると、想定通りに参照できないようです。

ConfigMapを作成する際に、これらを含まないようにするか、後述のVolumeとしてマウントする方法で使用した方がよいようです。

##Volumeとしてマウントする
Secretと同様にConfigMapもVolumeとしてマウントできます。この動作も確認してみます。

###特定のKeyのみマウントする

####KeyとValueが1対n
KeyとValueが1対nのConfigMapの動作を確認します。

以下のマニフェストをapplyして確認します。
mountPathにコンテナのマウントパスを指定して、pathにはマウントしたあとのファイル名を指定します。

```redis5.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis5
spec:
  containers:
    - name: redis5
      image: redis:latest
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: sample-configmap1
        items:
        - key: redis.conf
          path: redis.conf
```

```
$ kubectl apply -f redis5.yaml
pod/redis5 created
$ kubectl exec -it redis5 /bin/bash
root@redis5:/data# cd /etc/config/
root@redis5:/etc/config# ls
redis.conf
root@redis5:/etc/config# cat redis.conf
maxmemory=2mb
maxmemory-policy=allkeys-lru
```
ちゃんと設定されていますね。

####KeyとValueが1対1
次にKeyとValueが1対1のConfigMapで特定のKeyのみマウントしてみます。
ここでは、maxmemoryのみをマウントします。

```redis6.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis6
spec:
  containers:
    - name: redis6
      image: redis:latest
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: sample-configmap2
        items:
        - key: maxmemory
          path: redis_maxmemory
```

このマニフェストをapplyして確認します。

```
$ kubectl apply -f redis6.yaml
pod/redis6 created
$ kubectl exec -it redis6 cat /etc/config/redis_maxmemory
2mb
```
設定されていますね。
ただ、Redisについて詳しくはないのですが、この設定でRedisのパラメータとして使えるのかは怪しいです。


###全てのKeyをマウントする
マニフェストでConfigMapのみを指定して、全てのKeyをマウントします。
KeyとValueが1対n, 1対1それぞれのConfigMapを別々にマウントして動作を確認してみたいと思います。

```redis7.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis7
spec:
  containers:
    - name: redis7
      image: redis:latest
      volumeMounts:
      - name: config-volume1
        mountPath: /etc/config1
      - name: config-volume2
        mountPath: /etc/config2
  volumes:
    - name: config-volume1
      configMap:
        name: sample-configmap1
    - name: config-volume2
      configMap:
        name: sample-configmap2
```
このマニフェストをapplyして確認します。

```
$ kubectl apply -f redis7.yaml
pod/redis7 created
$ kubectl exec -it redis7 /bin/bash
root@redis7:/etc# cd /etc/config1
root@redis7:/etc/config1# ls
redis.conf
# cat redis.conf
maxmemory=2mb
maxmemory-policy=allkeys-lru
# cd ../config2
root@redis7:/etc/config2# ls
maxmemory  maxmemory-policy
root@redis7:/etc/config2# cat maxmemory
2mb
root@redis7:/etc/config2# cat maxmemory-policy
allkeys-lru
```
1対nの方は1つのKeyがファイル名となり、その中に複数の値が記載されていますね。
1対1の方は複数のKeyがそれぞれ一つのファイルになっていて、その中に各値が記載されています。

#まとめ
Secretと同じ要領だから簡単にできるだろうなと思ってましたが、思いかけず苦戦しました。やはりやってみないとわからないことが多いです。

同じ設定情報でもConfigMapの作り方、使い方でコンテナでの見え方が異なることが確認できました。利用するコンテナイメージに合わせて作り方、使い方を変える必要がありますね。