Docker+confdはなかなかよいと思う…

Dockerでいろいろやりたいことがあったので、いろいろ調べてました。

具体的には

  • 設定ファイルのテンプレート化
  • 設定の動的な管理と、変更に伴う継続的な設定の反映
    • 要するに設定が変更されたら設定ファイルが更新されてミドルウェアがリロードされると

でまあEntrykitconfdを教えてもらったんですが、継続的な設定の更新を考えるとconfdがよかろうと。codepの機能は必要ですが、それだけならdumb-initで十分そうでした。

で、以下のようなファイルを用意。

  • Dockerfile
FROM nginx:latest
MAINTAINER Genki Sugawara <sgwr_dts@yahoo.co.jp>

ENV DUMB_INIT_VERSION 1.1.3
ENV CONFD_VERSION 0.11.0

RUN apt-get update
RUN apt-get install -y --force-yes curl

RUN curl -sOL https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64.deb
RUN dpkg -i dumb-init_*.deb
RUN rm dumb-init_*.deb

RUN curl -sOL https://github.com/kelseyhightower/confd/releases/download/v${CONFD_VERSION}/confd-${CONFD_VERSION}-linux-amd64
RUN chmod +x confd-*
RUN mv confd-* /bin/confd
RUN mkdir -p /etc/confd/{conf.d,templates}
ADD nginx_default.conf.toml /etc/confd/conf.d/
ADD nginx_default.conf.tmpl /etc/confd/templates/

ADD init.sh /
RUN chmod +x /init.sh

ENV CONFD_ARGS -backend dynamodb -table confd

ENV AWS_REGION ap-northeast-1
ENV AWS_DEFAULT_REGION ap-northeast-1
ENV AWS_ACCESS_KEY_ID ...
ENV AWS_SECRET_ACCESS_KEY ...

CMD /init.sh
  • init.sh
#!/usr/bin/dumb-init /bin/sh
confd $CONFD_ARGS &
nginx -g 'daemon off;'
  • nginx_default.conf.toml
[template]
src = "nginx_default.conf.tmpl"
dest = "/etc/nginx/conf.d/default.conf"
keys = [
    "/nginx/statuscode"
]
check_cmd = "service nginx configtest"
reload_cmd = "service nginx reload"
  • nginx_default.conf.tmpl
server {
  listen       80 default_server;
  server_name  _;

  location / {
    return {{getv "/nginx/statuscode"}};
  }
}

バックエンドのdynamodbは以下の通り。

aws dynamodb create-table \
  --table-name confd \
  --attribute-definitions AttributeName=key,AttributeType=S \
  --key-schema AttributeName=key,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
$ ddbcli
ap-northeast-1> show create table confd;
CREATE TABLE `confd` (
  `key` STRING HASH
) read=1 write=1

ap-northeast-1> select all * from confd;
[
  {"key":"/nginx/statuscode","value":"404"}
]
// 1 row in set (0.05 sec)

バックエンドが選べるのはなかなかよいですね。 このコンテナをローカルで動かそうと思ったら、-backend envで適当な値を突っ込めるし。

で、これをdocker buildしてdocker runするとcurlで404が返る。

$ docker build -t awesome-confd .
...
$ docker run --rm -p 10080:80 --name awesome-confd -it awesome-confd
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO Backend set to dynamodb
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO Starting confd
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO Backend nodes set to
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO DynamoDB table set to confd
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO /etc/nginx/conf.d/default.conf has md5sum 4dce452bf8dbb01f278ec0ea9ba6cf40 should be 1e1181119f8355e81d3b0a7de2859d5a
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO Target config /etc/nginx/conf.d/default.conf out of sync
2016-08-28T08:34:26Z 1f4823caba59 confd[8]: INFO Target config /etc/nginx/conf.d/default.conf has been updated
$ curl localhost:10080
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.11.3</center>
</body>
</html>

おけおけ。これで-watchオブションつければ設定の監視できるぞ、、と思ったら

2016-08-28T08:36:32Z 63120fea70d1 confd[7]: INFO Watch is not supported for backend dynamodb. Exiting...

残念(あたりまえか…)。

まあ、手動でreloadすればいいかと、CONFD_ARGSとinit.shを以下のように書き換え。

ENV CONFD_ARGS -backend dynamodb -table confd -onetime
#!/usr/bin/dumb-init /bin/sh
confd $CONFD_ARGS
nginx -g 'daemon off;'

再度、docker runしたあと、dynamodbの値を書き換え。

ap-northeast-1> update confd set value = '401' where key = '/nginx/statuscode';
// 1 row changed (0.08 sec)

condを実行。

$ docker exec -it awesome-confd confd -backend dynamodb -table confd -onetime
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO Backend set to dynamodb
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO Starting confd
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO Backend nodes set to
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO DynamoDB table set to confd
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO /etc/nginx/conf.d/default.conf has md5sum 1e1181119f8355e81d3b0a7de2859d5a should be 306f95f0ae59a29344ed21eb0c7886c9
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO Target config /etc/nginx/conf.d/default.conf out of sync
2016-08-28T08:40:44Z 4b3509b1fd93 confd[49]: INFO Target config /etc/nginx/conf.d/default.conf has been updated
$ curl localhost:10080
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.11.3</center>
</body>
</html>

おけおけ。

機密情報について

機密情報については上記DynamoDBとは別のとこに置くと思うんですよね。 VaultとかCredStashとか。

現状のconfdだと、そこから引っ張るのは難しいので、init.shとかで機密情報を引っ張ってきて環境変数に保存して利用とかですかねぇ。環境変数に機密情報を入れるのはもにょるんですが、rootしか見れないだろうし、まあいいかなぁ…

PR眺めてたら機密情報を出し入れするやつがありました。

github.com

ですが、この機能をconfd側持ってしまうのは微妙かな、と考えて任意のシステムコマンドを実行できるテンプレート関数を追加するPRを投げてみました。

github.com

なんとなくリジェクトされる気がする…。

本来的にはプラガブルになるといいんでしょうけど、そこまで工数さくほどかなー