Chefの全体像が掴めた気になれる用語集

# 1. はじめに

ChefのチュートリアルをやってみたけどイマイチChefのなんたるかが掴めなかったので、公式ドキュメントのSite Mapを見ながら理解を深めるためにいろいろ書き出してみた。

# 2. Chefとは
あちこちのサイトで説明されているので省略

# 3. 構成

## 3.1. 超簡易概略図
* よくある構成

  ```text:Chef_Basic_Structure
      自マシン           中央管理鯖       デプロイ対象
                                        +------+
                                        | Node |
                                        +------+
  +-------------+    +-------------+    +------+
  | Workstation | -> | Chef server | -> | Node |
  +-------------+    +-------------+    +------+
                                        +------+
                                        | Node |
                                        +------+
  ```

* Chef Soloを用いた構成

  ```text:Chef_Solo_Structure
  +------------------------------------+
  | Workstation                        |
  |      |                             |
  |      v                             |
  | +-----------+                      |
  | | Chef Solo | -> Node(Workstation) |
  | +-----------+                      |
  +------------------------------------+
  ```

## 3.2. Workstation
自分の作業PCのこと。後述する`Chef Development Kit(Chef DK)`をインストールする。
Chefをかじったことがある人なら聞いたこのある`Recipe`や`Cookbook`の作成はココ。`Chef server`に対し`knife`と呼ばれるコマンドラインツールを用いて、作成した`Cookbook`、`Recipe`のアップロードをするのもココ。
https://docs.chef.io/workstation.html

## 3.3. Chef server
`Cookbook`の管理、後述する`Node`に対してどのような`Recipe`(正確に言うと`Run-list`)を適用させるかなどの設定管理を行う中央サーバー。`knife`を利用するために必要な秘密鍵の取得はココから取ってくる。
https://docs.chef.io/server_components.html

## 3.4. Node
デプロイ対象のサーバー、サーバーインスタンス、ネットワーク機器などさまざまなマシンのこと。これらの`Node`に対してChefは`Cookbook`を適用してマシンの構成管理を行う。`Node`には事前に`chef-client`をインストールする必要がある。
また`Node`には`Run-list`と呼ばれる構成情報リストを指定する必要がある。
https://docs.chef.io/nodes.html

# 4. ツール類

## 4.1. Chef Development Kit (Chef DK)
Chefを利用するのに必要なツールが1つになった開発キット。とりあえず`Workstation`に入れておけば問題なし。
https://downloads.chef.io/chef-dk/

## 4.2. chefコマンド
`Cookbook`や`Recipe`のひな形、`Cookbook`の開発に必要なgemの管理などを行う便利コマンド。
https://docs.chef.io/ctl_chef.html

## 4.3. knifeコマンド
Workstationにある`chef-repo`と`Chef server`間で通信を行うためのコマンドラインツール。`Node`の設定や`Cookbook`のアップロード、`Role`設定などなど、Chefの動作に必要な設定情報をこのツールを利用して`Chef server`とやりとりする。
https://docs.chef.io/knife.html

## 4.4. Berkshelf
`Cookbook`の依存関係を管理するツール。`Cookbook`が格納されたディレクトリの`Berksfile`がこのツールの設定ファイルとなる。
https://docs.chef.io/berkshelf.html
http://berkshelf.com/

## 4.5. chef-client
`Chef server`から`Cookbook`をダウンロードして同期したり、実際に`Node`に対して構成情報の反映を行うエージェントツール。`Node`にインストールして利用する。
https://docs.chef.io/chef_client.html

## 4.6. Test Kitchen, ChefSpec, Foodcritic
インテグレーションテストツール、コードの整形(lint)ツールなどなど。
あると便利なツールたちで、必要に応じて利用する。


# 5. 利用者が作成するもの

## 5.1. chef-repo
`Cookbook`本体や`Role`や`Environment`毎の情報を管理するレポジトリ。いわゆる作業ディレクトリのこと。これをGitなどのVCSを利用して管理する。

`chef-repo`の内容は`knife`コマンドを利用して`Chef server`との同期を行う。内容がアップロードされれば、`Chef server`に登録された`Node`上の`chef-client`で`chef-repo`内の`Cookbook`や`Role`そして`Environment`などが利用可能となる。
https://docs.chef.io/chef_repo.html

### 5.1.1. 管理するもの
以下が`chef-repo`で管理すべき項目。5.2.から各項目について説明していく。

* Policy
   * `Role`
   * `Environment`
   * `Data bag`
   * `Cookbook`
     * `Recipe`
     * `Attribute`
     * etc...

### 5.1.2. 構成ディレクトリ

| 構成ディレクトリ | 構成ファイル                            |
|---------------|--------------------------------------|
| .chef/        | `Chef server`から取得した秘密鍵と`knife.rb`など |
| cookbooks/    | `Cookbook`のディレクトリ           |
| databags/     | `Data bag`が記されたRubyもしくはjsonファイル     |
| environments/ | `Environment`が記されたRubyもしくはjsonファイル |
| roles/        | `Role`が記されたRubyもしくはjsonファイル        |

