confdでちいさく始めるインフラ構築の自動化

はじめに
---
最近ではInfrastracutre as codeやImmutable Infrastructreの考え方によるインフラ管理が浸透してきました。

ChefやAnsibl、最近ではItamaeといったプロビジョニングツールの選択肢が増えてきとはいえ、未だに敷居の高さを感じ導入に踏み切れていない方も多いのではないでしょうか。

そこで今回はお手軽に始められるインフラ構築ツールとして**confd**についてまとめてみました。

confdとは
---
goで書かれた設定ファイル管理ツールです。

>[kelseyhightower/confd](https://github.com/kelseyhightower/confd)

主要機能は設定ファイルのテンプレートエンジンなのですが、設定ファイルの生成前後で外部コマンドを実行することが可能です。

そのため
>1. **設定反映のための前処理**
2. **設定ファイルの自動生成**
3. **設定反映のためプロセス再起動**

といった一連の作業を担わせることができます。
また、構成もシンプルなので初めて利用するのに最適なのではと思い今回confdを取り上げてみました。※

また、confdはバイナリ1つで使えるシンプルなツールなので、他のツールと組み合わせて使うといった用途にも向いているかと思います。

以降でconfdのインストール方法、基本的な使い方について記載していきます。
詳細については[本家のドキュメント](https://github.com/kelseyhightower/confd/tree/master/docs)が充実しているので、あくまで本記事では導入部分について記載します。

>※
>正確にはconfdは、ChefやAnsibleなどといったコードでインフラを管理するようなツールではないので、同じ種類のツールではありません。
>ただし、インフラ管理を効率的に行うといった観点ではとても優れたツールなので今回取り上げた次第です。


confdの構成
----
confdは大まかに以下で構成されています。

* テンプレートリソース
* テンプレート
* バックエンド
 

上記の関連は以下のようなイメージです。
以降で各要素について説明します。



▼構成イメージ
![１１１１図1.png](https://qiita-image-store.s3.amazonaws.com/0/48330/a7ff2cba-bb14-5442-d1b5-546f283069cd.png)



#### テンプレートリソース
生成する設定ファイルに関連した以下の情報を記述します。(拡張子は.toml) 


* テンプレート(後述)の配置場所
* 生成ファイルの配置先
* テンプレートに埋め込むデータのキー名(変数のようなもの)
* 設定ファイル生成前後に実行する外部コマンド

このファイルは[TOML](https://github.com/toml-lang/toml)形式で記述していきます。

▼記述例

```
[template]
#テンプレート名
src = "my.cnf.tmpl"

#テンプレートから生成されたファイルの配置先
dest = "/etc/mysql/my.cnf"

#テンプレートの中で利用するキー名の設定
keys = [
    "/mysql/user",
    "/mysql/port",
]

#設定ファイル生成前に実行される外部コマンドを指定
check_cmd = "cp /etc/mysql/my.cnf /etc/mysql/bk_my.cnf"

#設定ファイル生成後に実行される外部コマンドを指定
reload_cmd = "/usr/sbin/service myslq restart"
```

#### テンプレート
生成する設定ファイルのひな形ファイルです。(拡張子は.tmpl)
実際の設定ファイルをベースに、confd専用コマンドを埋め込むことで、動的に設定ファイルを生成します。
下記例では先ほどのテンプレートリソース内で設定したキー名を埋め込み、バックエンド(後述)からキーに対応する値取得し埋め込みます。

▼記述例(例としてmysqlのmy.cnfを利用)

```
…(省略)
[mysqld]
user            = {{getv "/mysql/user"}} #キーに対応する値に置き換わる
port            = {{getv "/mysql/port"}} #キーに対応する値に置き換わる
…(省略)
```

その他利用できるコマンドは[ドキュメント](https://github.com/kelseyhightower/confd/blob/master/docs/templates.md)に記載があります。

#### バックエンド
テンプレートリソース内で設定したキーに対応した値を格納する先です。
バックエンドには以下を利用することが可能です。
KVSが中心ですが環境変数も利用できるので、より手軽に扱うことができます。

* etcd
* consul
* redis
* zookeeper
* dynamodb
* 環境変数

テンプレート中で利用したいキーバリューをバックエンドで設定し、それをテンプレートリソース経由で利用するようなイメージです。

下記例はredisで先ほどのキーに対応する値を設定しています。
confdによりキーに対応する値がバックエンドより取得され、設定ファイルが生成される仕組みです。

```
redis-cli set /mysql/user mysql
redis-cli set /mysql/port 443
```


confdのインストール
---
インストール方法には2通りあります。
>* ソースからビルド
* コンパイル済みバイナリを利用

今回は既にコンパイル済みのバイナリをダウンロードして利用します。

[こちら](https://github.com/kelseyhightower/confd/releases/)から今回はバージョン0.10.0をダウンロードします。

```shell-session
$ wget https://github.com/kelseyhightower/confd/releases/download/v0.10.0/confd-0.10.0-linux-amd64
```
これで早速confdが利用可能です。(goさすが！)
ただ名前が長く利用しにくいので今回はconfdにリネームしておきます。

```shell-session
$ mv confd-0.10.0-linux-amd64 confd
```
ソースからビルドする場合は[本家github](https://github.com/kelseyhightower/confd)に方法が記載されているのでご参照ください。

基本的な使い方
-----
confdの[Quick Start Guide](https://github.com/kelseyhightower/confd/blob/master/docs/quick-start-guide.md)をもとに、mysqlの設定を例にまとめます。
また、今回は手軽に始めれらるようにバックエンドに環境変数を利用します。

#### 1. 事前準備
各種ファイルを配置するディレクトリを作成します。

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

conf.dディレクトリにはテンプレートリソースファイル、templatesディレクトリにはテンプレートファイルを配置します。

#### 2. テンプレートリソースの作成
生成した設定ファイル(今回の例ではmy.cnf)に付随する情報をテンプレートリソースへ記述していきます。
あわせて、my.cnf生成後にmysqlへ設定を反映させるためプロセス再起動処理も記述します。

▼/etc/confd/conf.d/my.conf.toml

```
[template]
src = "my.cnf.tmpl"
dest = "/etc/mysql/my.cnf"
keys = [
    "/mysql/mysqld/querycachelimit",
    "/mysql/mysqld/querycachesize"
]
reload_cmd = "sudo /usr/sbin/service mysql restart"
```

#### 3. テンプレートの作成
テンプレートを作成します。
このテンプレートに埋め込まれた処理が実行されて生成されたファイルがテンプレートリソースで指定したパスに配置されます。
今回はテンプレートリソースで設定したキーバリューを埋め込みます。

▼/etc/confd/templates/my.conf.tmpl

```
[mysqld]

・・・(省略)

#
# * Query Cache Configuration
#
query_cache_limit       = {{getv "/mysql/mysqld/querycachelimit"}}
query_cache_size        = {{getv "/mysql/mysqld/querycachesize"}}

・・・(省略)
```

#### 4. 値の設定
テンプレートリソースで設定したキーに対応する値を設定していきます。
ここで設定した値がテンプレート内で記述した{{getv "キー名"}}に埋め込まれます。

バックエンドに環境変数を選択した場合、環境変数名は設定したキーの**スラッシュ(/)**を**アンダーバー(_)**に変え、文字を大文字に変えて設定する必要があります。

今回はキー名が

* /mysql/mysqld/querycachelimit
* /mysql/mysqld/querycachesize

なので、設定する環境変数名は以下のようになります。

```
$ export MYSQL_MYSQLD_QUERYCACHELIMIT=1M
$ export MYSQL_MYSQLD_QUERYCACHESIZE=4M
```

#### 5. 実行
それでは設定を反映します。
以下のオプションを指定してconfdを実行します。

**-onetime** : 一度だけ実行(デーモンでconfd常駐させない)
**-backend** : バックエンドを指定。今回は環境変数なので**env**を指定。

```
$ ${CONFD_BIN_HOME}/confd -onetime -backend env
```

実行に成功すると以下のようなログが出力されます。

```
2015-06-30T13:43:35+09:00 mypc ./confd[5373]: INFO Backend set to env
2015-06-30T13:43:35+09:00 mypc ./confd[5373]: INFO Starting confd
2015-06-30T13:43:35+09:00 mypc ./confd[5373]: INFO Backend nodes set to
2015-06-30T13:43:35+09:00 mypc ./confd[5373]: INFO /etc/mysql/my.cnf has md5sum edd5141e557f4e1fc8f4e039d2933876 should be 7de5f281279b7ebc1f9ca7a13aabf6f1
2015-06-30T13:43:35+09:00 mypc ./confd[5373]: INFO Target config /etc/mysql/my.cnf out of sync
2015-06-30T13:43:38+09:00 mypc ./confd[5373]: INFO Target config /etc/mysql/my.cnf has been updated
```

my.cnfを確認してみると更新されていることが分かります。

```shell-session
$ grep query_cache_ /etc/mysql/my.cnf
query_cache_limit       = 1M
query_cache_size        = 4M
```

ためしに続けて再度実行してみます。

```
$ ./confd  -onetime -backend env
2015-06-30T13:45:38+09:00 keigopc ./confd[5556]: INFO Backend set to env
2015-06-30T13:45:38+09:00 keigopc ./confd[5556]: INFO Starting confd
2015-06-30T13:45:38+09:00 keigopc ./confd[5556]: INFO Backend nodes set to
```

すると今度は設定ファイルの更新がなされた旨のメッセージが出力されません。
またmysqlのプロセスも再起動されていません。

このよう設定内容と実ファイルに差異がない限り処理が実施されてないようになっています。
環境変数の値を変えて再度実行すると、再度confdにより設定ファイルが更新されます。

さいごに
----
いかがでしたでしょうか。
confdは設定ファイル管理ツールであるものの、その前後で外部コマンドが実行できることで柔軟な設定ができます。

以前記事で拝見したのですが、Gunosy（グノシー）さんでは、confdで設定ファイルを生成する処理をスクリプトでラップし、それをDockerfile内で実行することで、コンテナイメージ作成の中であわせて設定ファイルも生成できるような仕組みを利用しているようでうす。

こうしたことからも、confd自体がシンプルなツールなので組み合わせがしやすいというのが一つの強みなのかなと思います。

ぜひconfdで小さくインフラ管理の自動化を始めてみるのはいかがでしょうか。