Posted at

confd を試す

More than 3 years have passed since last update.


confd とは

confd は Go 言語で実装されたシンプルな設定管理ツールです。

confd を実行すると、etcd や Consul といったデータストアの値を取得し、テンプレートに反映して設定ファイルを生成します。設定ファイルの生成後に任意のコマンドも実行できるため、例えば nginx の設定ファイルを生成して、nginx に反映するといった流れも実現できます。

confd をデーモンとして起動しておくと、設定を定期的に更新したり、リアルタイムに反映したりできて非常に便利です。ここからは confd を使う手順などをまとめていきます。


セットアップ

今回は Ubuntu 14.04 をインストールしたホストを用意し、そこに環境を構築していきます。

まず、confd をインストールします。

$ curl -L https://github.com/kelseyhightower/confd/releases/download/v0.11.0/confd-0.11.0-linux-amd64 -o confd

$ sudo mv confd /usr/local/bin

confd をサービスとして管理するためのファイルを作成しておきます。

$ sudo vim /etc/init/confd.conf


/etc/init/confd.conf

description "confd"

start on (net-device-up
and local-filesystems
and runlevel [2345])
stop on runlevel [016]

respawn
respawn limit 10 5

script
if [ -f "/etc/default/confd" ]; then
. /etc/default/confd
fi

chdir /var/confd
exec /usr/local/bin/confd >> /var/log/confd.log 2>&1
end script


次に、confd のバックエンドとなる etcd をインストールします。

$ curl -L https://github.com/coreos/etcd/releases/download/v2.2.5/etcd-v2.2.5-linux-amd64.tar.gz -o etcd-v2.2.5-linux-amd64.tar.gz

$ tar xzvf etcd-v2.2.5-linux-amd64.tar.gz
$ sudo cp etcd-v2.2.5-linux-amd64/etcd /usr/local/bin
$ sudo cp etcd-v2.2.5-linux-amd64/etcdctl /usr/local/bin
$ rm -rf etcd-v2.2.5-linux-amd64 etcd-v2.2.5-linux-amd64.tar.gz

etcd をサービスとして管理するためのファイルを作成しておきます。

$ sudo vim /etc/init/etcd.conf


/etc/init/etcd.conf

description "etcd 2.0 distributed key-value store"

start on (net-device-up
and local-filesystems
and runlevel [2345])
stop on runlevel [016]

respawn
respawn limit 10 5

script
if [ -f "/etc/default/etcd" ]; then
. /etc/default/etcd
fi

chdir /var/etcd
exec /usr/local/bin/etcd >> /var/log/etcd.log 2>&1
end script


必要なディレクトリを作成後に、confd と etcd を起動します。

$ sudo mkdir /var/confd /var/etcd

$ sudo service confd start
$ sudo service etcd start


テンプレートからファイルを生成する

ここからは、クイックスタートガイドを参考にテンプレートからファイルを生成する流れを確認します。今回は etcd に格納したキーの値をテンプレートに反映し、設定ファイルを生成します。

まずは、設定ファイルやテンプレートを配置するディレクトリを作成します。

$ sudo mkdir -p /usr/local/etc/confd/{conf.d,templates}

次に、confd の設定ファイルを作成します。設定ファイルは TOML 形式で記述します。

$ sudo vim /usr/local/etc/confd/conf.d/test.toml


/usr/local/etc/confd/conf.d/test.toml

[template]

src = "test.conf.tmpl"
dest = "/tmp/test.conf"
keys = [
"/myapp/database/url",
"/myapp/database/user",
]

設定ファイルの内容をもとに、テンプレートを記述します。

$ sudo vim /usr/local/etc/confd/templates/test.conf.tmpl


/usr/local/etc/confd/templates/test.conf.tmpl

[myconfig]

database_url = {{getv "/myapp/database/url"}}
database_user = {{getv "/myapp/database/user"}}

テンプレートを作成したら、テンプレート変数の値を etcd に設定します。

$ etcdctl set /myapp/database/url example.com

$ etcdctl set /myapp/database/user summerwind

設定ファイル、テンプレート、テンプレート変数の準備ができたら、confd を実行して、ファイルを生成します。

$ sudo /usr/local/bin/confd -onetime -backend etcd -node http://127.0.0.1:4001 -confdir /usr/local/etc/confd/

2016-03-09T05:36:07Z dev /usr/local/bin/confd[2929]: INFO Backend set to etcd
2016-03-09T05:36:07Z dev /usr/local/bin/confd[2929]: INFO Starting confd
2016-03-09T05:36:07Z dev /usr/local/bin/confd[2929]: INFO Backend nodes set to http://127.0.0.1:4001
2016-03-09T05:36:07Z dev /usr/local/bin/confd[2929]: INFO Target config /tmp/test.conf out of sync
2016-03-09T05:36:07Z dev /usr/local/bin/confd[2929]: INFO Target config /tmp/test.conf has been updated

生成されたファイル /tmp/test.conf を確認すると、正しく変数が埋め込まれていることが分かります。

$ cat /tmp/test.conf

[myconfig]
database_url = example.com
database_user = summerwind


継続的にファイルを自動更新する

confd をデーモンとして起動すると、etcd の値を定期的に取得して、ファイルを自動更新することができます。更新頻度は -interval オプションで指定できます。以下の例では30秒ごとに定期更新しています。

