LoginSignup
181
137

More than 5 years have passed since last update.

envsubstを使ってDockerで設定ファイルに環境変数を埋め込めこむ汎用的なパターン

Last updated at Posted at 2017-02-03

はじめに

Docker使ってるとできるだけイメージは共通化して、設定ファイルはマウントで差し込み、環境ごとの設定差分は環境変数で埋め込む方向になってきます。
しかしながら、設定ファイルに環境変数を直接埋め込めるかは対象のソフトウェアの実装次第で、例えばfluentdは設定ファイルで環境変数を直接埋め込めるけど、nginxは環境変数を直接埋め込めなかったりします。

で、よくやるのは entrypoint.sh みたいなのを作って起動時にsedするという原始的な方法もあるけど、もうちょっとスマートな方法として、 envsubst という軽量なテンプレートエンジンを使うことで、設定ファイルに汎用的に環境変数を埋め込むことができて便利なので紹介したい。

インストール

nginx:alpineには既にenvsubstコマンド入ってるので、そのまま使える。

他のイメージで入ってなければ以下の方法でインストールできる。

alpine:3.5

以下で雑にインストールはできる。

$ apk --no-cache add gettext

もうちょっとサイズを切り詰めたい場合は、こんなかんじ。

FROM alpine:3.5

RUN apk --no-cache add libintl && \
      apk --no-cache add --virtual .gettext gettext && \
      cp /usr/bin/envsubst /usr/local/bin/envsubst && \
      apk del .gettext

サイズとしてはこれぐらいで、envsubstは賞味111KBぐらい。めっちゃ軽い。

$ docker build -t envsubst .
$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
envsubst                        latest              1bab5f1656d7        6 seconds ago       4.095 MB
alpine                          3.5                 88e169ea8f46        5 weeks ago         3.984 MB

debian:jessie

$ apt-get install gettext-base

使い方

簡単な例として以下のような設定ファイルがあったとして、

$ cat test.conf.template
hoge=$HOGE

こんなかんじで設定ファルをマウントしつつ、環境変数を差し込んで、envsubstに食わせると埋め込んでくれます。

$ docker run --rm \
    -v $(pwd)/test.conf.template:/tmp/test.conf.template \
    -e HOGE=aaa \
    nginx:alpine \
    /bin/sh -c "envsubst < /tmp/test.conf.template > /tmp/test.conf && cat /tmp/test.conf"
hoge=aaa

なんにでも使えそうですね。

ただ、nginx.confのように、設定ファイルの中で $ 記号が使える場合は、埋め込む環境変数名を明示する必要があります。

たとえばこんなかんじのnginx.confがあったとして ${NGINX_SERVER_NAME}, ${NGINX_UPSTREAM_HOST}, ${NGINX_UPSTREAM_PORT} は置換したいけど、 $remote_addr, $host とかは置換してほしくないみたいな。

nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';

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

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    resolver           127.0.0.11 valid=5s;

    server {
        listen 80;
        set_real_ip_from   '10.0.0.0/8';
        real_ip_header     X-Forwarded-For;
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-Proto https;

        server_name ${NGINX_SERVER_NAME};

        set $upstream ${NGINX_UPSTREAM_HOST};

        location / {
            proxy_pass http://$upstream:${NGINX_UPSTREAM_PORT};
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

この場合ははenvsubstに置換対象の環境変数名を指定します。
引数が長いのでdocker-compose.ymlにしてます。(2017/02/05: 改行のバックスラッシュいらないという指摘があったので修正)

docker-compose.yml
version: '2'
services:
  nginx:
    image: nginx:alpine
    command: >
      /bin/sh -c
      "envsubst '
      $$NGINX_SERVER_NAME
      $$NGINX_UPSTREAM_HOST
      $$NGINX_UPSTREAM_PORT
      '< /etc/nginx/nginx.conf.template
      > /etc/nginx/nginx.conf
      && nginx -g 'daemon off;'"
    volumes:
      - ./nginx.conf.template:/etc/nginx/nginx.conf.template
    ports:
      - 8080:80
    environment:
      NGINX_SERVER_NAME: "test.example.com"
      NGINX_UPSTREAM_HOST: "hoge"
      NGINX_UPSTREAM_PORT: "80"

起動して設定ファイルの中身を覗いてみます。

$ docker-compose up -d
Starting 20170204_nginx_1

$ docker exec -it $(docker ps -l -q) cat /etc/nginx/nginx.conf

ちゃんと指定したところだけ環境変数が埋め込まれてます。

nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
        worker_connections  1024;
}

http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

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

        sendfile        on;
        #tcp_nopush     on;

        keepalive_timeout  65;

        #gzip  on;

        resolver           127.0.0.11 valid=5s;

        server {
                listen 80;
                set_real_ip_from   '10.0.0.0/8';
                real_ip_header     X-Forwarded-For;
                proxy_set_header   Host $host;
                proxy_set_header   X-Forwarded-Proto https;

                server_name test.example.com;

                set $upstream hoge;

                location / {
                        proxy_pass http://$upstream:80;
                }
        }
        include /etc/nginx/conf.d/*.conf;
}

まとめ

envsubst使うとDockerで設定ファイルに環境変数を埋め込めこむ汎用的なパターンとしていろいろ便利そうです。

181
137
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
181
137