## 5.2. Policy
`Policy`とは「`Chef server`に保持される`Node`のプロビジョニングのために必要な設定やオブジェクトの総称」のこと。意味は5.1.1.で紹介した`chef-repo`で管理する項目と同義。いわば`chef-repo`は`Policy`を管理していると言っても良い気がする。
https://docs.chef.io/policy.html

### 5.2.1. Role
`Node`に紐づく **役割(Role)** 毎に、プロビジョニングに利用する`Cookbook`の`Recipe`や後述する`Attribute`を設定する。
`Role`は、たとえばWebサーバーであったり、DBサーバーであったりと`Node`ごとに機能が分かれているサーバーの役割毎に作成することが多い。
https://docs.chef.io/roles.html

`Role`のjsonファイル例

```javascript:roles/web.json
{
  "name": "web",
  "chef_type": "role",
  "json_class": "Chef::Role",
  "default_attributes": {
    "apache": {
      "listen": [ "*:80", "*:443" ]
    }
  },
  "description": "HTTP Server",
  "run_list": [
    "recipe[apache2]",
    "recipe[apache2::mod_ssl]"
  ]
}
```

### 5.2.2. Enviornment
`Node`に紐づく **環境(Environment)** 毎に、プロビジョニングに利用する`Cookbook`の`Recipe`や後述する`Attribute`を設定する。
`Environment`は、たとえば開発に利用する「開発環境」であったり、本番デプロイ前に利用する「ステージング環境」、本番用の「本番環境」といった環境毎に作成することが多い。
https://docs.chef.io/environments.html

`Environment`のjsonファイル例

```javascript:environments/prod.json
{
  "name": "prod",
  "default_attributes": {
    "apache": {
      "timeout": 500,
      "contact": "admin@example.com",
      "serversignature": "Off"
    }
  },
  "json_class": "Chef::Environment",
  "description": "Procudtion environment",
  "chef_type": "environment"
}
```

### 5.2.3. Data Bag
上記の`Role`にも`Environment`にも関連しない、「`chef-repo`全体で共有しておくべきデータを扱いたい場合」は`Data bag`を利用する。
たとえば、各`Role`、各`Environment`で共通したアプリケーション実行ユーザーアカウントを利用したいと考えた場合、アカウントデータを`Data bag`に登録しておき、そのデータを`Recipe`内で利用してユーザーを`Node`上に作成する、といった使い方ができる。

また、サーバー間連携で利用するための秘密鍵や、DBに接続するためのパスワードなどのセキュアな情報を格納することも可能。それらのデータの暗号化、複合化機能もChefが提供してくれる。
https://docs.chef.io/data_bags.html

### 5.2.4. Run-list
`Run-list`は「`Node`もしくは`Role`」を構成するのに必要な「`Role`もしくは`Recipe`」を列挙したリストのこと。`Node`には`Role`の情報を、`Role`には`Recipe`の情報を指定する、といった使い方がキレイにまとまりそう。
https://docs.chef.io/run_lists.html

`Run-list`の書式は以下のとおり。

* webという`Role`を指定する

  ```
  'role[web]'
  ```

* `Cookbook`名がhoge、`Recipe`名がhugaの`Recipe`を指定する

  ```
  'recipe[hoge::huga]'
  ```


## 5.3. Cookbook
`Cookbook`は「`Recipe`の管理」や、「`Cookbook`内の`Recipe`および`Node`で利用する属性値を定義する`Attribute`の管理」を行う。`Recipe`と並ぶ`Chef`の根幹を成す概念。
https://docs.chef.io/cookbooks.html

`Cookbook`を構成する代表的なディレクトリやファイルは以下のとおり。

### 5.3.1. 代表的な構成ディレクトリ