$ sudo /usr/local/bin/confd -backend etcd -node http://127.0.0.1:4001 -confdir /usr/local/etc/confd/ -interval 30

この時点でのファイルの内容は以下のようになっています。

$ cat /tmp/test.conf

[myconfig]
database_url = example.com
database_user = summerwind

confd を起動後に、etcd のキーの値を変更します。

$ etcdctl set /myapp/database/url test.example.com

confd による更新がおこなわれると、ファイルの内容が以下のように変化します。

$ cat /tmp/test.conf

[myconfig]
database_url = test.example.com
database_user = summerwind


Watch を使用してリアルタイムに更新する

etcd や Consul といったバックエンドには、Watch 機能が実装されているため、値の変更と同時に設定ファイルを更新することが可能です。Watch 機能を使用するには、-watch オプションを指定して confd を起動します。

$ sudo /usr/local/bin/confd -backend etcd -node http://127.0.0.1:4001 -confdir /usr/local/etc/confd/ -watch


ファイル更新時に任意のコマンドを実行する

confd にはファイルの更新時に、更新されたファイルを検証するためのコマンドと更新されたファイルを反映するコマンドの2つを実行可能です。これらのコマンドは設定ファイルの check_cmdreload_cmd に指定します。

設定ファイルを以下のように変更し、ファイル更新時に /tmp/test.conf.checked/tmp/test.conf.reloaded が作成されるようにします。

$ sudo vim test.toml

[template]

src = "test.conf.tmpl"
dest = "/tmp/test.conf"
keys = [
"/myapp/database/url",
"/myapp/database/user",
]
check_cmd = "touch /tmp/test.conf.checked"
reload_cmd = "touch /tmp/test.conf.reloaded"

confd を起動後に etcd のキーを変更して、ファイルを更新します。

$ sudo /usr/local/bin/confd -backend etcd -node http://127.0.0.1:4001 -confdir /usr/local/etc/confd/ -watch

$ etcdctl set /myapp/database/url test.example.com

ファイルが更新されたのでコマンドが実行され、/tmp/test.conf.checked/tmp/test.conf.reloaded が作成されていることが分かります。

$ ls -al /tmp

total 12
drwxrwxrwt 2 root root 4096 Mar 9 06:18 .
drwxr-xr-x 22 root root 4096 Mar 8 09:22 ..
-rw-r--r-- 1 root root 67 Mar 9 06:18 test.conf
-rw-r--r-- 1 root root 0 Mar 9 06:18 test.conf.checked
-rw-r--r-- 1 root root 0 Mar 9 06:18 test.conf.reloaded

なお、コマンドは check_cmdreload_cmd の順に実行され、コマンドの実行に失敗した場合は、後続のコマンドが実行されず、ファイルもロールバックされるようです。使い方次第では、任意のコマンドを実行するようにもできるので、十分な注意が必要です。


セキュリティの考慮

confd は設定変更時に任意のコマンドを実行できる機能があるため、使い方によってはセキュリティ上問題になるかもしれません。Ubutntu では、標準でインストールされている AppArmor を使用すれば confd の権限を制御できます。AppArmor の設定方法については、ubuntuで AppArmor を使ってセキュアな環境を構築する が詳しいです。

AppArmor による制限を有効にするには、最初に設定ファイルを作成します。この設定ファイルには、confd がどのファイルにアクセスできるかなどの情報を記述します。

$ sudo vim /etc/apparmor.d/usr.local.bin.confd


/etc/apparmor.d/usr.local.bin.confd

# Last Modified: Fri Mar 11 01:53:58 2016

#include <tunables/global>

/usr/local/bin/confd {
#include <abstractions/nameservice>
#include <abstractions/base>

capability net_admin,

network inet stream,
network inet6 stream,

/usr/local/bin/confd mr,
/usr/local/etc/confd/conf.d/ r,
/usr/local/etc/confd/conf.d/test.toml r,
/usr/local/etc/confd/templates/ r,
/usr/local/etc/confd/templates/test.conf.tmpl r,

/etc/test.conf rw,
/etc/.test.conf* rw,

/usr/bin/basename ix,
/usr/bin/env ix,

/proc/sys/kernel/hostname r,
/proc/sys/net/core/somaxconn r,
}


設定ファイルができたら、設定を有効化します。

$ sudo aa-enforce confd

設定を無効化する場合は以下のコマンドを実行します。

$ sudo aa-disable confd

AppArmor によりファイルの読み込みやコマンドの実行が制限されているかどうかは、/var/log/syslog で参照できます。以下のようなログが出力されていれば、制限が有効になっていることになります。

Mar 11 02:32:08 dev kernel: [234656.156133] type=1400 audit(1457663528.431:2358): apparmor="DENIED" operation="open" profile="/usr/local/bin/confd" name="/usr/sbin/service" pid=8515 comm="service" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

Mar 11 02:32:41 dev kernel: [234688.878779] type=1400 audit(1457663561.151:2360): apparmor="DENIED" operation="open" profile="/usr/local/bin/confd" name="/usr/sbin/service" pid=8527 comm="service" requested_mask="r" denied_mask="r" fsuid=0 ouid=0