etcdと合わせてconfdを使うことで、コンテナ構成の変更を引き金に設定ファイルを動的に更新する事ができます。しかし、confd自体はetcdが元から備えている機能の薄いラッパーに過ぎず、そのためだけに golang 等の言語処理系を丸ごと入れるのは微妙な感じもします。
そこで、confdを使わずに以下の様なシェルスクリプトで代用することにしました。以下はnginxをロードバランサーとして起動するエントリポイントスクリプトの例です。
#!/bin/bash
ETCD=http://<etcd-name-or-ip>:2379
SERVICE=<service name>
SRC=/etc/nginx/nginx.conf.tmpl
DST=/etc/nginx/nginx.conf
gen_conf(){
NODES=`curl -Ls $ETCD/v2/keys/$SERVICE | jq .node.nodes[].value 2>/dev/null`
SERVERS=`
if [ -n "$NODES" ]; then
for N in $NODES; do
echo "server ${N//\"/} weight=1 max_fails=3 fail_timeout=10s;"
done
else
echo "server 127.0.0.1:65535; # force a 502"
fi
` awk '{sub("SERVERS",ENVIRON["SERVERS"]);print}' $SRC > $DST
cat $DST | shasum | awk '{print $1}'
}
DIGEST=`gen_conf`
echo "new $DST"
while :; do
curl -Ls "$ETCD/v2/keys/$SERVICE?recursive=true&wait=true" >/dev/null
NEW_DIGEST=`gen_conf`
if [ "$DIGEST" != "$NEW_DIGEST" ]; then
nginx -t -c $DST && nginx -s reload
DIGEST=$NEW_DIGEST
echo "updated $DST"
fi
done &
nginx -t -c $DST && exec nginx -c $DST
やっていることは、
- 初期テンプレートの生成とチェックサムの記録
- curlでetcdのwait機能を使い変更を監視
- 構成変更を引き金にテンプレートを再生性
- チェックサムに変更があればnginxをリロード
という感じですね。
nginx.conf.tmplの中身は
upstream <service name> {
SERVERS
}
のように置換用のマーカーを置いておきます。
etcdのJSON出力を処理するのにjq
を使っていますが、これはparsrj.shなどを使えばもっと依存関係を減らせそうです。