blog.petitviolet.net

kubernetesで動かすソフトウェアの設定をConfigMapで記述する

2018-03-18

Qiitakuberneteskubectl

まとめ

nginx.conf などの設定ファイルを kubernetes の ConfigMap で記述し、Volume としてマウントすることが出来る。
ドキュメントはこの辺り。

実際の yaml ファイルはGistにある。

何が課題か

kubernetes で動かす Docker コンテナ内にどうやって各アプリケーションが使用する設定ファイルを差し込むか、という話。 例えば nginx.conf などの設定ファイルをどうやって管理するか。 いくつか方法がある。

  • Docker イメージの中に入れておく

    • ADDした状態でdocker buildしておく
  • ファイルにしておいてコンテナに Volume としてマウントする

    • デプロイするホストのディレクトリをマウントする
    • 永続ディスクを作成してそこに配置しておいてマウントする
  • どこかのストレージに置いておいてダウンロードする

あたりが一般的な気がする(要出典)。

しかし、それぞれ難点がある

  • Docker イメージの中に入れておく

    • 例えば Nginx の公式イメージをそのまま使えない
    • docker build, docker pushして使う必要があって面倒
  • ファイルにしておいてコンテナに Volume としてマウントする

    • ファイルを置く Node の状態を管理しないといけない
    • 設定を変更するたびにストレージを変更するのは面倒
  • どこかのストレージに置いておいてダウンロードする

    • 権限とか考えないといけなくて面倒

と、どれを選んでも一長一短という感じ。

そこで ConfigMap

kubernetes には ConfigMap というものがあり、簡単にいうと key-value で値を持てるもの。 環境変数にイメージは近いが、上に書いたような設定ファイルも持つことが出来る。 さらに、ConfigMap は volume としてもマウントできるようになっているのがポイント。
ドキュメント

設定ファイルを ConfigMap で定義する

yaml では改行を含む文字列を定義できる。 YAML の基本について - TASK NOTES

pipe(|)を使うと改行を含んでいても一つのスカラ値として扱うことが出来る。 こんな感じ。

message: |
  hello
  world

|+とか|-とか>もあって少しずつ違うが|で大体は問題ないはず。

/etc/nginx/nginx.conf と/etc/nginx/virtualhost/virtualhost.conf を ConfigMap で定義してみる。 data項目の下に、nginx.confvirtualhost.confとしてそれぞれ記述する。

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  nginx.conf: |
    user nginx;
    worker_processes  3;
    error_log  /var/log/nginx/error.log;
    events {
      worker_connections  10240;
    }
    http {
      log_format  main
              'remote_addr:$remote_addr\t'
              'time_local:$time_local\t'
              'method:$request_method\t'
              'uri:$request_uri\t'
              'host:$host\t'
              'status:$status\t'
              'bytes_sent:$body_bytes_sent\t'
              'referer:$http_referer\t'
              'useragent:$http_user_agent\t'
              'forwardedfor:$http_x_forwarded_for\t'
              'request_time:$request_time';

      access_log	/var/log/nginx/access.log main;

      server {
          listen       80;
          server_name  _;

          location / {
              root   html;
              index  index.html index.htm;
          }
      }
      include /etc/nginx/virtualhost/virtualhost.conf;
    }
  virtualhost.conf: |
    upstream app {
      server localhost:8080; # localhost:8080で受け付けるWebアプリがあるとして
      keepalive 1024;
    }

    server {
      listen 80 default_server;
      server_name _;
      root /usr/local/app;

      access_log /var/log/nginx/app.access_log main;
      error_log /var/log/nginx/app.error_log;

      location / {
        proxy_pass http://app/;
        proxy_http_version 1.1;
      }
    }

こうやって定義した CofigMap を公式の nginx イメージに適用してみる。

---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /etc/nginx # /etc/nginxにvolumesのnginx-confをmountする
              readOnly: true
              name: nginx-conf
            - mountPath: /var/log/nginx
              name: log
      volumes:
        - name: nginx-conf # volumeMountsで/etc/nginxにmountするやつ
          configMap:
            name: nginx-conf # ConfigMapのnginx-confを/etc/nginx以下に配置する
            items:
              - key: nginx.conf # nginx-confのkey
                path: nginx.conf # nginx.confというファイル名
              - key: virtualhost.conf
                path: virtualhost/virtualhost.conf # ディレクトリを掘ることも可能
        - name: log
          emptyDir: {}

---
apiVersion: v1
kind: Service # nginxにアクセスする用のservice
metadata:
  name: nginx
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: nginx

デプロイ,動作確認

実際に kubernetes にデプロイして、ConfigMap がファイルとして存在しているかどうかを確認してみる。

$ kubectl create namespace nginx-sample
namespace "nginx-sample" created

$ kubectl --namespace=nginx-sample apply -f ./nginx-sample.yaml
configmap "nginx-conf" created
deployment "nginx" created
service "nginx" created

$ kubectl --namespace=nginx-sample get po
NAME                    READY     STATUS    RESTARTS   AGE
nginx-d78988cbc-js2fx   1/1       Running   0          10s

ここまでで起動できたので、kubectl execでファイルを見てみると正しく配置されていることが分かる。

$ kubectl exec  --namespace=nginx-sample -it nginx-d78988cbc-js2fx -c nginx -- ls -lhR /etc/nginx/
/etc/nginx/:
total 4.0K
lrwxrwxrwx 1 root root   17 Mar 11 01:38 nginx.conf -> ..data/nginx.conf
drwxr-xr-x 2 root root 4.0K Mar 11 01:38 virtualhost

/etc/nginx/virtualhost:
total 0
lrwxrwxrwx 1 root root 38 Mar 11 01:38 virtualhost.conf -> ../..data/virtualhost/virtualhost.conf

続けて nginx.conf の設定が正しく反映されていることを確認してみる。

$ curl $(minikube service --namespace=nginx-sample nginx --url) -I # localhost:8080で動くサービスがないのでエラーになるけど気にしない
HTTP/1.1 502 Bad Gateway
Server: nginx/1.13.9
Date: Sun, 18 Mar 2018 08:07:08 GMT
Content-Type: text/html
Content-Length: 173
Connection: keep-alive

$ kubectl exec --namespace=nginx-sample -it nginx-d78988cbc-js2fx -- cat /var/log/nginx/app.access_log  # logの中見を見る
remote_addr:172.17.0.1  time_local:18/Mar/2018:08:07:08 +0000   method:HEAD     uri:/   host:192.168.99.100     status:502      bytes_sent:0    referer:-       useragent:curl/7.54.0     forwardedfor:-  request_time:0.000

log_formatで指定したようなログになっていることが確認できた。

from: https://qiita.com/petitviolet/items/ee4b1bdba2670a1d6a12