petitviolet blog

    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