KubernetesのPodにConfigMapを複数読み込ませたり、複数のPodで同じConfogMapを読み込ませてみる

##これなに？

[Kubernetes](http://kubernetes.io/)でPodを２つデプロイした上で同じデータをConfigMapを使って動的に共有してみたり、複数のConfigMapを１つのPodに読み込ませたりします。
また、今回は[ConfigMapの公式ドキュメント](http://kubernetes.io/docs/user-guide/configmap/)だけでは理解しにくい同時にこれらを扱う使い方をRedisを使ったチュートリアル形式で紹介します。
※簡単に触るだけをしたい方は[こちらの記事](http://qiita.com/tkusumi/items/8e31fddda77f93ccfdd8)がオススメです

##今回使用した環境とあらかじめいるもの
- OSX El Capitan ver.10.11.6
- exec
- Vagrant
- VirtualBox
- CoreOS
- Kubernetes

**〜 Kubernetesの環境は構築済で進めます。構築の解説は[この記事](http://qiita.com/Clip-glass/items/1eb61f983a69f22ac8e3)を参考にしてください 〜**

##必要なファイルの準備

まず、下記の5つのファイルを作成して、同じフォルダにおいてください。
※yamlファイル以外の拡張子のないものは必ず拡張子なしで作成をしてください

**次の２つのファイルは今回使うRedisのPodの指定したい設定情報のみが書かれたConfigMapの元です**

```bash:redis-config1
maxmemory 2mb
maxmemory-policy allkeys-lru
```

```bash:redis-config2
maxmemory 4mb
maxmemory-policy allkeys-lru
```

**次のファイルは今回使う２つのPodで使う動的な共有データをyamlで書いたConfigMapの元です**

```yaml:redis-example.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-example
data:
  example.property.1: hello
  example.property.2: area
  example.property.3: niki’s
  example.property.4: world
  example.property.5: create
```

**次の２つのファイルは今回使う２つのRedisのPodの設定情報が書かれたものです**

```yaml:redis-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis1
spec:
  containers:
  - name: redis
    image: kubernetes/redis:v1
    env:
    - name: MASTER
      value: "true"
    ports:
    - containerPort: 6379
    resources:
      limits:
        cpu: "0.1"
    volumeMounts:
    - mountPath: /redis-master-data
      name: data
    - mountPath: /redis-master
      name: config
    - mountPath: /redis-cli
      name: redis-data
  volumes:
    - name: data
      emptyDir{}
    - name: config
      configMap:
        name: redis-config1
        items:
        - key: redis-config1
          path: redis.conf
    - name: redis-data
      configMap:
        name: redis-example
```

```yaml:redis-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis2
spec:
  containers:
  - name: redis
    image: kubernetes/redis:v1
    env:
    - name: MASTER
      value: "true"
    ports:
    - containerPort: 6379
    resources:
      limits:
        cpu: "0.1"
    volumeMounts:
    - mountPath: /redis-master-data
      name: data
    - mountPath: /redis-master
      name: config
    - mountPath: /redis-cli
      name: redis-data
  volumes:
    - name: data
      emptyDir{}
    - name: config
      configMap:
        name: redis-config2
        items:
        - key: redis-config2
          path: redis.conf
    - name: redis-data
      configMap:
        name: redis-example
```

作成できたら、Kubernetesを立ち上げて次へ進みましょう！

##ConfigMapを作成する

ConfigMapを作成する方法は下記の３パターンあります

- yamlファイルなどの設定ファイル直接記述して作る方法
  - ```
    kubectl create -f config.conf
    ```
方式

- 指定したい設定情報のみのファイルを記述して作る方法
  - ```
    kubectl create configmap --from-file
    ```
方式

- コマンドの引数に直接設定情報の引数を入れる方法
  - ```
    kubectl create configmap --from-literal
    ```
方式


**今回はyamlファイルを記述する方法と指定したい設定情報のみのファイルを記述する方法を使っていきます**

まず、指定したい設定情報のみのファイルからConfigMapを作ります。

```bash
$ kubectl create configmap redis-config1 --from-file=redis-config1
configmap "redis-config1" created
$ kubectl create configmap redis-config2 --from-file=redis-config2
configmap "redis-config2" created
```

次にyamlファイルを使って設定情報を直接記述する方法でConfigMapを作ります。

```bash
$ kubectl create -f redis-example.yaml
configmap "redis-example" created
```

正しく作成できたかどうかを確認してみましょう。

```bash
$ kubectl get configmap
NAME            DATA      AGE
redis-config1   1         6m
redis-config2   1         5m
redis-example   5         3m
```

##ConfigMapを用いてPodをデプロイしてみる

ConfigMapはbashコマンドを叩いてデプロイするときに環境変数に設定する方法とVolumeとしてマウントする方法があり、ここではVolumeを利用して異なる設定をしたPodを２つデプロイして、ファイルは共通のものを動的に利用することに挑戦します。

以下のコマンドでいっきに２つともPodをデプロイしちゃいましょう

```bash
$ kubectl create -f redis-pod1.yaml &&kubectl create -f redis-pod2.yaml
pod "redis1" created
pod "redis2" created
```

正しくPodがデプロイされたか確認してみましょう

```bash
$ kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
redis1    1/1       Running   0          1m
redis2    1/1       Running   0          1m
```

STATUSがRunningになっていたら準備は完了です。次へ進んで色々動かしてみましょう

##各Podが正しくConfigMap通り設定されているか確認する

まずは「redis1」という名前のPodに入って確認しみましょう

```bash
$ kubectl exec -it redis1 redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "2097152"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
127.0.0.1:6379> exit
```

次に「redis2」という名前のPodの中に入って確認してみましょう

```bash
$ kubectl exec -it redis2 redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "4194304"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
127.0.0.1:6379> exit
```

※IPアドレスがポートまで同じなのはそうなるようにyamlで書いてあるからなので、別々でもOKです

**今回はmaxmemoryが異なる設定にしたので、異なることが出力からわかるかと思います。**

次に同じ動的なデータをConfigMapから持ってこれていることを確認してみましょう

```bash
$ kubectl exec redis1 cat /redis-cli/example.property.1
hello
$ kubectl exec redis2 cat /redis-cli/example.property.1
hello
```

##ConfigMapで値を変更するとPod側の値も変わることを確認

　ConfigMapでVolumeの値を変えると即座にPod側にも反映されることを試してみましょう

```bash
$ kubectl edit configmap redis-example
```

標準だとviが立ち上がるので下記のように編集してみましょう

```vim
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  example.property.1: niki’s #Change
  example.property.2: area
  example.property.3: hello  #Change
  example.property.4: world
  example.property.5: create
kind: ConfigMap
metadata:
  creationTimestamp: 2016-08-23T04:27:36Z
  name: redis-example
  namespace: default
  resourceVersion: "93754"
  selfLink: /api/v1/namespaces/default/configmaps/redis-example
  uid: eb2a107c-68e9-11e6-96ee-080027e9ede8
```

escキーを押して```:wq```で変更を保存してViを終了させたら、変更が反映されているか確認してみましょう

```bash
$ kubectl exec redis1 cat /redis-cli/example.property.1
niki’s
$ kubectl exec redis2 cat /redis-cli/example.property.1
niki’s
```

ここで、もともとConfigMapを作るときに記述したファイルを確認してみましょう。

```bash
$ cat redis-example.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-example
data:
  example.property.1: hello
  example.property.2: area
  example.property.3: niki’s
  example.property.4: world
  example.property.5: create
```

ここからわかるように、もともとConfigMapを作成するために使用したファイルが書き換わるわけではなく、Kubernetes上のConfigMapが都度書き換わるという形のようです。また、同時に動的なデータを共有している仕組みについては[この記事](http://qiita.com/tkusumi/items/8e31fddda77f93ccfdd8#volume%E3%81%AE%E5%A0%B4%E5%90%88%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AF%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AA%E3%83%83%E3%82%AF%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B)が参考になります。

では、次は自分で実際に色々データを書き換えて出力をして試してみてください。（example.property.1~5までありますよ）

**遊び終えたら次のコマンドでもとどおりになります。お疲れさまでした！**

```bash
$ kubectl delete pod redis1 && kubectl delete pod redis2 && kubectl delete configmap redis-example && kubectl delete configmap redis-config2 && kubectl delete configmap redis-config1
pod "redis1" deleted
pod "redis2" deleted
configmap "redis-example" deleted
configmap "redis-config2" deleted
configmap "redis-config1" deleted
```

##参考文献
- [Kubernetes - Using ConfigMap](http://kubernetes.io/docs/user-guide/configmap/)
- [VagrantとCoreOSでkubernetesをMacで使ってみる　①環境構築編](http://qiita.com/Clip-glass/items/1eb61f983a69f22ac8e3)
- [KubernetesのConfigMapを試してみる](http://qiita.com/tkusumi/items/8e31fddda77f93ccfdd8)