ConfigMapを使って任意のファイルをpod内に生成する

(2020/10/30作成)
# はじめに
最近kubernetesを触り始めて、kustomizeでpodを立てることを学んでいる。
その中でConfigMapを作ってpod内にファイル生成をする方法が何となく理解できたので、アウトプットしてみた。

大体のことは[公式ドキュメント](https://kubernetes.io/ja/docs/concepts/configuration/configmap/)に書いてあるのでそちらを参照されたし

### ConfigMapとは
- 設定情報などのKey-Vlaueで保持できるデータを保存しておくリソース
- podに置きたいファイル、設定したい環境変数などをマニフェストとして持つことができる
- パスワードなど、暗号化したい情報は`Secret`を使う、という使い分けがある

## 環境
kubernetes v1.18.1

# やりたいこと
- k8sでpodを立てるときに、pod内の特定のvolumeパスに任意のファイルを生成したい

## 手順
1. 生成したいファイルをConfigMap化する（ConfigMapGenerator）
2. pod内のvolume pathを定義する（volumeMounts）
3. 2で定義したパスに対してどのようなファイルを生成するかを記述する（volumes）
4. `kustomize build`コマンドを実行する
5. applyする

# 例
- pod内の`/hoge/fuga`配下にA.txtを配置する。
- A.txtは手元のファイルを元に作成。

# 概要図
![configmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103477/4c4a063a-d92a-345e-6382-5359b42ed137.png)

※比較のためにB.txtを書いているが以下の詳細ではB.txtの作成は省略する

# ディレクトリ構成
```tree
.
├── kustomization.yml
├── deployment.yml
└── A.txt
```

# ConfigMapGeneratorを書く
- ConfigMapGeneratorを利用する利点としては以下
    - ConfigMapのyamlファイルを自分で作成する必要がない
    - 元ファイルとマニフェストを分離できる<br>（Aファイルをpodに置きたいと思ったらAファイルを用意すればいい）

逆に言えば、ConfigMapGeneratorを利用しないでも、自分で`kind: ConfigMap`のyamlを用意して、その中のValueとして配置したいファイルの中身が書いてあればよい  
-> [別でConfigMapのyamlを用意する場合](https://qiita.com/shu-suke/items/517b9ecca8b1d5283124#%E5%88%A5%E3%81%A7configmap%E3%81%AEyaml%E3%82%92%E7%94%A8%E6%84%8F%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88)

- 今回の例の場合A.txtを元にpod内に同じA.txtを配置したいので以下となる。

```kustomization.yml
resources:
- deployment.yml

configMapGenerator:
- name: ConfigMapA  #作成されるConfigMapの識別名
  files: 
  - A.txt  #元となるファイルを記載
```

```A.txt
aaa
bb
cccc
```

- これに`kusomize build`コマンドを実行することにより以下のようなマニフェストが作成される

```yaml
<省略>
data:
  A.txt: |-  # ファイル名が"key"に、中身が"Value"になる
    aaa
    bb
    cccc
kind: ConfigMap
metadata:
  name: ConfigMapA-<乱数> #なぜか最後に乱数が入る
<省略>
```

# pod内のvolume pathを定義する（volumeMounts）
- `deployment.yml`で`.spec.containers[].volumeMounts[]`を記述。
- 今回のファイル作成先となる`/hoge/fuga`を定義する。

```deployment.yml
kind: Deployment
<省略>
    spec:
    containers:
    - name: sample
        image: sample-image
        volumeMounts:
        - name: path-a  #Volumeパスの識別名
        mountPath: "/hoge/fuga"  #デフォルトで無ければパスが作成される
```

# 定義したパスに対してどのようなファイルを生成するかを記述する（volumes）
- ConfigMapGeneratorで作成されるConfigMapAを用いる
- ConfigMapA内のどの箇所(key)を使って、何という名前(path)のファイルを生成するかを書く

```deployment.yml
kind: Deployment
<省略>
    spec:
    containers:
    <省略>
        volumes:
            - name: path-a  #上でマウントしたVolumeパスを指定
            configMap:  #ConfigMapを元にファイルを作成することを宣言
                name: ConfigMapA  #ConfigMapを識別
                items:
                - key: A.txt #ConfigMapAの中の"key"を指定
                  path: A.txt #pod内に作成するファイル名を記載
```

# `kustomize build`コマンドを実行する
- ConfigMapとdeployment.ymlが合わさったマニフェストが作成される。
- 作成されたConfigMapのnameは、[上で書いたように](https://qiita.com/drafts/517b9ecca8b1d5283124/edit#configmapgenerator%E3%82%92%E6%9B%B8%E3%81%8F)指定した`ConfigMapA`ではなく`ConfigMapA-<乱数>`となるが、Volumesでの指定も勝手に書き換えてくれるのでOK

```bash
kustomize build . > kustomize-deployment.yml
```

# applyする

```bash
kubectl apply -f kustomize-deployment.yml
```

- podが立ち上がったら

```bash
kubectl exec -it <pod名> /bin/bash
```
などでpod内に想定通りファイルがあるか確認してみてください。

# おまけ

## 別でConfigMapのyamlを用意する場合
- `kind: ConfigMap`のyamlを書くだけ
- ファイルを元にConfigMapを作成するのはコマンドでもできる
    - `metadata.name`はConfigMapの識別名となる。（マニフェスト内で指定されるのはこっち。ConfigMapのファイル名は何でもいいし使われない）

```bash
kubectl create configmap --dry-run=client <metadata.name> --from-file=<file> -o yaml > <hoge>.yml
```

## patchファイルを用いる場合のvolumes
- いわゆる以下のような構成で、素のdeploymentを用意して、patchを当ててkustomizeを管理する場合

```tree
.
├── base
│   ├── kustomization.yml
│   └── deployment.yml
└── overlays
    └── prod
        ├── kustomization.yml
        ├── patch-deployment.yml
        └── A.txt
```

- `deployment.yml`で先にディレクトリを定義をしたければ、下記のように空のディレクトリを宣言し、

```base/deployment.yml
      volumes:        
        - name: path-a
          emptyDir: {}
```
- `patch-deployment.yml`側でnullであることを改めて宣言し直さなければいけない

```overlays/patch-deployment.yml
      volumes:
        - name: path-a
          emptyDir: null
          configMap:
            name: ConfigMapA
            items:
              - key:
                path:
```

- patchの方でディレクトリパスを定義すればこんなことにはならなそうですが