Docker configs を利用した設定データの保存
読む時間の目安: 12 分
configs について
スウォームサービスでは configs が導入され、設定ファイルのようにそれほど重要ではない情報を、サービスイメージや稼働中のコンテナーの外部に保存できます。 これがあれば、ビルドイメージをできるだけ汎用的なものとして維持できます。 また設定ファイルをコンテナーにバインドマウントしたり、環境変数を利用したりすることも不要になります。
configs は secrets と同じように機能します。 ただし configs は保存の際に暗号化はされません。 またコンテナーのファイルシステム内に直接マウントされますが、RAM ディスクは消費しません。 configs はサービスに対して、どのタイミングであっても追加および削除ができます。 またサービス間で 1 つの config を共有することもできます。 さらに configs と環境変数や Docker labels を組み合わせて利用できるので、最大限に柔軟性を持たせることができます。 configs の値には、通常の文字列やバイナリ(500 KB まで)を指定します。
メモ: Docker configs はスウォームサービスにおいて利用可能であり、スタンドアロンのコンテナーでは利用できません。 この機能を利用するには、コンテナーをサービスとして稼動させ、スケールは 1 としてください。
configs は Linux と Windows においてサポートされます。
Windows サポート
Docker には Windows コンテナーに対する configs サポートが含まれます。 ただし実装には違いがあるため、以降の利用例において示しています。 重要な違いとして以下があることを覚えておいてください。
-
カスタムターゲットを利用する config ファイルは、Windows コンテナーに対して直接バインドマウントされません。 Windows では、ディレクトリではないファイルのバインドマウントがサポートされないためです。 そのかわり、コンテナーに対する configs は、コンテナー内の
C:\ProgramData\Docker\internal\configs
(アプリケーションに依存しない実装場所)にすべてマウントされます。 ここを示すシンボリックリンクが利用され、コンテナー内に必要となる config ターゲットが設定されます。 デフォルトターゲットはC:\ProgramData\Docker\configs
です。 -
Windows コンテナーを利用するサービスが生成されるとき、UID、GID を指定するオプションやモードは configs においてサポートされません。 configs は現在のところ、コンテナー内の administrators か
system
アクセス可能なユーザーのみがアクセス可能であるからです。 -
On Windows, create or update a service using
--credential-spec
with theconfig://<config-name>
format. This passes the gMSA credentials file directly to nodes before a container starts. No gMSA credentials are written to disk on worker nodes. For more information, refer to Deploy services to a swarm.
Docker は configs をどう管理しているか
スウォームに対して config を追加すると、Docker は TLS 相互接続によりスウォームマネージャーに対して config を送信します。 この config は Raft ログとして暗号化され保存されます。 Raft ログ全体は、他のマネージャーに向けて複製されますが、スウォームが管理するデータとともに configs の高可用性は確保されます。
新規生成したサービス、あるいは既存のサービスに対して config へのアクセス許可を行うと、config はコンテナー内において 1 つのファイルとしてマウントされます。
コンテナー内のマウントポイントのデフォルトは、Linux コンテナーでは /<config-name>
となります。
Windows コンテナーの場合、configs はすべて C:\ProgramData\Docker\configs
にマウントされ、
コンテナー内に必要となる config ターゲットが、シンボリックリンクとして生成されます。
config ターゲットのデフォルトは C:\<config-name>
です。
config の所有(uid
と gid
)を設定するには、ID 値か、あるいはユーザー名やグループ名を用います。
またファイルパーミッションを設定することもできます。
この設定は Windows コンテナーにおいては無視されます。
- 所有者が設定されていない場合、config を所有するユーザーは、コンテナーコマンドを実行したユーザー(普通は
root
)とそのグループ(これも普通はroot
)になります。 - 所有者が設定されていない場合、config のパーミッションはすべて読み込み可(
0444
モード)となります。 ただしこれはコンテナー内にumask
が設定されていない場合であり、これが設定されていればumask
の値設定に従います。
configs を追加した際に、configs にアクセスできるようにサービスをアップデートしたり、configs を再読み込みしたりすることは、どのタイミングでも可能です。
configs へアクセスできるノードはスウォームマネージャーか、あるいはその configs へのアクセスが許可された稼働中のサービスタスクです。 コンテナータスクが停止すると、共有されていた configs は、そのコンテナーのメモリ内ファイルシステムからアンマウントされ、ノードのメモリからも消去されます。
config にアクセスしている稼働中のタスクコンテナーが、スウォームとの接続を失った場合、そのタスクコンテナーの config へのアクセスは維持されます。 ただし config の更新を受け取ることはできず、これができるようになるのはスウォームに再接続した後です。
個々の config を追加したり確認したり、configs すべてを一覧したりすることはいつでもできます。 ただし稼働中のサービスが config を利用している場合は、それを削除できません。 config の入れ替えでは、実行中のサービスを中断することなく config を削除する方法について説明しています。
configs のアップデートやロールバックをより簡単に行うために、config 名にバージョン番号や日付をつけることを考えてみてください。 取り扱うコンテナーの config マウントポイントを自由に管理できれば、より一層簡単になります。
スタックの更新や Compose ファイルの変更を行うには docker stack deploy -c <new-compose-file> <stack-name>
を再実行します。
新たな config を用いるようにしたのであれば、それを利用してサービスが起動します。
設定は不変なものであることを忘れないでください。
つまり既存のサービスに対する設定ファイルは変更することはできません。
これを行うなら、新たな設定を別のファイルとして生成してください。
docker stack rm
を実行すれば、アプリを止めてスタックを停止させることができます。
このとき、同一のスタック名により docker stack deploy
から生成された config は削除されます。
これは すべての configs が削除されるということです。
サービスから参照されていなかったものや、docker service update --config-rm
を実行した後に残ったものも、すべて削除されます。
docker config
コマンドについての詳細
コマンドの詳細は以下のリンクを参照してください。 また サービスにおける configs の利用例 も参照してください。
利用例
本節では Docker configs の利用例を段階的に示します。
メモ: ここでの利用例では説明を簡単にするために、単一エンジンによるスウォームとスケールアップしていないサービスを用いることにします。 Linux コンテナーを例に用いますが、Windows コンテナーでも configs はサポートされています。
Compose ファイルにおける configs の定義と利用
docker stack
コマンドには、Compose ファイルにて configs を定義する機能がサポートされています。
しかし configs
キーは docker compose
コマンドではサポートされていません。
詳しくは Compose ファイルリファレンス を参照してください。
簡単な例: configs を利用する
この簡単な例では、コマンドを少し書くだけで configs が動作することを示します。 現実的な例としては、応用例: Nginx サービスに configs を利用する に進んでください。
-
Docker に config を追加します。 この
docker config create
コマンドは、最後の引数により標準入力から読み込みを行います。 最後の引数は config をどのファイルから読み込むかを示すものであって、ここではそれを-
としています。$ echo "This is a config" | docker config create my-config -
-
redis
サービスを生成し、config に対してのアクセスを許可します。 デフォルトでコンテナーは/my-config
にある config へのアクセスが可能です。 コンテナー内のそのファイル名は、target
オプションを使って変更することができます。$ docker service create --name redis --config my-config redis:alpine
-
docker service ps
を実行して、タスクが問題なく実行しているかを確認します。 問題がなければ、出力結果は以下のようになります。$ docker service ps redis ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS bkna6bpn8r1a redis.1 redis:alpine ip-172-31-46-109 Running Running 8 seconds ago
-
docker ps
を実行して、redis
サービスのタスクコンテナーに対する ID を取得します。 これを使ってdocker container exec
によりコンテナーにアクセスして、config データファイルの内容を読み込むことができます。 config データファイルはデフォルトで誰でも読むことができ、ファイル名は config 名と同じです。 以下の最初のコマンドは、コンテナー ID を調べるものです。 そして 2 つめと 3 つめは、シェルのコマンド補完を用いて自動的に入力しました。$ docker ps --filter name=redis -q 5cb1c2348a59 $ docker container exec $(docker ps --filter name=redis -q) ls -l /my-config -r--r--r-- 1 root root 12 Jun 5 20:49 my-config $ docker container exec $(docker ps --filter name=redis -q) cat /my-config This is a config
-
config を削除してみます。 ただし削除には失敗します。 これは
redis
サービスが稼働中であり、config にアクセスしているためです。$ docker config ls ID NAME CREATED UPDATED fzwcfuqjkvo5foqu7ts7ls578 hello 31 minutes ago 31 minutes ago $ docker config rm my-config Error response from daemon: rpc error: code = 3 desc = config 'my-config' is in use by the following service: redis
-
redis
サービスを更新して、稼働中のサービスからの config へのアクセスを取り除きます。$ docker service update --config-rm my-config redis
-
手順の 3 と 4 を繰り返してみます。 このときには、もう config へのアクセスが行われていません。 コンテナー ID は異なるものになっています。
service update
コマンドを実行したので、サービスが再デプロイされたためです。$ docker container exec -it $(docker ps --filter name=redis -q) cat /my-config cat: can't open '/my-config': No such file or directory
-
サービスを停止して削除します。 そして Docker から config も削除します。
$ docker service rm redis $ docker config rm my-config
簡単な例: Windows サービスにて configs を利用する
ここでの簡単な例は Windows 上において configs を利用するものです。 利用にあたっては Microsoft Windows 10 上の Docker for Windows を用いて Windows コンテナーを稼動させて、Microsoft IIS サービスを稼動させます。 この例は config 内にウェブページを保存します。
PowerShell はインストール済であるとします。
-
以下のような
index.html
を新規生成して保存します。<html lang="en"> <head><title>Hello Docker</title></head> <body> <p>Hello Docker! You have deployed a HTML page.</p> </body> </html>
-
スウォームの初期化と参加を行っていない場合は、これを行います。
docker swarm init
-
index.html
ファイルを、スウォームの config ファイルとしてhomepage
という名前により保存します。docker config create homepage index.html
-
IIS サービスを生成して
homepage
config へのアクセスを許可します。docker service create --name my-iis --publish published=8000,target=8000 --config src=homepage,target="\inetpub\wwwroot\index.html" microsoft/iis:nanoserver
-
IIS サービスを通じて
http://localhost:8000/
にアクセスします。 手順 1 で作り出した HTML 内容が表示されるはずです。 -
サービスと config を削除します。
docker service rm my-iis docker config rm homepage
Example: Use a templated config
To create a configuration in which the content will be generated using a
template engine, use the --template-driver
parameter and specify the engine
name as its argument. The template will be rendered when container is created.
-
Save the following into a new file
index.html.tmpl
.<html lang="en"> <head><title>Hello Docker</title></head> <body> <p>Hello {{ env "HELLO" }}! I'm service {{ .Service.Name }}.</p> </body> </html>
-
Save the
index.html.tmpl
file as a swarm config namedhomepage
. Provide parameter--template-driver
and specifygolang
as template engine.$ docker config create --template-driver golang homepage index.html.tmpl
-
Create a service that runs Nginx and has access to the environment variable HELLO and to the config.
$ docker service create \ --name hello-template \ --env HELLO="Docker" \ --config source=homepage,target=/usr/share/nginx/html/index.html \ --publish published=3000,target=80 \ nginx:alpine
-
Verify that the service is operational: you can reach the Nginx server, and that the correct output is being served.
$ curl http://0.0.0.0:3000 <html lang="en"> <head><title>Hello Docker</title></head> <body> <p>Hello Docker! I'm service hello-template.</p> </body> </html>
応用例: Nginx サービスに configs を利用する
この例は 2 つの部分から構成されます。 1 つめの部分は、サーバー証明書の生成に関してです。 Docker configs とは直接関係がありません。 ただし 2 つめの部分において、一連の機密情報としてそのサーバー証明書を保存して利用します。 また Nginx の設定を config として保存します。 この例では config におけるオプションの設定方法を示しており、たとえばコンテナー内のターゲットを指定したり、ファイルパーミッションを指定したりしています。
サーバー証明書の生成
自サイトに対しての root CA と TLS 証明書および鍵を生成します。
本番環境向けでは Let’s Encrypt
のようなサービスを利用して、TLS 証明書や鍵を生成するかもしれませんが、この例ではコマンドラインツールを用いることにします。
ここでの手順は多少複雑です。
ただしここでは唯一、Docker secret を使って情報を保存する手順を示すものです。
この手順を行わない場合は、Let’s Encrypt の利用を通じて、サイトの鍵と証明書を生成し、それぞれを site.key
、site.crt
としてください。
その場合は Nginx コンテナーの設定 に進んでください。
-
root 鍵を生成します。
$ openssl genrsa -out "root-ca.key" 4096
-
root 鍵を使って CSR を生成します。
$ openssl req \ -new -key "root-ca.key" \ -out "root-ca.csr" -sha256 \ -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA'
-
root CA を設定します。 新規に
root-ca.cnf
というファイルを生成して、以下の内容を書き込みます。 ここでは root CA をリーフ証明書として生成し、中間証明書とはしません。[root_ca] basicConstraints = critical,CA:TRUE,pathlen:1 keyUsage = critical, nonRepudiation, cRLSign, keyCertSign subjectKeyIdentifier=hash
-
証明書にサインします。
$ openssl x509 -req -days 3650 -in "root-ca.csr" \ -signkey "root-ca.key" -sha256 -out "root-ca.crt" \ -extfile "root-ca.cnf" -extensions \ root_ca
-
サイト鍵を生成します。
$ openssl genrsa -out "site.key" 4096
-
サイト証明書を生成し、サイト鍵を用いてサインします。
$ openssl req -new -key "site.key" -out "site.csr" -sha256 \ -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
-
サイト証明書を設定します。 新規に
site.cnf
というファイルを生成して、以下の内容を書き込みます。 この証明書はサーバーを認証するためだけに用いるものとし、他の証明書のサインには用いることができないようにします。[server] authorityKeyIdentifier=keyid,issuer basicConstraints = critical,CA:FALSE extendedKeyUsage=serverAuth keyUsage = critical, digitalSignature, keyEncipherment subjectAltName = DNS:localhost, IP:127.0.0.1 subjectKeyIdentifier=hash
-
サイト証明書にサインします。
$ openssl x509 -req -days 750 -in "site.csr" -sha256 \ -CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \ -out "site.crt" -extfile "site.cnf" -extensions server
-
site.csr
とsite.cnf
は Nginx サービスにとっては不要です。 ただし新たなサイト証明書を生成する際には必要になります。root-ca.key
は大事に保管しておきます。
Nginx コンテナーの設定
-
Nginx の基本的な設定として、HTTPS 越しにスタティックファイルを提供するものを用意します。 TLS 証明書と鍵は Docker secrets として保存します。 こうしておけば config の入れ替えも簡単に行うことができます。
カレントディレクトリにおいて、
site.conf
というファイルを新規生成し、内容を以下のようにします。server { listen 443 ssl; server_name localhost; ssl_certificate /run/secrets/site.crt; ssl_certificate_key /run/secrets/site.key; location / { root /usr/share/nginx/html; index index.html index.htm; } }
-
鍵と証明書を表わす Docker secrets を 2 つ生成します。 Docker secrets はどのようなファイルであっても、サイズが 500 KB 以下であれば保存できます。 こうして鍵と証明書は、これを利用するサービスから切り離すことができます。 ここでの例では、secrets とファイル名は同一にしています。
$ docker secret create site.key site.key $ docker secret create site.crt site.crt
-
Docker config の中に
site.conf
ファイルを保存します。 第 1 パラメーターは config 名、第 2 パラメーターはそれを読み込むファイル名です。$ docker config create site.conf site.conf
configs の一覧を確認します。
$ docker config ls ID NAME CREATED UPDATED 4ory233120ccg7biwvy11gl5z site.conf 4 seconds ago 4 seconds ago
-
Nginx を起動するサービスを生成し、2 つの secrets と config へのアクセスを許可します。 モードは
0440
とし、読み込み可とするのは所有者とそのグループのみ、つまりすべてへの読み込み許可は与えないようにします。$ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --config source=site.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \ --publish published=3000,target=443 \ nginx:latest \ sh -c "exec nginx -g 'daemon off;'"
稼動中のコンテナー内部では、以下の 3 つのファイルが存在しています。
/run/secrets/site.key
/run/secrets/site.crt
/etc/nginx/conf.d/site.conf
-
Nginx サービスが起動していることを確認します。
$ docker service ls ID NAME MODE REPLICAS IMAGE zeskcec62q24 nginx replicated 1/1 nginx:latest $ docker service ps nginx NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS nginx.1.9ls3yo9ugcls nginx:latest moby Running Running 3 minutes ago
-
そのサービスが操作可能であることを確認します。 つまり Nginx サーバーへアクセスができ、正しい TLS 証明書が用いられていることを確認します。
$ curl --cacert root-ca.crt https://0.0.0.0:3000 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support, refer to <a href="https://nginx.org">nginx.org</a>.<br/> Commercial support is available at <a href="https://www.nginx.com">www.nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
$ openssl s_client -connect 0.0.0.0:3000 -CAfile root-ca.crt CONNECTED(00000003) depth=1 /C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA verify return:1 depth=0 /C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost verify return:1 --- Certificate chain 0 s:/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost i:/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA --- Server certificate -----BEGIN CERTIFICATE----- … -----END CERTIFICATE----- subject=/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost issuer=/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA --- No client certificate CA names sent --- SSL handshake has read 1663 bytes and written 712 bytes --- New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 4096 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: A1A8BF35549C5715648A12FD7B7E3D861539316B03440187D9DA6C2E48822853 Session-ID-ctx: Master-Key: F39D1B12274BA16D3A906F390A61438221E381952E9E1E05D3DD784F0135FB81353DA38C6D5C021CB926E844DFC49FC4 Key-Arg : None Start Time: 1481685096 Timeout : 300 (sec) Verify return code: 0 (ok)
-
この例を実行した後に、次に示す例は確認しないのであれば、
nginx
サービスと保存した secrets、config を削除します。$ docker service rm nginx $ docker secret rm site.crt site.key $ docker config rm site.conf
ここまでの例から Nginx サービスの設定内容を、そのイメージから切り離した形で実現しました。 まったく同じイメージを使い異なる設定によって複数サイトを提供しようと思ったら、もう新たなイメージをビルドする必要はなくなったわけです。
例: config の入れ替え
config を入れ替えるには、まず新たな config を、現在利用している config とは別の名前で保存しておきます。
そしてサービスを再デプロイし、古い config を削除して、コンテナー内の同一マウントポイントに新たな config を追加します。
ここに示す例では、前述の例をもとにして、site.conf
という設定ファイルを切り替える方法を示します。
-
ローカルの
site.conf
ファイルを編集します。index
行にindex.php
を追加し保存します。server { listen 443 ssl; server_name localhost; ssl_certificate /run/secrets/site.crt; ssl_certificate_key /run/secrets/site.key; location / { root /usr/share/nginx/html; index index.html index.htm index.php; } }
-
上の
site.conf
ファイルを使って、新たなsite-v2.conf
という Docker config を生成します。$ docker config create site-v2.conf site.conf
-
nginx
サービスを更新して、古い config から新しい config を利用するようにします。$ docker service update \ --config-rm site.conf \ --config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \ nginx
-
docker service ps nginx
を実行して、nginx
サービスが問題なく再デプロイされていることを確認します。 正常であれば、古い config つまりsite.conf
を削除します。$ docker config rm site.conf
-
クリーンアップします。
nginx
サービスを削除し、同じく secrets と configs も削除します。$ docker service rm nginx $ docker secret rm site.crt site.key $ docker config rm site-v2.conf
こうして nginx
サービスの設定は、イメージを再ビルドすることなく更新することができました。