今回は Docker コンテナを起動するタイミングで、コンテナの動作に必要な設定を受け渡す方法について書く。
やり方としては、大まかに分けて「環境変数を通して渡す」と「コマンドライン引数を通して渡す」という二つがある。
どちらの場合も docker run
で実行するコマンドの中に設定を含めることになる。
使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.12.6 BuildVersion: 16G1212 $ docker version Client: Version: 18.01.0-ce API version: 1.35 Go version: go1.9.2 Git commit: 03596f5 Built: unknown-buildtime OS/Arch: darwin/amd64 Experimental: false Orchestrator: swarm Server: Engine: Version: 18.01.0-ce API version: 1.35 (minimum version 1.12) Go version: go1.9.2 Git commit: 03596f5 Built: Wed Jan 10 20:13:12 2018 OS/Arch: linux/amd64 Experimental: false
環境変数を通して渡す
まずは環境変数を通して渡す一般的なやり方から。
最初は動作確認のために、起動時に環境変数の一覧を表示する Docker イメージを作ることにする。 その Dockerfile が次の通り。
$ cat << 'EOF' > Dockerfile FROM alpine CMD env EOF
Alpine Linux をベースイメージにして、起動時に実行するコマンドを CMD
命令で指定している。
env
コマンドは環境変数を一覧で表示する。
これ以上ないくらいシンプル。
上記の Docker ファイルをビルドして Docker イメージを作る。
$ docker build -t example/env . ... Successfully tagged example/env:latest
上記でビルドした Docker イメージからコンテナを起動してみよう。 すると、コンテナ内で設定されている環境変数が出力される。
$ docker run -t example/env HOSTNAME=4df5d62c61a1 SHLVL=1 HOME=/root TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
続いてコンテナに環境変数を設定してみる。
これには docker run
コマンドで -e (--env)
オプションを指定する。
例えば、よくありがちなバインドするアドレスやポートっぽい値を設定してみよう。
$ docker run -e BIND_ADDRESS=127.0.0.1 -e BIND_PORT=8080 -t example/env BIND_ADDRESS=127.0.0.1 HOSTNAME=2fb165c97c2a SHLVL=1 HOME=/root BIND_PORT=8080 TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
ちゃんと環境変数に BIND_ADDRESS
と BIND_PORT
が設定されたことが分かる。
ちなみに、環境変数はファイル経由で渡すこともできる。 渡す変数の数が多いときは、こちらを使った方が良い。
まずは環境変数を羅列したファイルを用意する。
$ cat << 'EOF' > envfile.txt BIND_ADDRESS=127.0.0.1 BIND_PORT=8080 EOF
あとはコンテナを起動するときに --env-file
オプションでファイルを指定する。
$ docker run --env-file envfile.txt -t example/env HOSTNAME=4ed1b4a9a45c BIND_ADDRESS=127.0.0.1 SHLVL=1 BIND_PORT=8080 HOME=/root TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
デフォルト値を設定する (Dockerfile)
上記でアプリケーションの設定として環境変数を使う下地が整った。 ただ、設定には一般的にデフォルト値がほしくなる。
そんなときは Dockerfile で ENV
命令を使うことができる。
先ほどの Dockerfile に ENV
命令を加えたものを用意しよう。
$ cat << 'EOF' > Dockerfile FROM alpine ENV BIND_ADDRESS 127.0.0.1 ENV BIND_PORT 8080 CMD env EOF
上記のファイルをビルドする。
$ docker build -t example/env . ... Successfully tagged example/env:latest
ビルドしたイメージからコンテナを起動してみよう。
特に -e (--env)
オプションを使わなくても環境変数が出力されていることが分かる。
$ docker run -t example/env BIND_ADDRESS=127.0.0.1 HOSTNAME=4c795ff84a32 SHLVL=1 HOME=/root BIND_PORT=8080 TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
上記の値は -e (--env)
オプションを指定することで上書きできる。
$ docker run -e BIND_ADDRESS=0.0.0.0 -e BIND_PORT=80 -t example/env BIND_ADDRESS=0.0.0.0 HOSTNAME=de360066a866 SHLVL=1 HOME=/root BIND_PORT=80 TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
デフォルト値を設定する (シェルスクリプト)
環境変数のデフォルト値を設定するには Dockerfile で ENV
命令を使う以外のやり方もある。
具体的には、コンテナが起動するタイミングでシェルスクリプトを実行して、その中で環境変数を操作する。
以下の Dockerfile では docker-entrypoint.sh
というファイルをイメージに転送している。
そして ENTRYPOINT
命令を使うことで、コンテナの起動時にそのシェルスクリプトを実行するように設定されている。
$ cat << 'EOF' > Dockerfile FROM alpine COPY docker-entrypoint.sh /usr/local/bin ENTRYPOINT ["docker-entrypoint.sh"] EOF
続いて、上記の Dockerfile で使っている docker-entrypoint.sh
を用意する。
やっていることは単純で、環境変数がないときはデフォルト値を扱うように ${環境変数名:-デフォルト値}
という記法を使うだけ。
$ cat << 'EOF' > docker-entrypoint.sh #!/bin/sh echo ${BIND_ADDRESS:-127.0.0.1} echo ${BIND_PORT:-8080} EOF $ chmod +x docker-entrypoint.sh
上記で用意したファイル群から Docker イメージをビルドする。
$ docker build -t example/env . ... Successfully tagged example/env:latest
イメージからコンテナを起動する。
特にオプションを指定のないときはシェルスクリプトで指定したデフォルト値が使われる。
また、先ほどと同じように -e (--env)
オプションを指定することで値を上書きできる。
$ docker run -t example/env 127.0.0.1 8080 $ docker run -e BIND_ADDRESS=0.0.0.0 -e BIND_PORT=80 -t example/env 0.0.0.0 80
もちろんシェルスクリプトの中では受け渡された環境変数の内容をバリデーションしたりもできる。
コマンドライン引数を通して渡す
続いてはもう一つのやり方、コマンドライン引数を使う方法について。 このやり方は、基本的には前述したシェルスクリプトを使う方法の応用になっている。
まずは、先ほどと同じように起動時にシェルスクリプトを実行するような Docker ファイルを用意する。
ここでシェルスクリプトを実行するのに ENTRYPOINT
命令を使っているのがポイントになる。
これが CMD
命令だと上手くいかない。
$ cat << 'EOF' > Dockerfile FROM alpine COPY docker-entrypoint.sh /usr/local/bin ENTRYPOINT ["docker-entrypoint.sh"] EOF
実行されるシェルスクリプトは、全てのコマンドライン引数を参照できる $@
変数を echo
コマンドで出力する。
$ cat << 'EOF' > docker-entrypoint.sh #!/bin/sh echo $@ EOF $ chmod +x docker-entrypoint.sh
上記をビルドしよう。
$ docker build -t example/opt .
...
Successfully tagged example/opt:latest
上記のイメージからコンテナを起動するタイミングで、普段なら起動するコマンドを渡すところに適当な文字列を入れてみよう。
$ docker run -t example/opt foo bar baz foo bar baz
すると、入力した文字列がそのまま出力された。
これはシェルスクリプトがコマンドライン引数を出力するようにした echo $@
による結果となる。
つまり、コマンドライン引数をシェルスクリプトに渡すことができたというわけ。
コマンドライン引数を解析する (getopts)
シェルスクリプトにコマンドライン引数さえ渡せてしまえば、あとはどうとでもなる。
一例として、ここでは getopts
を使って引数を解析してみることにした。
起動するシェルスクリプトで getopts
を使って受け取った引数を解析する。
そして、最終的には解析した変数を出力している。
ここでは -a
オプションで渡した値が BIND_ADDRESS
に、-p
オプションで渡したあたいが BIND_PORT
に格納される。
$ cat << 'EOF' > docker-entrypoint.sh #!/bin/sh usage() { echo "Usage: $0 [-a bind-address] [-p bind-port]" 1>&2 exit 1 } while getopts a:p:h OPT do case $OPT in a) BIND_ADDRESS=$OPTARG ;; p) BIND_PORT=$OPTARG ;; h) usage ;; esac done echo ${BIND_ADDRESS:-127.0.0.1} echo ${BIND_PORT:-8080} EOF $ chmod +x docker-entrypoint.sh
上記を元にイメージをビルドしよう。
$ docker build -t example/opt .
...
Successfully tagged example/opt:latest
そしてイメージからコンテナを起動する。 特に何も指定しないときはデフォルト値が表示され、オプションをコマンドライン引数で指定したときはその値が表示される。
$ docker run -t example/opt 127.0.0.1 8080 $ docker run -t example/opt -a 0.0.0.0 -p 80 0.0.0.0 80
これだと、例えば -h
を渡したときは usage を表示して終了みたいなことも簡単にできる。
$ docker run -t example/opt -h
Usage: /usr/local/bin/docker-entrypoint.sh [-a bind-address] [-p bind-port]
ちなみに上記のやり方を取るとデバッグしたいときにどうするんだって話になる。
起動時のパラメータの最後に bin/bash
とか付けるだけではシェルスクリプトの起動が上書きできないので。
そんなときは --entrypoint
オプションを使えば ENTRYPOINT
命令の内容を上書きできる。
$ docker run --entrypoint sh -it example/opt / # uname -a Linux a6c3524f68a5 4.4.111-boot2docker #1 SMP Thu Jan 11 16:25:31 UTC 2018 x86_64 Linux
ばっちり。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る