| ディレクトリ名 | 概要                         |
|-------------|------------------------------|
| attributes/ | `Attribute`を定義するRubyコードを格納するディレクトリ |
| files/      | `cookbook_file` resourceなどのファイルを操作するresourceで利用するファイルが格納される<br>https://docs.chef.io/files.html |
| libraries/  | 任意のRubyのコードを格納するディレクトリ<br>https://docs.chef.io/libraries.html |
| recipes/    | `Recipe`を格納するディレクトリ |
| resources/  | `Cookbook`独自の`Resource`(`Custom Resource`)を定義するために利用するディレクトリ<br>https://docs.chef.io/custom_resources.html |
| spec/       | ChefSpecなどで利用するテストファイルを格納するディレクトリ<br>https://docs.chef.io/chefspec.html |
| templates/  | [eRuby](https://ja.wikipedia.org/wiki/ERuby)を利用しテンプレート化した設定ファイルを格納するディレクトリ<br>https://docs.chef.io/templates.html |

### 5.3.2. 代表的な構成ファイル

| ファイル名     | 概要                           |
|--------------|-------------------------------|
| .kitchen.yml | [Test Kitchen](http://kitchen.ci/)で利用する設定ファイル |
| Berksfile    | [Berkshelf](http://berkshelf.com/)の設定ファイル          |
| metadata.rb  | `Cookbook`の名前や作者などのメタデータの設定ファイル<br>https://docs.chef.io/cookbook_repo.html#about-cookbook-metadata |
| chefignore   | `Chef server`へのアップロード時に除外するファイルの設定ファイル<br>https://docs.chef.io/chef_repo.html#chefignore-files |

### 5.3.3. Recipe
Chef独自の[DSL](https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%9B%BA%E6%9C%89%E8%A8%80%E8%AA%9E)で記述されたRubyファイルのこと。「特定のパッケージがインストールされている」、「このパスに特定のファイルが配置されている」など`Node`を構成する設定情報が記述されている。`Cookbook`の構成要素の1つ。
https://docs.chef.io/recipes.html

### 5.3.4. Recipeの例

```ruby:recipe.rb
file '/tmp/motd' do
  content 'hello chef!'
end

apt_update 'Update the apt cache daily' do
  frequency 86_400
  action :periodic
end

package 'tar'
```

上記の`Recipe`は`Node`が以下の3つの状態になっていることを表している。

* `/tmp/motd`にはファイルが存在していて、そのファイルの内容は`hello chef!`と書かれている
* 86,400秒ごとに`apt-get update`が実行される
* `tar`パッケージがインストールされている

`file`や`apt_update`は`Resource`と呼ばれ、この`Resource`を`Recipe`内に記述していくことで構成情報を定義していく。
https://docs.chef.io/resource.html

### 5.3.5. Attribute
`Node`に設定された属性情報のこと。`Ohai`と呼ばれる`Node`内の情報を収集するツールが自動で設定する`Attribute`もあれば、`Cookbook`や`Recipe`で定義される`Attribute`も存在する。この`Attribute`は`Recipe`内で利用することもできる。
https://docs.chef.io/attributes.html


#### 5.3.5.1. Ohaiで設定されるAttribute例
| Attribute名     | 説明                |
|-----------------|--------------------|
| node['platform']| `Node`のプラットフォーム情報<br>(ex. ubuntu, centos...)|
| node['ipaddress']| `Node`のIPアドレス  |

#### 5.3.5.2. Attributeファイル
`Cookbook`の`attributes/`ディレクトリにはAttributeファイルを設置することができる。このAttributeファイルはその`Cookbook`で利用する`Attribute`のデフォルト値を定義し、それを`Node`の`Attribute`として利用することができる。

たとえばApache2の`Cookbook`を作成しようと考え、以下のようなAttributeファイルを定義しデフォルト値を設定することができる。

```ruby:attributes/default.rb
default['apache']['dir'] = '/etc/apache2'
default['apache']['listen'] = [ '*:80' ]
```

これらの値を`Recipe`や設定ファイルのテンプレートで利用することができる。各ファイルで`Attribute`を参照するときの書き方は以下の通り。

* `Recipe`

  ```ruby:recipe.rb
  node['apache']['dir']    # /etc/apache2
  node['apache']['listen'] # [ '*:80' ]
  ```

* 設定ファイルのテンプレート

  ```apache2.conf.erb
  …
  ServerRoot "<%= node['apache']['dir'] %>"
  …
  <% node['apache']['listen'].each do |l| %>
  Listen <%= l %>
  <% end %>
  …
  ```

#### 5.3.5.3. Attributeの上書き
Attributeファイルは`Cookbook`内で利用する属性のデフォルト値を設定するが、`Node`の動作環境によってはその値を変えたい時がある。そういう時は`Role`や`Environment`の設定ファイルで`Attribute`の値を上書きし`Node`へ反映させることができる。

たとえばApache2のDocumentRootを`Environment`によって変化させたい時は以下のように`Environment`のjsonファイルを作成する。ここでは開発環境のDocumentRootを変更したいと考える。

```javascript:environments/dev.json
{
  "name": "dev",
  "default_attributes": {
    "apache": {
      "dir": "/tmp/etc/apache2/"
    }
  },
  "json_class": "Chef::Environment",
  "description": "Development environment",
  "chef_type": "environment"
}
```

このように環境によって属性値を変更することが可能。同じように`Role`でも似たような書き方をすれば属性値の上書きができる。

属性値の種類や上書きの優先順位はChefによって定義されているので、詳しくは公式ドキュメントを参照。

* 種類: https://docs.chef.io/attributes.html#attribute-types
* 優先順位: https://docs.chef.io/attributes.html#attribute-precedence

# 参考
* https://docs.chef.io/
* https://github.com/svanzoest-cookbooks/apache2
  * `Cookbook`の構成や各機能の利用方法が参考になる