Docker configs を利用した設定データの保存¶
configs について¶
Docker 17.06 からスウォームサービスの configs が導入されました。 これは設定ファイルのようにそれほど重要ではない情報を、サービスイメージや稼働中のコンテナの外部に保存できる機能です。 これがあれば、ビルドイメージをできるだけ汎用的なものとして維持できます。 また設定ファイルをコンテナにバインドマウントしたり、環境変数を利用したりすることも不要になります。
configs は secrets と同じように機能します。 ただし configs は保存の際に暗号化はされません。 またコンテナのファイルシステム内に直接マウントされますが、RAM ディスクは消費しません。 configs はサービスに対して、どのタイミングであっても追加および削除ができます。 またサービス間で 1 つの config を共有することもできます。 さらに configs と環境変数や Docker labels を組み合わせて利用できるので、最大限に柔軟性を持たせることができます。 configs の値には、通常の文字列やバイナリ(500 KB まで)を指定します。
注釈
Docker configs はスウォームサービスにおいて利用可能であり、スタンドアロンのコンテナでは利用できません。 この機能を利用するには、コンテナをサービスとして稼動させ、スケールは 1 としてください。
configs は Linux と Windows においてサポートされます。
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>
です。
configs を追加した際に、configs にアクセスできるようにサービスをアップデートしたり、configs を再読み込みしたりすることは、どのタイミングでも可能です。
configs へアクセスできるノードはスウォームマネージャか、あるいはその configs へのアクセスが許可された稼働中のサービスタスクです。 コンテナタスクが停止すると、共有されていた configs は、そのコンテナのメモリ内ファイルシステムからアンマウントされ、ノードのメモリからも消去されます。
config にアクセスしている稼働中のタスクコンテナが、スウォームとの接続を失った場合、そのタスクコンテナの config へのアクセスは維持されます。 ただし config の更新を受け取ることはできず、これができるようになるのはスウォームに再接続した後です。
個々の config を追加したり確認したり、configs すべてを一覧したりすることはいつでもできます。 ただし稼働中のサービスが config を利用している場合は、それを削除できません。 config の入れ替え では、実行中のサービスを中断することなく config を削除する方法について説明しています。
configs のアップデートやロールバックをより簡単に行うために、config 名にバージョン番号や日付をつけることを考えてみてください。 取り扱うコンテナの config マウントポイントを自由に管理できれば、より一層簡単になります。
docker config
コマンドについての詳細¶
コマンドの詳細は以下のリンクを参照してください。 また サービスにおける configs の利用例 も参照してください。
利用例¶
本節では Docker configs の利用例を段階的に示します。
注釈
ここでの利用例では説明を簡単にするために、単一エンジンによるスウォームとスケールアップしていないサービスを用いることにします。 Linux コンテナを例に用いますが、Windows コンテナでも configs はサポートされています。
簡単な例: 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 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 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 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 Server 2016 上の Docker 17.06 EE、または Microsoft Windows 10 上の Docker Windows 17.06 CE を用いて Microsoft IIS サービスを稼動させます。 この例は config 内にウェブページを保存します。
PowerShell はインストール済であるとします。
以下のような
index.html
を新規生成して保存します。<html> <head><title>Hello Docker</title></head> <body> <p>Hello Docker! You have deployed a HTML page.</p> </body> </html>
スウォームの初期化と参加を行っていない場合は、これを行います。
PS> docker swarm init
index.html
ファイルを、スウォームの config ファイルとしてhomepage
という名前により保存します。PS> docker config create homepage index.html
IIS サービスを生成して
homepage
config へのアクセスを許可します。PS> docker service create --name my-iis -p 8000:8000 --config src=homepage,target="\inetpub\wwwroot\index.html" microsoft/iis:nanoserver
IIS サービスを通じて
http://localhost:8000/
にアクセスします。 手順 1 で作り出した HTML 内容が表示されるはずです。
サービスと config を削除します。
PS> docker service rm my-iis PS> docker config rm homepage
応用例: 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 へのアクセスを許可します。
$ docker service create \ --name nginx \ --secret site.key \ --secret site.crt \ --config source=site.conf,target=/etc/nginx/conf.d/site.conf \ --publish 3000: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 please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">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 \ 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
サービスの設定は、イメージを再ビルドすることなく更新することができました。
参考
- Store configuration data using Docker Configs