ChefのCookbookをChef localmodeで実行する手順

chef-clientのみで、ChefのCookbookを実行する Chef localmodeを使ってみます。


## 解決したい課題
Chefを使うにはChef Serverが必要だと思われがちですが、ChefのCookbookはサーバレスでも実行可能であり、その実行形態をChef localmodeといいます。  

Chef localmodeは、Cookbookを実行したい環境に、Chef Clientを導入するだけで使えるので、Cookbookを開発したり、Chef Serverのない環境にCookbookを持ち込んで実行したいときに気軽に使えて便利です。  

Chef Clientを導入してから、実際にChef localmodeでCookbookを実行するまでの流れをまとめておきます。

## Chef localmodeの使い方

### 1. Chef Clientを導入する

それぞれのOSにあったChef Clientをダウンロードし、インストールしてください。
[Chef Download](https://downloads.chef.io/chef/)

### 2. Chef Repositoryを作成する

まず、Cookbook開発のディレクトリであるところのChef Repositoryを作ります。
最低限、`chef-repo`ディレクトリとその下に`cookbooks`ディレクトリがあればOKです。

```shell-session
$ mkdir chef-repo
$ mkdir chef-repo/cookbooks
```

Chef DKがあれば、`chef generate repo local-repo` というコマンドでChef Repositoryを作ることができます。



### 3. Cookbookを作成する

Cookbook用のディレクトリとファイルを作成します。こちらも手で作ります。ここでは例として、`sample_cb`という名前のCookbookを作ります。

> もし、既に作成済みのcookbookをlocalmodeで実行したいだけであれば、作成済みのcookbookをchef-repo/cookbooks 配下に配置してください。その場合は、`手順3. Cookbookを作成する`、`手順4. Cookbookを編集する` をスキップしてください。
> また、既にCookbookを配置済みのchef-repoそのものをzipあたりで圧縮して、Chef Nodeに持ち込んでも良いでしょう。

```shell
$ cd chef-repo/cookbooks
$ mkdir sample_cb
$ mkdir sample_cb/attributes
$ mkdir sample_cb/templates
$ mkdir sample_cb/files
$ mkdir sample_cb/recipes
$ touch sample_cb/attributes/default.rb
$ touch sample_cb/recipes/default.rb
$ touch sample_cb/metadata.rb
$ touch sample_cb/README.md
```

`metadata.rb`には最低限以下のような内容を記載します。`name`には、Cookbookディレクトリと同じ名称のCookbook名を記載してください。

```ruby:sample_cb/metadata.rb
name             'sample_cb'
maintainer       'xxx'
maintainer_email 'dummy@dummy.com'
license          'All rights reserved'
description      '...'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'
```

metadata.rb の詳細は以下を参照してください。
[metadata.rb](https://docs.chef.io/config_rb_metadata.html)


Chef DKがあれば、`chef generate cookbook`というコマンドでCookbookの雛形を作成することができます。もちろん、Chef DKがある環境で作ったCookbookの雛形を持ち込んでも構いません。
> `chef generate cookbook`と同じくCookbookの雛形を作成することができた`knife cookbook create`コマンドは、Chef12で削除されました。

### 4. Cookbookを編集する

デフォルトレシピ（`sample_cb/recipes/default.rb`)にテスト実行用の処理を追加します。ここでは、[logリソース](https://docs.chef.io/resource_log.html)のサンプルを使います。

```ruby:sample_cb/recipes/default.rb
log 'message' do
  message 'A message add to the log.'
  level :warn
end
```


### 5. Cookbookをlocalmodeで実行する

`chef-client` を実行します。localmodeで実行するので`-z`か`--localmode`のオプションが必要です。また、`-o`もしくは`--override-runlist` で実行するCookbookを指定してください。

また、chef-repo直下でchef-client を実行することを推奨します。

```shell-session
$ chef-client -z -o "recipe[sample_cb::default]"
[2018-05-15T16:04:43+09:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 14.1.1
[2018-05-15T16:04:53+09:00] WARN: Run List override has been provided.
[2018-05-15T16:04:53+09:00] WARN: Original Run List: []
[2018-05-15T16:04:53+09:00] WARN: Overridden Run List: [recipe[sample_cb::default]]
resolving cookbooks for run list: ["sample_cb::default"]
Synchronizing Cookbooks:
  - sample_cb (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 1 resources
Recipe: sample_cb::default
  * log[message] action write[2018-05-15T16:04:53+09:00] WARN: A message add to the log.

[2018-05-15T16:04:53+09:00] WARN: Skipping final node save because override_runlist was given

Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 08 seconds
```

`Chef Client finished`と表示されればOKです。

### 補足

`-o` で 実行するCookbookを都度指定しましたが、以下のようにjsonファイルを作成して、Cookbookを実行することも可能です。この方法であれば、jsonファイルの中にAttributeで、CookbookのAttributeを上書きすることも可能になります。

```local.json
{
  "sample_cb": {
    "echo": "HelloWorld!!"
  },
  "run_list": [
    "recipe[sample_cb::default]"
  ]
}
```

```shell-session
$ chef-client -z -j local.json
[2018-05-15T18:01:14+09:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.
[2018-05-15T18:01:20+09:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 14.1.1
resolving cookbooks for run list: ["sample_cb::default"]
Synchronizing Cookbooks:
  - sample_cb (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 1 resources
Recipe: sample_cb::default
  * log[message] action write[2018-05-15T18:01:30+09:00] WARN: HelloWorld!!

Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 08 seconds
```

※ 上の例はデフォルトレシピを以下のように書き換えています。

```ruby:sample_cb/recipes/default.rb
log 'message' do
  message node['sample_cb']['echo']
  level :warn
end
```