chef-provisioningでお手軽にChef-zero対応してみる

chef-provisioningでお手軽にChef-zero対応してみる
===

![IMG_0940.JPG](https://qiita-image-store.s3.amazonaws.com/0/3470/734f1206-54c7-72e3-abc5-76e41ee89be1.jpeg)


Chef使いの皆さんなら、Chefから、Local Modeが使えるようになったので、[Chef-Soloから乗り換えるといいよ](https://www.chef.io/blog/2014/06/24/from-solo-to-zero-migrating-to-chef-client-local-mode/)といったようなアナウンスを聞いているかと思います。

これは、普段Chef-soloを使っていた私からすると、次の手を探さないといけません。まだ方法は模索中ですが、chef-provisioningを使う方法がすんなり出来たのでその手順を共有したいと思います。とりあえず、簡単にサクッとやりたいんや！


1. Chef-soloからChef-zeroへは甘くない
---

Chef-soloは便利でした。ChefServerなしで、レシピをプロビジョニングできるのでとてもお手軽でした。日本ではそのシンプルさから多くの人に好まれているようです。私も同じです。ところが、この度Local Modeが出来て、Chef-zeroという、ローカルで動作するインメモリのChefServerを使うような仕組みになっています。先の[アナウンス](https://www.chef.io/blog/2014/06/24/from-solo-to-zero-migrating-to-chef-client-local-mode/)では、Local Modeは、Chef-soloのすべての機能を内包しているので、乗り換えな！といっているのですが、実はそんなに甘くないのです。

　次の素晴らしいエントリでも解説されているように、Local Modeで使われる、Chef-zeroでつくられるローカルのサーバーは、プロビジョン先のサーバーからデータを取得しにくるようになるのです。ということは、普通に考えると、プロビジョン先のサーバーがvagrantでつくったものの場合、vagrantから、ホストコンピュータにアクセスできる必要があるのです。そのため、一工夫しないと、気軽に自分のつくったCookbookをプロビジョン先のサーバーにさっと渡すことができません。

[Chefのローカルモードだけでリモートサーバを運用してみようと、Knife-Zeroを作った。Nodeの構成情報もとれるよ。](http://qiita.com/sawanoboly/items/218a7b03ddec6be45e34)

Chefとしては、Chef-soloは上記のアナウンスを見ても、いまいちな方法を思っているらしく、本番にはおそらくChef Serverをつかった方法で運用してほしいという意図が読み取れます。Chef-zeroにしても、実はテストの用途や、Chef-soloの用途と書いてあるけどセキュアでもないし、スケーラブルでもないし、永続的でもないと説明しています。

[Chef-solo](https://docs.chef.io/chef_solo.html)
[Chef-zero](https://github.com/opscode/chef-zero)


2. Chef-soloからの移行の幾つかの手段
---

### 2.1. Knife-zero

真っ先に試してみたのが、[knife-zero](https://github.com/higanworks/knife-zero)です。これはknifeのプラグインで、chef-solo感覚で、Local Modeを使えるようにした素晴らしいツールです。もっともシンプルな記事は[http://knowledge.sakura.ad.jp/tech/2708/](http://knowledge.sakura.ad.jp/tech/2708/)　これが流行ってほしいとは思うのですが、私の方で試してみたところ、また若干枯れていないところがあるのと、私がミスをしているのかもしれませんが、`knife zero chef-client`のオプションなどの指定が、vagrantを使っているときにいまいちどうしたらいいかわらなかったりしました。このツールが悪いというより、元々Chef-zeroという構造がややこしいので、試していないユースケースがあるといろいろ調整しないといけない段階なのだと思います。

　こういうのも、だんだん情報がでてくると思うので、すぐに解消されるとは思います。エラーを報告したり、Pull Requestを送ったりして貢献しましょう！
　
### 2.2. Ansible

Chefの対抗で、シンプルさが売りのAnsibleです。チュートリアルをやりましたが、本当にシンプルですぐに開始することができました。しかし、私はRuby使いでPython使いではないことと、もう一度DSLを覚え直すのが面倒なこともあり、Chefからの鞍替えはできれば避けたいところです。

### 2.3. Chef-provisioning

さて、現状ではこれがいいかな。と思ったのは[Chef-privisioning](https://github.com/opscode/chef-provisioning)。元々RubyのDSLで、複数のマシンをプロビジョニングするための、Chef-Metalというツールが名前が変わったものです。これはChefからリリースされているものなので、ある程度いろんなケースがテストされているようです。サポートされているプラットフォームは、vagrant, aws, Digital Ocean, Dockerなどなど。Azureは一応ありますが、まだ本番には使うなよって書いてありました。サクラとかの場合は自分でプラグインを書く必要があるかもしれません。（サクラ派ではないので試していません、、、w）ですので、それ以外のクラウド使いの人は向いていないかもしれません。

  元々クラスタをプロビジョンするための仕組みなので、knife-zeroが充実する方が元々の意図をみたしやすいのでオススメですが、それまでの間、お手軽にできないんかいな！というときで、かつ上記のようなプラットフォームでしかレシピを流さない人は結構快適かもしれません。
  
  ですので、Chef-soloの代替えという用途では、若干邪道ですが、結果として、快適なので、しばしこの方法でいってみたいと思います。（ただし、壁にぶつかるかもしれませんが、保証はいたしかねますw)
  
[Chef Provisioning: Infrastructure As Code](https://www.chef.io/blog/2014/11/12/chef-provisioning-infrastructure-as-code/)
  
3. Chef-provisioningをつかったレシピ流し
---

だらだらといろいろ書きましたが、Chef-provisioningをつかったレシピ流しのためのチュートリアルを私含めた皆さんが慣れていないChefServerを扱う時のコマンド含めてご説明したいと思います。MacBookPro Yosemiteで動作確認しています。

### 3.1. Chefリポジトリの作成

最近はChefは[ChefDK](https://downloads.chef.io/chef-dk/mac/#/)というツールがリリースされています。これはdmgファイルになっていて、インストールすると、chefの各種ツールが入るようになっています。（実は私はあまりこの方法が好きではありません。Bundlerとかで柔軟に使える方がいいなと思います。実際それでもいいと思います。）

　方法はともかく、chefをインストールすると、chefリポジトリを作成します。ここでは名前をchef-zeroにしてみました。この後gitの管理下に置くとかするといいと思います。


```
$ chef generate repo chef-zero
$ cd chef-zero
```

ここでできるディレクトリ構造は[Chefを使う人のための、最低限のRuby関連知識](http://qiita.com/TsuyoshiUshio@github/items/28dcbe1a57da420e8096)というエントリに昔まとめてみましみましたので、慣れていない人は読んでみてください。

### 3.2. Gemfileの設定

次にGemfileを書いてみましょう。

```
source 'https://rubygems.org'

gem 'chef'
gem 'chef-zero'
gem 'berkshelf'
gem 'chef-provisioning'
gem 'chef-provisioning-vagrant'
```

こんな感じで、書いておきます。そして、実行しておきます。

```
$ bundle install
```

### 3.3. Local Modeの設定

Knifeのローカルモードを設定するためにはどうしたらいいでしょう？例えばknifeコマンドだと、`-z`コマンドでローカルモードになりますが、指定を忘れると謎挙動になりやすいとのことなので、ここは、`.chef/knife.rb`に設定をしておきましょう。これで、このリポジトリのディレクトリにいるときは、knifeコマンドのオプション指定が不要になります。(後述のchef-clientでは必要なので注意)

```
$ echo "local_mode true" >> .chef/knife.rb
```

### 3.4. Cookbookの作成

サンプルのために、なんらかのCookbookが必要です。今回の趣旨はここではないので、面倒なので、Berkshefを使ってさっとつくってしまいます。

Berksfileはこんな感じ。まずzshのクックブックをとってきます。

```
source "https://api.berkshelf.com"

cookbook 'zsh'
```

このコマンドを実行します。これで、cookbooks配下にZshのCookbookが格納されました。

```
$ bundle exec berks vendor cookbooks
```

### 3.5. Chef-provisioningの準備

こいつを、Vagrantで仮想マシンを立ててプロビジョニングを決めてみることにします。まず実施することは、環境変数の設定です。

```
$ export CHEF_DRIVER=vagrant
```

ちなみに、vagrantはこうですが、AWSだと例えばここが`fog:AWS`になったりします。詳しくは[本家のページ](https://github.com/opscode/chef-provisioning)をごらんください。

次に、chef-provisioning用のファイルを書きます。

vagrantの場合は、２つ書きます。どこでもいいのですが、私はprovisionというサブディレクトリを掘ってその下に置きました。

```
$ mkdir provision
$ vim provision/vagrant_linux.rb
```

vagrant_linux.rb　このファイルはvagrantの時は必要ですが、AWSの時は不要みたいです。

```
require 'chef/provisioning/vagrant_driver'

vagrant_box 'precise64' do
  url 'http://files.vagrantup.com/precise64.box'
end

with_machine_options :vagrant_options => {
  'vm.box' => 'precise64'
}

```
そして、プロビジョンをするマシンを記述するファイルです。ここでは`sample.rb`という名前にしてみました。この例では、sandayuuという名前の仮想マシンを１台立ち上げて、zshのレシピを流すというものです。タグ名もつけています。ちなみに、ここに複数台のマシンを書くことも当然可能です。

```
require 'chef/provisioning'

machine 'sandayuu' do
  recipe 'zsh'
  tag 'itsa_me'
  converge true
end
```

### 3.6. プロビジョニング

さて、vagrantの仮想マシンを立ち上げてChefを打ち込んで、レシピを流しましょう。普段なら、仮想マシンをvagrantで起動して、`vagrant ssh-config`をつかって、アクセスできるようにして、、、とかいろいろ面倒でしたが、これを使えば余裕です。

```
$ chef-client provision/vagrant.rb provision/sample.rb -z
```

はい、このコマンド一発で、provision/sample.rbの内容が反映されます。最後の　`-z`はLocal Mode指定ですね。自分は試していませんが、Vagrant+Chefの代表的謎挙動防止ポイントである、メモリ増やすとかの指定とかも、vagrant.rbとかの中の記述できっといけそうですね。

このコマンド一発で何が行われているかというと、、、

```
1. Chef-zeroのサーバーにレシピと、プロビジョニング先のマシンの情報を転送
2. Vagrantで仮想マシンを立ち上げ
3. 仮想マシンにsshで接続して、chefのクライアントをインストールする
4. 仮想マシンから、Chef-zeroサーバー（母艦で動作中）からレシピを取得
5. 仮想マシンで、レシピをchef-clientで実行して、プロビジョニング
```

という感じです。なんの問題もなくすんなり起動します。

もし、レシピとかにエラーがある場合も指示に従えばオッケーです。

ちなみに、現在Chef-zeroサーバーに対象の仮想マシンのノード(sandayuu)が登録されていることが、次のコマンドで確認できます。このコマンドはローカルのChef-zeroサーバーにアクセスしています。

```
$ knife node list
history.local
sandayuu
```
さらに、具体的な内容を見るためにはこんなコマンドです。

```
$ knife node show sandayuu
Node Name:   sandayuu
Environment: _default
FQDN:        sandayuu
IP:          10.0.2.15
Run List:    recipe[zsh]
Roles:       
Recipes:     zsh
Platform:    ubuntu 12.04
Tags:        itsa_me
```

これは、chef-solo時代にはなかった感じですね。あくまでサーバーで管理されているのです。
ローカルのインメモリですが。


### 3.7. レシピの変更と流し直し

さらにもう一歩すすめて、プロビジョニングした後にレシピを変更した場合を想定してみましょう。
単純に`apache2`のクックブックを追加してみるユースケースをやってみます。

最初に、Berksfileを変更して、クックブックを追加してみます。

```
source "https://api.berkshelf.com"

cookbook 'zsh'
cookbook 'apache2'
```

apache2を追加してみました。変更を反映しましょう。

```
$ bundle exec berks vendor cookbooks
```

これで、cookbooksの下にapache2のcookbookが追加になりました。こいつを反映してみます。

反映は簡単で、provision/sample.rbを変更しましょう。

```
require 'chef/provisioning'

machine 'sandayuu' do
  recipe 'zsh'
  recipe 'apache2'
  tag 'itsa_me'
  converge true
end
```

一行だけ追加しました。では、反映させましょう。先ほどと全く同じコマンドです。

```
$ chef-client provision/vagrant.rb provision/sample.rb -z
```

もうすでに仮想マシンは起動していますし、Chef-clientもインストールされていますので、変更部分のみが反映さてれいます。コンソールで確認できますが、念のためChef-zeroサーバーの情報も確認してみます。

```
$ knife node show sandayuu
Node Name:   sandayuu
Environment: _default
FQDN:        sandayuu
IP:          10.0.2.15
Run List:    recipe[zsh], recipe[apache2]
Roles:       
Recipes:     zsh, apache2, zsh::default, apache2::default, apache2::mod_status, apache2::mod_alias, apache2::mod_auth_basic, apache2::mod_authn_core, apache2::mod_authn_file, apache2::mod_authz_core, apache2::mod_authz_groupfile, apache2::mod_authz_host, apache2::mod_authz_user, apache2::mod_autoindex, apache2::mod_dir, apache2::mod_env, apache2::mod_mime, apache2::mod_negotiation, apache2::mod_setenvif, apache2::mod_rewrite, apache2::mod_deflate, apache2::mod_headers
Platform:    ubuntu 12.04
Tags:        itsa_me
```

こりゃ楽だわ。

### 3.8. その他の話題

さて、トラブルシューティング系ですが、ちょっと試しただけなのでわかりませんが、あまり苦労はしていません。tipsとしては、レシピを追加して削除したときに、実際のレシピは削除されていても、Chef-zeroサーバーに残っていて、プロビジョン先の仮想サーバーに反映されてしまってたということがありました。その時は、`knife node show`でChef-zeroサーバーの状態を確認して、`knife node run_list remove`で削除すれば反映されました。knife nodeコマンドは、いろいろchef-zeroの状態が確認・編集できて便利なので`knife node --help`で使い方を確認するのをお勧めします。

``` 
$ knife node show sandayuu
Node Name:   sandayuu
Environment: _default
FQDN:        sandayuu
IP:          10.0.2.15
Run List:    recipe[zsh], recipe[nginx], recipe[apache2]
Roles:       
Recipes:     zsh, nginx, apache2
Platform:    ubuntu 12.04
Tags:        itsa_me


$knife node run_list remove sandayuu recipe[nginx]

$ knife node show sandayuu
Node Name:   sandayuu
Environment: _default
FQDN:        sandayuu
IP:          10.0.2.15
Run List:    recipe[zsh], recipe[apache2]
Roles:       
Recipes:     zsh, apache2
Platform:    ubuntu 12.04
Tags:        itsa_me


```

### 3.9. 仮想サーバーへのログイン

さて、chef-provisioningは非常に便利ですが、仮想サーバーを勝手につくってくれるのはいいのですが、こいつにログインするにはどうしたらいいでしょう？作成したChefリポジトリの下にこっそりファイルができています。

```
$ cd .chef/
history:.chef 
$ ls
knife.rb		local-mode-cache	vms
$ cd vms/
$ ls
Vagrantfile	sandayuu.vm
```
このディレクトリまで降りて行って

```
$ vagrant ssh
```
でオッケーです。ここにあるxxx.vmが自動で作成されるVagrantファイルの実態です。尚、普通のsshで接続したいという場合は、方法は私はまだ知りませんが、chef-client -zを実行時に `-l debug`オプションをつけて実行するとsshで接続するポートとIPを見ることができます。

### 3.10. 作業ワークフローとテスト

Cookbookを作成中は、[ChefDK Getting Started](http://tcotav.github.io/chefdk_getting_started.html)にあるような感じで、testKitchenをつかってクックブックを個別にテストして作成が便利です。TestKitchenでも内部でChef-zeroが使われていますが、かなり快適に実行、テストができました。
　その後実際にプロビジョンするときにChef-provisionを使います。まだ、試せていませんが、Chef-provisionで作ったクラスターを試すためのTestKitchenプラグインがあります。[Kitchen-metal](https://github.com/doubt72/kitchen-metal)これを使えば、クラスタごとテストが書けるので強力そうですね。またためしてみたいです。

4. おわりに
---

さて、どうでしたか？[Chef Provisioning: Infrastructure As Code](https://www.chef.io/blog/2014/11/12/chef-provisioning-infrastructure-as-code/)ではさらに、複数マシンやロードバランサの書き方も載っていました。

codeでたくさんのマシンをコントロールするのは相当気持ちいですね！

では、良いお年を！