Chef-clientとKnife-zeroを触ってみた記録

新卒エンジニアがChef-clientとknife-zeroを使ってみた記録です。
まだまだ勉強中なのですが、Chef-zeroに関してだったり、情報が色々あって混沌としていたのでまとめてみました。

『初めてChefを触るぜ!!』という読者が、最終的には『リモートサーバーの環境設定、管理をChefでやってみよう!!』と思えるようになることがこの投稿の目標です。

## 1. Chef(シェフ)って?
### コードでサーバー環境を整備、管理するツール
[本家](https://www.chef.io/chef/)によると
> Chefはインフラをコードにする。Chefを使えば、ビルドやデプロイ、インフラのマネジメントを自動で行うことができる。するとアプリケーションのコードのようにインフラがバージョン管理やテスト、繰り返し可能になるぜ!!

⊂二二二(　^ω^)二⊃ブーン
なるほど!!
つまりミスが減るのか(ざっくり...)!!
自動でというのがキーですねw

これまでの環境整備と管理は、サーバーにSSHなどでログインし、人が手順書に従って１つずつ作業してました。

* スペルミス
* 時間がかかる(一つの作業もですが、サーバーが増えると...)
* 手順書の更新忘れ
* あれっどこまでやってたっけ?ってなる

といった問題が考えられます(他にもいろいろ)。
以上の問題をコードを実行して **自動化** することで、解決しようというツールです。
問題を経験したことがない人はぜひドットインストールで[さくらVPSの設定](http://dotinstall.com/lessons/basic_sakura_vps)を[開発環境](http://dotinstall.com/lessons/basic_localdev_mac)で行ってみてください。

## 2. 実際に触ってみる
ゴールは『サーバーにSSHログインせずに、Chefコマンドをリモート実行で環境整備・管理』することですが、まずはゲストOS上に『SSHログインしてみて、Chefコマンドを叩いて環境整備・管理』を実行してみます。

### 2-1. 仮想環境の準備(VirtualBoxとVagrant)
サンプル実行時の環境は

* MacOSX(Yosemite:10.10.3)(ホストOS)
* VirtualBox(4.3.26)
* Vagrant(1.6.5)
* CentOS6.6(ゲストOS)

VirtualBoxとVagrantに関しては[他の記事](http://qiita.com/MasahiroSakoda/items/9da5e20baed653bcd8b1)をどうぞ!!

Mac上でターミナルを開き作業をはじめます。

'''bash
$ mkdir testchef01
$ cd testchef01
```

Vagrantfileを以下のように作成し

```ruby:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "opscode-centos-6.6"
  config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/vmware/opscode_centos-6.6_chef-provisionerless.box"
  config.vm.network "private_network", ip: "192.168.33.100"
end
```

仮想環境を立ち上げます。

```bash
$ vagrant up
```

これで仮想環境が立ち上がりました。
次にsshでログインを行います。

```bash
$ vagrant ssh
```

### 2-2. Chef-dk(Chef-DevelopmentKit)の導入 
ゲストOSにchef-dkを導入します

```bash
$ curl -O https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chefdk-0.5.1-1.el6.x86_64.rpm
```
気長に待ちます...
ダウンロードできたら

```bash
sudo rpm -Uvh chefdk-0.5.1-1.el6.x86_64.rpm
```

これで必要なツールはすべてインストールされました。

### 2-3. Chefを使ってみる
ここでは基本的なChefの機能を触ってみます。  
まずはChefのリポジトリを作ります。  

```bash
$ chef generate repo chef-repo
$ cd chef-repo
```

chef-repo/をホームとして作業を進めていきます。
続いてクックブックというものを作成します。
クックブックはツールをインストールする際に必要になるデータやファイルをまとめたディレクトリです。
今回はapacheをインストールして起動してみます。

```bash
$ chef exec knife cookbook create apache -o cookbooks
```

これでcookbooksの中にapacheという名前のクックブックが作成されました。
それではレシピを編集していきます。
レシピはサーバー設定の手順書のようなものです。

```bash:cookbooks/apache/recipes/default.rb
package "httpd" do
  action :install
end

service "httpd" do
  action [ :enable, :start ]
end
```

httpdをインストールして、起動してねと書いてます。
package、 service等をリソースといいます。
では実行して実際にレシピを適用してみます。
その前にどのレシピを使うかChefに教えてあげる必要があります。
json形式でファイルを作成します。

```json:centos.json
{
  "run_list":[
    "recipe[apache]"
  ]
}
```

新しくレシピを追加したら、ここに追加してから実行する必要があります。
結構忘れるので気をつけてくださいw
では今度こそ実行します。

```bash
$ sudo chef exec chef-client --local-mode -j centos.json
```

完了したらブラウザで192.168.33.100にアクセスしてみてください。
apacheのテストページが表示されていればOKです。
  
  
続いてアトリビュートという機能を使ってみます。 
これは、レシピに汎用性を持たせるために変数が使えるよという機能です。
mysqlを入れてみます。

```bash
$ chef exec knife cookbook create mysql -o cookbooks
```

mysqlのクックブックのひな形ができました。
レシピを作ります。

```ruby:cookbooks/mysql/recipes/default.rb
%w{mysql mysql-server}.each do |pkg|
  package pkg do
    action :install
  end
end

service "mysqld" do
  action [ :enable, :start ]
end

execute "set root password" do
  command "mysqladmin -u root password '#{node['mysql']['server_root_password']}'"
  only_if "mysql -u root -e 'show databases;'"
end
```

12行目にある\#{node['mysql']['server_root_password']}はRubyの変数展開です。
ではこの変数を設定します。
ファイルを作成します。

```ruby:cookbooks/mysql/attributes/default.rb
default['mysql']['server_root_password'] = "password"
```

これでmysqlのクックブックができました。
ではcentos.jsonに追加します。

```json:centos.json
{
  "run_list":[
    "recipe[apache]",
    "recipe[mysql]"
  ]
}
```

run_listに追加したら実行します。

```bash
$ sudo chef exec chef-client --local-mode -j centos.json
```

mysqlがインストールされて、mysql -u root -ppasswordでmysqlのコンソールに入ることができるようになりました。

この項の最後としてテンプレートという機能を使ってみます。
設定ファイル等を予め準備しておいて、書き込みを行う機能です。
iptablesの設定を例に作ってみたいと思います。

```bash
$ chef exec knife cookbook create iptables -o cookbooks
```

レシピを記述していきます。

```ruby:cookbooks/iptables/recipes/default.rb
template "/etc/sysconfig/iptables" do
  source "iptables.erb"
  owner "root"
  group "root"
  mode 0644
end

service "iptables" do
  action [ :enable, :start ]
  supports :status => true, :restart => true
end
```

templateというリソースが出てきました。
/etc/sysconfig/iptablesファイルにiptables.erbを適用するという意味を持ってます。
iptables.erbを作成します。

```bash:cookbooks/iptables/template/default/iptables.erb
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:SERVICES -    [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -j SERVICES
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p udp --sport 123 --dport 123 -j ACCEPT
-A SERVICES -p tcp --dport 22 -j ACCEPT
-A SERVICES -p tcp --dport 80 -j ACCEPT
-A SERVICES -p tcp --dport 443 -j ACCEPT
COMMIT
```

内容については[さくらVPSの設定](https://help.sakura.ad.jp/app/answers/detail/a_id/2423)で確認してください。  

erbということなのでテンプレート内でもアトリビュート機能は使えます。  
今回は使いませんが...
ではcentos.jsonにiptablesを追加して、chefを実行します。  

```json:centos.json
{
  "run_list":[
    "recipe[apache]",
    "recipe[mysql]",
    "recipe[iptables]"
  ]
}
```

```bash
$ sudo chef exec chef-client --local-mode -j centos.json
```

iptables -Lコマンドで設定が適用されているのが確認できます。
  
この節では
sshログインを行ってサーバー上でChefコマンドを叩いて環境設定を行いました。
これらの設定を次はサーバーにSSHログインせずに、Chefコマンドをリモート実行して環境整備・管理を行いました。

ではexitコマンドでホストに戻って下さい

## 3. リモートサーバーの環境設定をしてみる
上記の2、3の部分をリモート実行によって行えば目的は達成できます。
それを可能にするchefクライアントがknife-zeroです。

ではMac上にchef-dkをインストールします。
https://opscode-omnibus-packages.s3.amazonaws.com/mac_os_x/10.8/x86_64/chefdk-0.5.1-1.dmg  
待ちます...
ダウンロードが完了したら、実行してください。
ツールのインストールが始まります。

インストールが完了すればターミナルに戻ってknife-zeroを入れます。

```bash
$ chef gem install knife-zero
```

これでknife-zeroが入りました。
新しく作業ディレクトリを作ります。

```bash
$ cd ~
$ mkdir testchef02
$ cd testchef02
```

再びVagrantfileを作成します。
ipの値を2-3で使ったファイルとは違う値にしているので気をつけてください。

```bash:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "opscode-centos-6.6"
  config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/vmware/opscode_centos-6.6_chef-provisionerless.box"
  config.vm.network "private_network", ip: "192.168.33.101"
end
```

vagrant upで立ち上げます。
少し雰囲気を出すためにhostsを編集します。

```bash
$ sudo vi /etc/hosts
#最後の行に以下の一行を追加
192.168.33.101 testchef01.com
```

2-3で作成したchef-repoを引っ張ってきます。

```bash
$ git clone https://github.com/Islands5/chefsample01.git
$ cd chefsample01
```

ここをメインに作業を行います。
設定ファイルを書きます。

```bash
$ mkdir .chef
$ echo 'local_mode true' >> .chef/knife.rb
```

2-3では使いませんでしたが、ロールというものを使います。
説明は後ほど...
role/example.jsonを開いてみてください

```role/example.json
{
    "name": "example",
    "description": "This is an example role defined as JSON",
    "chef_type": "role",
    "json_class": "Chef::Role",
    "default_attributes": {
    },
    "override_attributes": {
    },
    "run_list": [
        "recipe[example]"
    ]
}
```

run_listの部分を編集し、recipeを追加していきます。

```json:role/example.json
#編集
    "run_list": [
        "recipe[apache]",
        "recipe[mysql]",
        "recipe[iptables]"
    ]
#
```

それではサーバーに適用します。

```bash
$ chef exec knife zero bootstrap testchef01.com -x vagrant -Pvagrant --sudo -r 'role[example]'
```

少し待ちます。
完了すれば、ブラウザでtestchef01.comにアクセスするとapacheのテストページが確認できます!!

-xはユーザー名
-Pはパスワード(鍵認証を使った設定方法もあります)
--sudoはリモートサーバー上でsudo権限で実行してねという指示(つまりパスワードなしでsudoできる権限をもったユーザーじゃないと実行できない)
-rはroleかrecipeを適用するのですが、今回はroleを渡しました。

ロールは、アプリサーバーやデータベースサーバーといった役割の違いを役割別にレシピをまとめておく機能
今回はただ単にまとめてレシピを記述できるという点に着目して使いました。

以上が今回調べてみてわかったことです。

## 4. まとめ
『初めてChefを触るぜ!!』という読者が、最終的には『リモートサーバーの環境設定、管理をChefでやってみよう!!』と思えるようになることを目標に記事を作成しました。
仮想環境を使って『SSHログインしてみて、Chefコマンドを叩いて環境整備・管理』することからスタートします。その際、chefの便利な機能の一部として、パッケージのインストール、アトリビュートの適用、テンプレートの適用を触ってみました。最後にメインである『サーバーにSSHログインせずに、Chefコマンドをリモート実行で環境整備・管理』を行いました。
同じ手法を用いることで、ドメイン名がわかっているホスト+sudoをパスワードなしで実行できる権限を持ったユーザー(リモート上で)があればリモート実行が可能になります。
次はさくらVPSに対して行ってみようと思っています。
また、今回はクックブックを作成しましたが、Berkshelfを使えば有志が作ったクックブックを使うことができます。

## 5. あとがき
本投稿では触れなかったchef-soloやknife-soloに関しての今後は[こちらの記事](http://www.creationline.com/lab/9840)が大変わかりやすいです。
記事によるとknife-soloから乗り換えを急ぐ必要は無いとということです。なぜならknife-soloも内部でChef-clientローカルモードを利用するように検討されているそうです。みんなknife-soloはchef-soloと心中しないぞ!!

今日もいい天気だ＼(^o^)／


## 用語集
**クックブック**
レシピやテンプレート、アトリビュート等をまとめたフォルダ
**レシピ**
リソースを並べたRubyコード、環境構築の手順書
**リソース**
package、service、execute、templateといったサーバーの状態を記述している命令
**テンプレート**
設定ファイル等を予め準備しておいて、書き込みを行う機能
**アトリビュート**
レシピに汎用性を持たせるために変数が使えるよという機能
**ロール**
アプリサーバーやデータベースサーバーといった役割の違いを役割別にレシピをまとめておく機能
**ノード**
サーバーのことをノードといったりします

## 参考資料
### サイト
Chef-SoloからChef-Clientローカルモードへの移行: http://www.creationline.com/lab/6380
Chef-dkを使ってみよう: http://www.creationline.com/lab/6255
knife-zero: https://github.com/higanworks/knife-zero
knife-zeroでInfrastructure as Codeを始めよう: http://www.creationline.com/lab/6718
chef界隈のまとめ: http://www.creationline.com/lab/9840
技術的な文章を書くための1,2,3歩: http://qiita.com/vvakame/items/d657baf26cf83ac98bd0


### 書籍
Chef実践入門