fbpx

Knife-ZeroでInfrastructure as Codeを始めよう #getchef

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本稿はChef Advent Calendar 201424日目の記事です。

Chefとは

Chefとは、インフラの情報を集中管理するツールです。An Overview of Chefでは次のように述べられています。

Chef is a powerful automation platform that transforms complex infrastructure into code, bringing your servers and services to life. (略)

Chef is built around simple concepts: achieving desired state, centralized modeling of IT infrastructure, and resource primitives that serve as building blocks. (略)

[和訳] Chefは複雑なインフラをコードに変換し、サーバやサービスを生きた状態とする、強力な自動化プラットフォームです。(略)

Chefは単純な概念で成り立っています: 望ましい状態に到達させる。ITインフラの中央集権的なモデルとなる。リソースの根源的要素を組み立てブロックのように扱う。(略)

インフラの情報を集中管理し、インフラの各要素を細かい部品に分けて再利用できるようにし、各要素をあるべき状態に収束させることがChefの真価です。

Chefで見逃されがちなのが インフラの情報を集中管理 の部分です。ここを見ずに単なる自動セットアップツールとしてChefを用いてもよいけれど、それはもったないでしょう。

Chefのインストール

では、さっそくChefをインストールしてみましょう。今回はChef Serverは必要ありません。Ubuntu 12.04 LTSをワークステーションとして、クライアントパッケージのみをインストールします。
また、管理する対象のリモートノードもUbuntu 12.04 LTSとします。

Chef Development Kitのインストール

ワークステーション用のクライアントパッケージはChef Development Kit、通称Chef DKと呼ばれています。Chefのクライアントプログラムだけでなく、Chefで開発を行うための各種ツールや、Chefを動作させるためのRubyまで同梱しています。そのため、別途Rubyをインストールしたり、RubyGemsでChefをインストールする必要はまったくありません

Chef DKはChef Development Kit | Chef Downloads | Chefからダウンロードできます。OS、Chef DKのバージョン、OSのバージョンを選択し、ダウンロードしましょう。今回は chefdk_0.3.5-1_amd64.deb をダウンロードしました。早速インストールしましょう。


ubuntu@ws:~$ sudo dpkg -i chefdk_0.3.5-1_amd64.deb
以前に未選択のパッケージ chefdk を選択しています。
(データベースを読み込んでいます ... 現在 49102 個のファイルとディレクトリがインストールされています。)
(chefdk_0.3.5-1_amd64.deb から) chefdk を展開しています...
chefdk (0.3.5-1) を設定しています ...
Thank you for installing Chef Development Kit!
ubuntu@ws:~$

Knife-Zeroのインストール

ChefクライアントプログラムはChef DK付属のものではなく、Knife-Zeroを利用します。


ubuntu@ws:~$ chef gem install knife-zero --no-document
Fetching: knife-zero-1.1.0.gem (100%)
WARNING: You don't have /home/ubuntu/.chefdk/gem/ruby/2.1.0/bin in your PATH,
gem executables will not run.
Successfully installed knife-zero-1.1.0
1 gem installed
ubuntu@ws:~$

警告はKnife-Zeroには関係ないので無視してかまいません。

SSHキーペアの作成など下準備

Knife-ZeroはSSHを利用してリモートノードの操作を行うので、SSH秘密鍵・公開鍵のペアを作成しておきます。ここではパスフレーズなしの鍵ペアを作成しています。


ubuntu@ws:~$ ssh-keygen -N ''
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa):
Created directory '/home/ubuntu/.ssh'.
Your identification has been saved in /home/ubuntu/.ssh/id_rsa.
Your public key has been saved in /home/ubuntu/.ssh/id_rsa.pub.
The key fingerprint is:
9a:72:67:23:3a:5c:2e:e9:74:03:44:0f:5e:87:0e:67 ubuntu@ws.example.jp
The key's randomart image is:
+--[ RSA 2048]----+
| o ... |
| o.+E. |
| o=. |
| . . |
| . S |
| ..o |
| .o+B + |
| .==.= . |
| .oo |
+-----------------+
ubuntu@ws:~$

当然ながら、対象のリモートノードはSSHデーモンが動作している必要があるので起動しておきます。また、先に作成した公開鍵をリモートノードにあらかじめ配置します。


ubuntu@node:~$ mkdir .ssh
ubuntu@node:~$ cat > .ssh/authorized_keys
ssh-rsa (省略) ubuntu@ws.example.jp
ubuntu@node:~$

加えて簡便のために、パスワードなしでsudoを実行してroot権限を得られるように、ログインアカウントに設定しておきましょう。

作業環境を作る

Knife-Zeroを実行する環境とするディレクトリツリーを作り、gitの管理下に置いておきます。このディレクトリツリーはchef-repoと呼ばれ、インフラをコード化したものとなります。


ubuntu@ws:~$ chef generate repo chef-repo
Compiling Cookbooks...
Recipe: code_generator::repo
* directory[/home/ubuntu/chef-repo] action create
- create new directory /home/ubuntu/chef-repo
:
(diff output suppressed by config)
ubuntu@ws:~$

ubuntu@ws:~$ cd chef-repo
ubuntu@ws:~/chef-repo$ tree
.
├── LICENSE
├── README.md
├── Rakefile
├── certificates
│ └── README.md
├── chefignore
├── config
│ └── rake.rb
├── cookbooks
│ └── README.md
├── data_bags
│ └── README.md
├── environments
│ └── README.md
└── roles
└── README.md

6 directories, 10 files
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ git init
Initialized empty Git repository in /home/ubuntu/chef-repo/.git/
ubuntu@ws:~/chef-repo$

これからKnife-Zeroで管理すると示す設定ファイルを準備しておきます。


ubuntu@ws:~/chef-repo$ mkdir .chef
ubuntu@ws:~/chef-repo$ echo 'local_mode true' > .chef/knife.rb
ubuntu@ws:~/chef-repo$ cat .chef/knife.rb
local_mode true
ubuntu@ws:~/chef-repo$

ノードへChefクライアントのインストール

リモートノードへChefクライアントをインストールし、Chefの管理対象とします。
knife zero bootstrapがコマンド、node.example.jpがノードのホスト名、-x ubuntuがログインユーザ名の指定、--sudoがsudoコマンドにてroot権限を取得するという意味となります。


ubuntu@ws:~/chef-repo$ knife zero bootstrap node.example.jp -x ubuntu --sudo
Connecting to node.example.jp
node.example.jp Installing Chef Client...
node.example.jp --2014-12-19 12:06:20-- https://www.opscode.com/chef/install.sh
node.example.jp www.opscode.com (www.opscode.com) をDNSに問いあわせています... 184.106.28.90
node.example.jp www.opscode.com (www.opscode.com)|184.106.28.90|:443 に接続しています... 接続しました。
node.example.jp HTTP による接続要求を送信しました、応答を待っています... 200 OK
node.example.jp 長さ: 18285 (18K) [application/x-sh]
node.example.jp `STDOUT' に保存中
node.example.jp
100%[======================================>] 18,285 --.-K/s 時間 0.002s
node.example.jp
node.example.jp 2014-12-19 12:06:21 (7.52 MB/s) - stdout へ出力完了 [18285/18285]
node.example.jp
node.example.jp Downloading Chef 11 for ubuntu...
node.example.jp downloading https://www.opscode.com/chef/metadata?v=11&prerelease=false&nightlies=false&p=ubuntu&pv=12.04&m=x86_64
node.example.jp to file /tmp/install.sh.1100/metadata.txt
node.example.jp trying wget...
node.example.jp url https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chef_11.16.4-1_amd64.deb
node.example.jp md5 2ffff5b4d80e4dcffc917f8eb2003a31
node.example.jp sha256 28b08975e7e33ac46c888616ec7fa232a0c624aeeda81e58a6047d2c6b62edfb
node.example.jp downloaded metadata file looks valid...
node.example.jp downloading https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chef_11.16.4-1_amd64.deb
node.example.jp to file /tmp/install.sh.1100/chef_11.16.4-1_amd64.deb
node.example.jp trying wget...
node.example.jp Comparing checksum with sha256sum...
node.example.jp Installing Chef 11
node.example.jp installing with dpkg...
node.example.jp 以前に未選択のパッケージ chef を選択しています。
(データベースを読み込んでいます ... 現在 49102 個のファイルとディレクトリがインストールされています。)
node.example.jp (.../chef_11.16.4-1_amd64.deb から) chef を展開しています...
node.example.jp chef (11.16.4-1) を設定しています ...
node.example.jp Thank you for installing Chef!
node.example.jp Starting first Chef Client run...
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp Creating a new client identity for node.example.jp using the validator key.
node.example.jp resolving cookbooks for run list: []
node.example.jp Synchronizing Cookbooks:
node.example.jp Compiling Cookbooks...
node.example.jp [2014-12-19T12:06:48+09:00] WARN: Node node.example.jp has an empty run list.
node.example.jp Converging 0 resources
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 0/0 resources updated in 1.443860973 seconds
ubuntu@ws:~/chef-repo$

自動的にChefクライアントをダウンロードし、ノードにインストールされました。
そして、ノードをChef管理対象に置きました。Chef Serverではなく、ワークステーションのChef-Repoディレクトリ内に管理情報が格納される形となっています。


ubuntu@ws:~/chef-repo$ cat clients/node.example.jp.json | cat
{
"name": "node.example.jp",
"public_key": "-----BEGIN PUBLIC KEY-----\n(省略)\n-----END PUBLIC KEY-----\n"
}
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ cat nodes/node.example.jp.json
{
"name": "node.example.jp",
"normal": {
"tags": [

]
},
"automatic": {
"network": {
"interfaces": {
"lo": {
"mtu": "16436",
"flags": [
"LOOPBACK",
"UP",
"LOWER_UP"
],
"encapsulation": "Loopback",
"addresses": {
"127.0.0.1": {
"family": "inet",
"prefixlen": "8",
"netmask": "255.0.0.0",
"scope": "Node"
},
"::1": {
"family": "inet6",
"prefixlen": "128",
"scope": "Node"
}
},
"state": "unknown"
},
"eth0": {
"type": "eth",
"number": "0",
"mtu": "1500",
"flags": [
"BROADCAST",
"MULTICAST",
"UP",
"LOWER_UP"
],
"encapsulation": "Ethernet",
"addresses": {
"52:54:00:8E:F7:2A": {
"family": "lladdr"
},
"192.168.122.67": {
"family": "inet",
"prefixlen": "24",
"netmask": "255.255.255.0",
"broadcast": "192.168.122.255",
"scope": "Global"
},
"fe80::5054:ff:fe8e:f72a": {
"family": "inet6",
"prefixlen": "64",
"scope": "Link"
}
},
"state": "up",
"arp": {
"192.168.122.209": "52:54:00:62:c3:07"
},
:
"recipes": [

],
"roles": [


]
}
}
ubuntu@ws:~/chef-repo$

ついでにワークステーション自体も登録してしまいましょう。


ubuntu@ws:~/chef-repo$ knife zero bootstrap ws.example.jp -x ubuntu --sudo
Connecting to ws.example.jp
ws.example.jp Starting first Chef Client run...
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp Creating a new client identity for ws.example.jp using the validator key.
ws.example.jp resolving cookbooks for run list: []
ws.example.jp Synchronizing Cookbooks:
ws.example.jp Compiling Cookbooks...
ws.example.jp [2014-12-19T12:33:12+09:00] WARN: Node ws.example.jp has an empty run list.
ws.example.jp Converging 0 resources
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 0/0 resources updated in 1.627046827 seconds
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ ls -l clients
合計 8
-rw-rw-r-- 1 ubuntu ubuntu 511 12月 19 12:06 node.example.jp.json
-rw-rw-r-- 1 ubuntu ubuntu 509 12月 19 12:33 ws.example.jp.json
ubuntu@ws:~/chef-repo$ ls -l nodes
合計 64
-rw-rw-r-- 1 ubuntu ubuntu 31169 12月 19 12:23 node.example.jp.json
-rw-rw-r-- 1 ubuntu ubuntu 31157 12月 19 12:33 ws.example.jp.json
ubuntu@ws:~/chef-repo$

以降、Knife-Zeroによって、ノードを管理していきます。

knifeコマンドでノードを管理する

knifeコマンドで登録した情報の取得を行ってみます。knife searchを用います。次はノードのIPアドレスを取得する例です。


ubuntu@ws:~/chef-repo$ knife search 'name:*' --attribute ipaddress
2 items found

node.example.jp:
ipaddress: 192.168.122.67

ws.example.jp:
ipaddress: 192.168.122.209


ubuntu@ws:~/chef-repo$

これらはChef-Repoに格納されらデータから表示しています。

引数を操作することで、個々のノードの情報も表示ができます。


ubuntu@ws:~/chef-repo$ knife search 'name:node*' --attribute fqdn
1 items found

node.example.jp:
fqdn: node.example.jp

ubuntu@ws:~/chef-repo$ knife search 'name:ws*' --attribute fqdn
1 items found

ws.example.jp:
fqdn: ws.example.jp


ubuntu@ws:~/chef-repo$

knife sshで各ノードに対してリモートからコマンドを実行できます。


ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'uname -a'
node.example.jp Linux node.example.jp 3.2.0-74-generic #109-Ubuntu SMP Tue Dec 9 16:45:49 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
ws.example.jp Linux ws.example.jp 3.2.0-74-generic #109-Ubuntu SMP Tue Dec 9 16:45:49 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
ubuntu@ws:~/chef-repo$

クックブックを作る

インフラをコード化してあるべき状態を記述したChefのファイルをクックブックと呼びます。クックブックはRubyを知らなくても書けます。クックブックがRubyの内部DSLというのは一旦忘れましょう。知るべきことはクックブックの書き方だけでいいのです。

パッケージを1つインストールする

ntpパッケージをインストールするクックブックを作ってみましょう。
chef generate cookbookコマンドを使うと、クックブックの雛形を用意してくれます。クックブックの名前は「ntp」とします。


ubuntu@ws:~/chef-repo$ chef generate cookbook cookbooks/ntp
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[/home/ubuntu/chef-repo/cookbooks/ntp] action create
- create new directory /home/ubuntu/chef-repo/cookbooks/ntp
:
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ tree cookbooks/ntp
cookbooks/ntp
├── Berksfile
├── README.md
├── chefignore
├── metadata.rb
└── recipes
└── default.rb


1 directory, 5 files
ubuntu@ws:~/chef-repo$

cookbooks/ntp/recipes/default.rbは「ntpクックブック」の「defaultレシピ」と言います。通常、クックブックとはレシピ以外を含めたさまざまなデータの集合体を表すものですが、おおざっぱに同一視してしまってもだいたい通じます。
では編集してntpパッケージをインストールするようにしましょう。


#
# Cookbook Name:: ntp
# Recipe:: default
#
# Copyright (c) 2014 The Authors, All Rights Reserved.


package 'ntp'

これだけです。元々あるコメントを除けば1行付け足しただけです。Ruby要素はどこにもありません。

このレシピを適用したいノードに登録します。


ubuntu@ws:~/chef-repo$ knife node run_list add node.example.jp 'recipe[ntp]'
node.example.jp:
run_list: recipe[ntp]
ubuntu@ws:~/chef-repo$ knife node run_list add ws.example.jp 'recipe[ntp]'
ws.example.jp:
run_list: recipe[ntp]
ubuntu@ws:~/chef-repo$

ノードでChefクライアントを実行して実際に適用する前に-Wオプションでwhy-run (dry-runのようなもの)してみます。


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo -W
node.example.jp [2014-12-22T13:09:25+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp Compiling Cookbooks...
node.example.jp Converging 1 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install
node.example.jp - Would install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
node.example.jp [2014-12-22T13:09:26+09:00] WARN: In whyrun mode, so NOT performing node save.
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 1/1 resources would have been updated
ws.example.jp [2014-12-22T13:09:27+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 1 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install
ws.example.jp - Would install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
ws.example.jp [2014-12-22T13:09:28+09:00] WARN: In whyrun mode, so NOT performing node save.
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 1/1 resources would have been updated
ubuntu@ws:~/chef-repo$

ntpパッケージがインストールされることがわかります。では-Wオプションを取り除いて実際にレシピを適用し、ノードをあるべき状態に収束します。


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T13:14:00+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp Compiling Cookbooks...
node.example.jp Converging 1 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install
node.example.jp - install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 1/1 resources updated in 9.409252235 seconds
ws.example.jp [2014-12-22T13:14:11+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 1 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install
ws.example.jp - install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 1/1 resources updated in 10.834032539 seconds
ubuntu@ws:~/chef-repo$

レシピの適用が成功し、1/1 resources updatedで表されている通り、ノードの1リソース中1つのリソースに変更があったことを示しています。べき等性の確認のためもう1回適用してみます。


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T13:18:52+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp Compiling Cookbooks...
node.example.jp Converging 1 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 0/1 resources updated in 0.991954497 seconds
ws.example.jp [2014-12-22T13:18:55+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 1 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 0/1 resources updated in 1.050684551 seconds
ubuntu@ws:~/chef-repo$

0/1 resources updatedで表されている通り、ノードの1リソース中どのリソースにも変更がなかったことを示しています。

さらにべき等性の確認のため、パッケージをアンインストールしてもう1回実行してみます。


ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'sudo apt-get purge -y ntp' -x ubuntu
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
ws.example.jp 以下のパッケージが自動でインストールされましたが、もう必要とされていません:
ws.example.jp libopts25 libcap2
ws.example.jp これらを削除するには 'apt-get autoremove' を利用してください。
ws.example.jp 以下のパッケージは「削除」されます:
ws.example.jp ntp*
ws.example.jp アップグレード: 0 個、新規インストール: 0 個、削除: 1 個、保留: 1 個。
ws.example.jp この操作後に 1,511 kB のディスク容量が解放されます。
(データベースを読み込んでいます ... 現在 100642 個のファイルとディレクトリがインストールされています。)
ws.example.jp ntp を削除しています ...
ws.example.jp * Stopping NTP server ntpd [ OK ]
ws.example.jp ntp の設定ファイルを削除しています ...
ws.example.jp man-db のトリガを処理しています ...
ws.example.jp ureadahead のトリガを処理しています ...
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
node.example.jp 以下のパッケージが自動でインストールされましたが、もう必要とされていません:
node.example.jp libopts25 libcap2
node.example.jp これらを削除するには 'apt-get autoremove' を利用してください。
node.example.jp 以下のパッケージは「削除」されます:
node.example.jp ntp*
node.example.jp アップグレード: 0 個、新規インストール: 0 個、削除: 1 個、保留: 1 個。
node.example.jp この操作後に 1,511 kB のディスク容量が解放されます。
(データベースを読み込んでいます ... 現在 61224 個のファイルとディレクトリがインストールされています。)
node.example.jp ntp を削除しています ...
node.example.jp * Stopping NTP server ntpd [ OK ]
node.example.jp ntp の設定ファイルを削除しています ...
node.example.jp man-db のトリガを処理しています ...
node.example.jp ureadahead のトリガを処理しています ...
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T13:25:47+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp Compiling Cookbooks...
node.example.jp Converging 1 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install
node.example.jp - install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 1/1 resources updated in 5.015853954 seconds
ws.example.jp [2014-12-22T13:25:54+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 1 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install
ws.example.jp - install version 1:4.2.6.p3+dfsg-1ubuntu3.1 of package ntp
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 1/1 resources updated in 5.624764122 seconds
ubuntu@ws:~/chef-repo$

1/1 resources updatedで表されている通り、再びレシピの適用に成功してリソースの更新が行われました。

なお、Chef-Repoディレクトリのnodes/ディレクトリの情報は、Chefクライアントの実行などで更新が行われています。


ubuntu@ws:~/chef-repo$ git diff
diff --git a/nodes/node.example.jp.json b/nodes/node.example.jp.json
index d90e315..03bea39 100644
--- a/nodes/node.example.jp.json
+++ b/nodes/node.example.jp.json
:
@@ -1207,11 +1208,11 @@
},
"current_user": "ubuntu",
"root_group": "root",
- "ohai_time": 1418959381.048563,
- "uptime_seconds": 2566,
- "uptime": "42 minutes 46 seconds",
- "idletime_seconds": 2528,
- "idletime": "42 minutes 08 seconds",
+ "ohai_time": 1419222348.6213446,
+ "uptime_seconds": 5229,
+ "uptime": "1 hours 27 minutes 09 seconds",
+ "idletime_seconds": 5154,
+ "idletime": "1 hours 25 minutes 54 seconds",
"block_device": {
"ram0": {
"size": "131072",
@@ -1316,10 +1317,14 @@
}
},
"recipes": [
-
+ "ntp",
+ "ntp::default"
],
"roles": [

]
- }
+ },
+ "run_list": [
+ "recipe[ntp]"
+ ]
}
diff --git a/nodes/ws.example.jp.json b/nodes/ws.example.jp.json
index 09b10d6..099b1af 100644
--- a/nodes/ws.example.jp.json
+++ b/nodes/ws.example.jp.json
:
@@ -1207,11 +1208,11 @@
},
"current_user": "ubuntu",
"root_group": "root",
- "ohai_time": 1418959992.8692613,
- "uptime_seconds": 3175,
- "uptime": "52 minutes 55 seconds",
- "idletime_seconds": 3127,
- "idletime": "52 minutes 07 seconds",
+ "ohai_time": 1419222354.9337227,
+ "uptime_seconds": 5235,
+ "uptime": "1 hours 27 minutes 15 seconds",
+ "idletime_seconds": 5117,
+ "idletime": "1 hours 25 minutes 17 seconds",
"block_device": {
"ram0": {
"size": "131072",
@@ -1316,10 +1317,14 @@
}
},
"recipes": [
-
+ "ntp",
+ "ntp::default"
],
"roles": [


]
- }
+ },
+ "run_list": [
+ "recipe[ntp]"
+ ]
}
ubuntu@ws:~/chef-repo$

パッケージを複数インストールする

nginxパッケージとredis-serverパッケージをインストールするクックブックを作ってみましょう。


ubuntu@ws:~/chef-repo$ chef generate cookbook cookbooks/multi_pkgs
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[/home/ubuntu/chef-repo/cookbooks/multi_pkgs] action create
- create new directory /home/ubuntu/chef-repo/cookbooks/multi_pkgs
:
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ vi cookbooks/multi_pkgs/recipes/default.rb
#
# Cookbook Name:: multi_pkgs
# Recipe:: default
#
# Copyright (c) 2014 The Authors, All Rights Reserved.


package 'nginx'
package 'redis-server'
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife node run_list add node.example.jp 'recipe[multi_pkgs]'
node.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
ubuntu@ws:~/chef-repo$ knife node run_list add ws.example.jp 'recipe[multi_pkgs]'
ws.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T16:23:51+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp - multi_pkgs
node.example.jp Compiling Cookbooks...
node.example.jp Converging 3 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install
node.example.jp - install version 1.1.19-1ubuntu0.6 of package nginx
node.example.jp * package[redis-server] action install
node.example.jp - install version 2:2.2.12-1build1 of package redis-server
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 2/3 resources updated in 14.823459658 seconds
ws.example.jp [2014-12-22T16:24:07+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - multi_pkgs
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 3 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install
ws.example.jp - install version 1.1.19-1ubuntu0.6 of package nginx
ws.example.jp * package[redis-server] action install
ws.example.jp - install version 2:2.2.12-1build1 of package redis-server
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 2/3 resources updated in 15.721211671 seconds
ubuntu@ws:~/chef-repo$

インストールできました。ここで一旦アンインストールしておきます。


ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'sudo apt-get purge -y nginx redis-server' -x ubuntu
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
ws.example.jp 以下のパッケージが自動でインストールされましたが、もう必要とされていません:
ws.example.jp libjpeg-turbo8 libjpeg8 libxslt1.1 nginx-full nginx-common libgd2-noxpm
ws.example.jp これらを削除するには 'apt-get autoremove' を利用してください。
ws.example.jp 以下のパッケージは「削除」されます:
ws.example.jp nginx* redis-server*
ws.example.jp アップグレード: 0 個、新規インストール: 0 個、削除: 2 個、保留: 1 個。
ws.example.jp この操作後に 610 kB のディスク容量が解放されます。
(データベースを読み込んでいます ... 現在 100734 個のファイルとディレクトリがインストールされています。)
ws.example.jp nginx を削除しています ...
ws.example.jp redis-server を削除しています ...
ws.example.jp Stopping redis-server: redis-server.
ws.example.jp redis-server の設定ファイルを削除しています ...
ws.example.jp dpkg: 警告: redis-server の削除中、ディレクトリ '/var/log/redis' が空でないため削除できませんでした。
ws.example.jp man-db のトリガを処理しています ...
ws.example.jp ureadahead のトリガを処理しています ...
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
node.example.jp 以下のパッケージが自動でインストールされましたが、もう必要とされていません:
node.example.jp libjpeg-turbo8 libjpeg8 libxslt1.1 nginx-full nginx-common libgd2-noxpm
node.example.jp これらを削除するには 'apt-get autoremove' を利用してください。
node.example.jp 以下のパッケージは「削除」されます:
node.example.jp nginx* redis-server*
node.example.jp アップグレード: 0 個、新規インストール: 0 個、削除: 2 個、保留: 1 個。
node.example.jp この操作後に 610 kB のディスク容量が解放されます。
(データベースを読み込んでいます ... 現在 61316 個のファイルとディレクトリがインストールされています。)
node.example.jp nginx を削除しています ...
node.example.jp redis-server を削除しています ...
node.example.jp Stopping redis-server: redis-server.
node.example.jp redis-server の設定ファイルを削除しています ...
node.example.jp dpkg: 警告: redis-server の削除中、ディレクトリ '/var/log/redis' が空でないため削除できませんでした。
node.example.jp man-db のトリガを処理しています ...
node.example.jp ureadahead のトリガを処理しています ...
ubuntu@ws:~/chef-repo$

ループを用いてレシピを書き直してみます。


ubuntu@ws:~/chef-repo$ vi cookbooks/multi_pkgs/recipes/default.rb
#
# Cookbook Name:: multi_pkgs
# Recipe:: default
#
# Copyright (c) 2014 The Authors, All Rights Reserved.


%w{ nginx redis-server }.each do |pkg|
package pkg
end


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T16:28:00+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - ntp
node.example.jp - multi_pkgs
node.example.jp Compiling Cookbooks...
node.example.jp Converging 3 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install
node.example.jp - install version 1.1.19-1ubuntu0.6 of package nginx
node.example.jp * package[redis-server] action install
node.example.jp - install version 2:2.2.12-1build1 of package redis-server
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 2/3 resources updated in 6.903009063 seconds
ws.example.jp [2014-12-22T16:28:08+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - multi_pkgs
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 3 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install
ws.example.jp - install version 1.1.19-1ubuntu0.6 of package nginx
ws.example.jp * package[redis-server] action install
ws.example.jp - install version 2:2.2.12-1build1 of package redis-server
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 2/3 resources updated in 7.603140636 seconds
ubuntu@ws:~/chef-repo$

packageを数並べた場合と同じようにインストールできました。resourcesの数が変わっていないことに注目してください。つまり、同じ結果を得るための書き方はさまざまにできるということです。

テンプレートを用いる

ChefはエンジンにERBを用いたテンプレートが利用できます。

変数から得た値(Hello, World!)をテンプレート(tmpl.hello.erb)中に埋め込み、ファイル(/tmp/hello.txt)として出力するクックブックを作成します。

雛形を作成します。

まずはデータの集合体であるクックブックです。tmplクックブックと命名しています。


ubuntu@ws:~/chef-repo$ chef generate cookbook cookbooks/tmpl
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[/home/ubuntu/chef-repo/cookbooks/tmpl] action create
- create new directory /home/ubuntu/chef-repo/cookbooks/tmpl
:
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$

変数であるアトリビュートファイルです。デフォルト値を入れるので、defaultアトリビュートと命名しています。


ubuntu@ws:~/chef-repo$ chef generate attribute cookbooks/tmpl default
Compiling Cookbooks...
Recipe: code_generator::attribute
* directory[cookbooks/tmpl/attributes] action create
- create new directory cookbooks/tmpl/attributes
* template[cookbooks/tmpl/attributes/default.rb] action create
- create new file cookbooks/tmpl/attributes/default.rb
- update content in file cookbooks/tmpl/attributes/default.rb from none to e3b0c4
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$

テンプレートファイルです。前述の通りtmpl.hello.erbファイルと命名しています。


ubuntu@ws:~/chef-repo$ chef generate template cookbooks/tmpl tmpl.hello.erb
Compiling Cookbooks...
Recipe: code_generator::template
* directory[cookbooks/tmpl/templates/default] action create
- create new directory cookbooks/tmpl/templates/default
* template[cookbooks/tmpl/templates/default/tmpl.hello.erb] action create
- create new file cookbooks/tmpl/templates/default/tmpl.hello.erb
- update content in file cookbooks/tmpl/templates/default/tmpl.hello.erb from none to e3b0c4
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$

tmplクックブックの雛形が準備できました。


ubuntu@ws:~/chef-repo$ tree cookbooks/tmpl/
cookbooks/tmpl/
├── Berksfile
├── README.md
├── attributes
│ └── default.rb
├── chefignore
├── metadata.rb
├── recipes
│ └── default.rb
└── templates
└── default
└── tmpl.hello.erb


4 directories, 7 files
ubuntu@ws:~/chef-repo$

各雛形からクックブックを作っていきましょう。


ubuntu@ws:~/chef-repo$ vi cookbooks/tmpl/attributes/default.rb
default['tmpl']['message'] = 'Hello, World!'
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ vi cookbooks/tmpl/templates/default/tmpl.hello.erb
"<%= node['tmpl']['message'] %>"
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ vi cookbooks/tmpl/recipes/default.rb
#
# Cookbook Name:: tmpl
# Recipe:: default
#
# Copyright (c) 2014 The Authors, All Rights Reserved.


template '/tmp/hello.txt' do
source 'tmpl.hello.erb'
end
ubuntu@ws:~/chef-repo$

ノードに適用します。


ubuntu@ws:~/chef-repo$ knife node run_list add node.example.jp 'recipe[tmpl]'
node.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
recipe[tmpl]
ubuntu@ws:~/chef-repo$ knife node run_list add ws.example.jp 'recipe[tmpl]'
ws.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
recipe[tmpl]
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T17:25:29+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - multi_pkgs
node.example.jp - ntp
node.example.jp - tmpl
node.example.jp Compiling Cookbooks...
node.example.jp Converging 4 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * package[redis-server] action install (up to date)
node.example.jp Recipe: tmpl::default
node.example.jp * template[/tmp/hello.txt] action create
node.example.jp - create new file /tmp/hello.txt
node.example.jp - update content in file /tmp/hello.txt from none to 3d06fb
node.example.jp --- /tmp/hello.txt 2014-12-22 17:25:30.600670333 +0900
node.example.jp +++ /tmp/chef-rendered-template20141222-9137-1tt4lvn 2014-12-22 17:25:30.600670333 +0900
node.example.jp @@ -1 +1,2 @@
node.example.jp +"Hello, World!"
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 1/4 resources updated in 1.531860219 seconds
ws.example.jp [2014-12-22T17:25:31+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - multi_pkgs
ws.example.jp - tmpl
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 4 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * package[redis-server] action install (up to date)
ws.example.jp Recipe: tmpl::default
ws.example.jp * template[/tmp/hello.txt] action create
ws.example.jp - create new file /tmp/hello.txt
ws.example.jp - update content in file /tmp/hello.txt from none to 3d06fb
ws.example.jp --- /tmp/hello.txt 2014-12-22 17:25:33.028000026 +0900
ws.example.jp +++ /tmp/chef-rendered-template20141222-9405-1e5lqms 2014-12-22 17:25:33.028000026 +0900
ws.example.jp @@ -1 +1,2 @@
ws.example.jp +"Hello, World!"
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 1/4 resources updated in 1.301652536 seconds
ubuntu@ws:~/chef-repo$

ファイルが作成できたことを確認します。


ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'cat /tmp/hello.txt' -x ubuntu
ws.example.jp "Hello, World!"
node.example.jp "Hello, World!"
ubuntu@ws:~/chef-repo$

テンプレートにはOhaiで収集した値を埋め込むこともできます。ここではfqdnを埋め込みます。


ubuntu@ws:~/chef-repo$ git diff cookbooks
diff --git a/cookbooks/tmpl/templates/default/tmpl.hello.erb b/cookbooks/tmpl/templates/default/tmpl.hello.erb
index 1c1ac75..b8087c4 100644
--- a/cookbooks/tmpl/templates/default/tmpl.hello.erb
+++ b/cookbooks/tmpl/templates/default/tmpl.hello.erb
@@ -1 +1 @@
-"<%= node['tmpl']['message'] %>"
+<%= node['fqdn'] %> says "<%= node['tmpl']['message'] %>"
ubuntu@ws:~/chef-repo$

ノードに適用します。


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T17:29:34+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - multi_pkgs
node.example.jp - tmpl
node.example.jp - ntp
node.example.jp Compiling Cookbooks...
node.example.jp Converging 4 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * package[redis-server] action install (up to date)
node.example.jp Recipe: tmpl::default
node.example.jp * template[/tmp/hello.txt] action create
node.example.jp - update content in file /tmp/hello.txt from 3d06fb to f3a09e
node.example.jp --- /tmp/hello.txt 2014-12-22 17:25:30.600670333 +0900
node.example.jp +++ /tmp/chef-rendered-template20141222-9637-g2wd8o 2014-12-22 17:29:35.516354291 +0900
node.example.jp @@ -1,2 +1,2 @@
node.example.jp -"Hello, World!"
node.example.jp +node.example.jp says "Hello, World!"
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 1/4 resources updated in 1.291272443 seconds
ws.example.jp [2014-12-22T17:29:36+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - multi_pkgs
ws.example.jp - tmpl
ws.example.jp Compiling Cookbooks...
ws.example.jp Converging 4 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * package[redis-server] action install (up to date)
ws.example.jp Recipe: tmpl::default
ws.example.jp * template[/tmp/hello.txt] action create
ws.example.jp - update content in file /tmp/hello.txt from 3d06fb to 053da1
ws.example.jp --- /tmp/hello.txt 2014-12-22 17:25:33.028000026 +0900
ws.example.jp +++ /tmp/chef-rendered-template20141222-10088-1kk0bd5 2014-12-22 17:29:37.982553342 +0900
ws.example.jp @@ -1,2 +1,2 @@
ws.example.jp -"Hello, World!"
ws.example.jp +ws.example.jp says "Hello, World!"
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 1/4 resources updated in 1.348914275 seconds
ubuntu@ws:~/chef-repo$

ファイルを変更できたことを確認します。


ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'cat /tmp/hello.txt' -x ubuntu
ws.example.jp ws.example.jp says "Hello, World!"
node.example.jp node.example.jp says "Hello, World!"
ubuntu@ws:~/chef-repo$

リソース間の通信

notifiesまたはsubscribesを用いることで、設定ファイルに変更があったらサービスを再起動するといった動作を実現できます。

nginxパッケージをインストールし、待ち受けポート番号(listen_port)のみが変更できる設定ファイル(/etc/nginx/sites-available/default)を設置するクックブックを作成します。

まずnginxクックブックの雛形を作成します。


ubuntu@ws:~/chef-repo$ chef generate cookbook cookbooks/nginx
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[/home/ubuntu/chef-repo/cookbooks/nginx] action create
- create new directory /home/ubuntu/chef-repo/cookbooks/nginx
:
ubuntu@ws:~/chef-repo$ chef generate attribute cookbooks/nginx default
Compiling Cookbooks...
Recipe: code_generator::attribute
* directory[cookbooks/nginx/attributes] action create
- create new directory cookbooks/nginx/attributes
* template[cookbooks/nginx/attributes/default.rb] action create
- create new file cookbooks/nginx/attributes/default.rb
- update content in file cookbooks/nginx/attributes/default.rb from none to e3b0c4
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$ chef generate template cookbooks/nginx nginx.default.erb
Compiling Cookbooks...
Recipe: code_generator::template
* directory[cookbooks/nginx/templates/default] action create
- create new directory cookbooks/nginx/templates/default
* template[cookbooks/nginx/templates/default/nginx.default.erb] action create
- create new file cookbooks/nginx/templates/default/nginx.default.erb
- update content in file cookbooks/nginx/templates/default/nginx.default.erb from none to e3b0c4
(diff output suppressed by config)
ubuntu@ws:~/chef-repo$

実際にクックブックを作成していきます。ここではnotifiesを使用します。subscribesでも同じことが実現できますが、ここでは説明およびコード例は省略します。各自の宿題としてください。


ubuntu@ws:~/chef-repo$ vi cookbooks/nginx/attributes/default.rb
default['nginx']['listen_port'] = 80
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ vi cookbooks/nginx/templates/default/nginx.default.erb
#
# Generated by Chef for <%= node['fqdn'] %>
#

server {
listen <%= node['nginx']['listen_port'] %> default_server;
listen [::]:<%= node['nginx']['listen_port'] %> default_server ipv6only=on;

root /usr/share/nginx/html;
index index.html index.htm;

server_name localhost;


location / {
try_files $uri $uri/ =404;
}
}


ubuntu@ws:~/chef-repo$ vi cookbooks/nginx/recipes/default.rb
#
# Cookbook Name:: nginx
# Recipe:: default
#
# Copyright (c) 2014 The Authors, All Rights Reserved.

package 'nginx'

template '/etc/nginx/sites-available/default' do
source 'nginx.default.erb'
notifies :restart, 'service[nginx]'
end


service 'nginx' do
supports :restart => true
action :enable
end
ubuntu@ws:~/chef-repo$

ノードに適用します。


ubuntu@ws:~/chef-repo$ knife node run_list add node.example.jp 'recipe[nginx]'
node.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
recipe[tmpl]
recipe[nginx]
ubuntu@ws:~/chef-repo$ knife node run_list add ws.example.jp 'recipe[nginx]'
ws.example.jp:
run_list:
recipe[ntp]
recipe[multi_pkgs]
recipe[tmpl]
recipe[nginx]
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo
node.example.jp [2014-12-22T18:17:40+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl", "nginx"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - tmpl
node.example.jp - ntp
node.example.jp - multi_pkgs
node.example.jp - nginx
node.example.jp Compiling Cookbooks...
node.example.jp [2014-12-22T18:17:41+09:00] WARN: Cloning resource attributes for package[nginx] from prior resource (CHEF-3694)
node.example.jp [2014-12-22T18:17:41+09:00] WARN: Previous package[nginx]: /var/chef/cache/cookbooks/multi_pkgs/recipes/default.rb:8:in `block in from_file'
node.example.jp [2014-12-22T18:17:41+09:00] WARN: Current package[nginx]: /var/chef/cache/cookbooks/nginx/recipes/default.rb:7:in `from_file'
node.example.jp Converging 7 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * package[redis-server] action install (up to date)
node.example.jp Recipe: tmpl::default
node.example.jp * template[/tmp/hello.txt] action create (up to date)
node.example.jp Recipe: nginx::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * template[/etc/nginx/sites-available/default] action create
node.example.jp - update content in file /etc/nginx/sites-available/default from 7fe53b to 97aa27
node.example.jp --- /etc/nginx/sites-available/default 2012-03-29 11:50:24.000000000 +0900
node.example.jp +++ /tmp/chef-rendered-template20141222-10157-1n5zvby 2014-12-22 18:17:42.116304044 +0900
node.example.jp @@ -1,121 +1,18 @@
:
node.example.jp * service[nginx] action enable (up to date)
node.example.jp * service[nginx] action restart
node.example.jp - restart service service[nginx]
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 2/8 resources updated in 2.850105057 seconds
ws.example.jp [2014-12-22T18:17:44+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl", "nginx"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - tmpl
ws.example.jp - multi_pkgs
ws.example.jp - nginx
ws.example.jp Compiling Cookbooks...
ws.example.jp [2014-12-22T18:17:45+09:00] WARN: Cloning resource attributes for package[nginx] from prior resource (CHEF-3694)
ws.example.jp [2014-12-22T18:17:45+09:00] WARN: Previous package[nginx]: /var/chef/cache/cookbooks/multi_pkgs/recipes/default.rb:8:in `block in from_file'
ws.example.jp [2014-12-22T18:17:45+09:00] WARN: Current package[nginx]: /var/chef/cache/cookbooks/nginx/recipes/default.rb:7:in `from_file'
ws.example.jp Converging 7 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * package[redis-server] action install (up to date)
ws.example.jp Recipe: tmpl::default
ws.example.jp * template[/tmp/hello.txt] action create (up to date)
ws.example.jp Recipe: nginx::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * template[/etc/nginx/sites-available/default] action create
ws.example.jp - update content in file /etc/nginx/sites-available/default from 7fe53b to 223390
ws.example.jp --- /etc/nginx/sites-available/default 2012-03-29 11:50:24.000000000 +0900
ws.example.jp +++ /tmp/chef-rendered-template20141222-10819-d944p2 2014-12-22 18:17:45.884371929 +0900
ws.example.jp @@ -1,121 +1,18 @@
:
ws.example.jp * service[nginx] action enable (up to date)
ws.example.jp * service[nginx] action restart
ws.example.jp - restart service service[nginx]
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 2/8 resources updated in 2.687193341 seconds
ubuntu@ws:~/chef-repo$

設定通りの80番ポートにアクセスできることを確認します。


ubuntu@ws:~/chef-repo$ curl http://node.example.jp

404 Not Found


nginx/1.1.19

ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ curl http://ws.example.jp

404 Not Found


nginx/1.1.19

ubuntu@ws:~/chef-repo$

ポート番号を8080に変更します。クックブックのアトリビュートを変更してもかまいませんが、Chef-Repoに格納してあるノード情報を編集します。


ubuntu@ws:~/chef-repo$ knife node edit node.example.jp
{
"name": "node.example.jp",
"chef_environment": "_default",
"normal": {
"nginx": {
"listen_port": 8080
},
"tags": [

]
},
"run_list": [
"recipe[ntp]",
"recipe[multi_pkgs]",
"recipe[tmpl]",
"recipe[nginx]"
]


}
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ knife node edit ws.example.jp
{
"name": "ws.example.jp",
"chef_environment": "_default",
"normal": {
"nginx": {
"listen_port": 8080
},
"tags": [

]
},
"run_list": [
"recipe[ntp]",
"recipe[multi_pkgs]",
"recipe[tmpl]",
"recipe[nginx]"
]


}
ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ git diff
diff --git a/nodes/node.example.jp.json b/nodes/node.example.jp.json
index c4c6fb5..09e752e 100644
--- a/nodes/node.example.jp.json
+++ b/nodes/node.example.jp.json
@@ -1,6 +1,9 @@
{
"name": "node.example.jp",
"normal": {
+ "nginx": {
+ "listen_port": 8080
+ },
"tags": [

]
diff --git a/nodes/ws.example.jp.json b/nodes/ws.example.jp.json
index 9043d68..76bf9b4 100644
--- a/nodes/ws.example.jp.json
+++ b/nodes/ws.example.jp.json
@@ -1,6 +1,9 @@
{
"name": "ws.example.jp",
"normal": {
+ "nginx": {
+ "listen_port": 8080
+ },
"tags": [


]
ubuntu@ws:~/chef-repo$

変更したノード情報をノードに適用します。


ubuntu@ws:~/chef-repo$ knife zero chef_client 'name:*' -x ubuntu --sudo -C 1
node.example.jp [2014-12-22T18:26:40+09:00] WARN:
:
node.example.jp Starting Chef Client, version 11.16.4
node.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl", "nginx"]
node.example.jp Synchronizing Cookbooks:
node.example.jp - multi_pkgs
node.example.jp - tmpl
node.example.jp - ntp
node.example.jp - nginx
node.example.jp Compiling Cookbooks...
node.example.jp [2014-12-22T18:26:41+09:00] WARN: Cloning resource attributes for package[nginx] from prior resource (CHEF-3694)
node.example.jp [2014-12-22T18:26:41+09:00] WARN: Previous package[nginx]: /var/chef/cache/cookbooks/multi_pkgs/recipes/default.rb:8:in `block in from_file'
node.example.jp [2014-12-22T18:26:41+09:00] WARN: Current package[nginx]: /var/chef/cache/cookbooks/nginx/recipes/default.rb:7:in `from_file'
node.example.jp Converging 7 resources
node.example.jp Recipe: ntp::default
node.example.jp * package[ntp] action install (up to date)
node.example.jp Recipe: multi_pkgs::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * package[redis-server] action install (up to date)
node.example.jp Recipe: tmpl::default
node.example.jp * template[/tmp/hello.txt] action create (up to date)
node.example.jp Recipe: nginx::default
node.example.jp * package[nginx] action install (up to date)
node.example.jp * template[/etc/nginx/sites-available/default] action create
node.example.jp - update content in file /etc/nginx/sites-available/default from 97aa27 to 3960f9
node.example.jp --- /etc/nginx/sites-available/default 2014-12-22 18:17:42.116304044 +0900
node.example.jp +++ /tmp/chef-rendered-template20141222-10563-2yu0aq 2014-12-22 18:26:41.266762936 +0900
node.example.jp @@ -3,8 +3,8 @@
node.example.jp #
node.example.jp
node.example.jp server {
node.example.jp - listen 80 default_server;
node.example.jp - listen [::]:80 default_server ipv6only=on;
node.example.jp + listen 8080 default_server;
node.example.jp + listen [::]:8080 default_server ipv6only=on;
node.example.jp
node.example.jp root /usr/share/nginx/html;
node.example.jp index index.html index.htm;
node.example.jp * service[nginx] action enable (up to date)
node.example.jp * service[nginx] action restart
node.example.jp - restart service service[nginx]
node.example.jp
node.example.jp Running handlers:
node.example.jp Running handlers complete
node.example.jp Chef Client finished, 2/8 resources updated in 2.28401369 seconds
ws.example.jp [2014-12-22T18:26:43+09:00] WARN:
:
ws.example.jp Starting Chef Client, version 11.18.0.rc.1
ws.example.jp resolving cookbooks for run list: ["ntp", "multi_pkgs", "tmpl", "nginx"]
ws.example.jp Synchronizing Cookbooks:
ws.example.jp - ntp
ws.example.jp - nginx
ws.example.jp - multi_pkgs
ws.example.jp - tmpl
ws.example.jp Compiling Cookbooks...
ws.example.jp [2014-12-22T18:26:44+09:00] WARN: Cloning resource attributes for package[nginx] from prior resource (CHEF-3694)
ws.example.jp [2014-12-22T18:26:44+09:00] WARN: Previous package[nginx]: /var/chef/cache/cookbooks/multi_pkgs/recipes/default.rb:8:in `block in from_file'
ws.example.jp [2014-12-22T18:26:44+09:00] WARN: Current package[nginx]: /var/chef/cache/cookbooks/nginx/recipes/default.rb:7:in `from_file'
ws.example.jp Converging 7 resources
ws.example.jp Recipe: ntp::default
ws.example.jp * package[ntp] action install (up to date)
ws.example.jp Recipe: multi_pkgs::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * package[redis-server] action install (up to date)
ws.example.jp Recipe: tmpl::default
ws.example.jp * template[/tmp/hello.txt] action create (up to date)
ws.example.jp Recipe: nginx::default
ws.example.jp * package[nginx] action install (up to date)
ws.example.jp * template[/etc/nginx/sites-available/default] action create
ws.example.jp - update content in file /etc/nginx/sites-available/default from 223390 to f0e3c4
ws.example.jp --- /etc/nginx/sites-available/default 2014-12-22 18:17:45.884371929 +0900
ws.example.jp +++ /tmp/chef-rendered-template20141222-11323-n203be 2014-12-22 18:26:44.702071618 +0900
ws.example.jp @@ -3,8 +3,8 @@
ws.example.jp #
ws.example.jp
ws.example.jp server {
ws.example.jp - listen 80 default_server;
ws.example.jp - listen [::]:80 default_server ipv6only=on;
ws.example.jp + listen 8080 default_server;
ws.example.jp + listen [::]:8080 default_server ipv6only=on;
ws.example.jp
ws.example.jp root /usr/share/nginx/html;
ws.example.jp index index.html index.htm;
ws.example.jp * service[nginx] action enable (up to date)
ws.example.jp * service[nginx] action restart
ws.example.jp - restart service service[nginx]
ws.example.jp
ws.example.jp Running handlers:
ws.example.jp Running handlers complete
ws.example.jp Chef Client finished, 2/8 resources updated in 2.440957849 seconds
ubuntu@ws:~/chef-repo$

設定ファイルの変更とnginxの再起動が行われました。設定通りの8080番ポートにアクセスできることを確認します。


ubuntu@ws:~/chef-repo$ curl http://node.example.jp
curl: (7) couldn't connect to host
ubuntu@ws:~/chef-repo$ curl http://node.example.jp:8080

404 Not Found


nginx/1.1.19

ubuntu@ws:~/chef-repo$


ubuntu@ws:~/chef-repo$ curl http://ws.example.jp
curl: (7) couldn't connect to host
ubuntu@ws:~/chef-repo$ curl http://ws.example.jp:8080

404 Not Found


nginx/1.1.19

ubuntu@ws:~/chef-repo$

まとめ

Knife-ZeroはChef Serverを用いずに、手軽にChefによるInfrastructure as Codeを実践できる大変有用なツールです。Chef Serverによる使い勝手とまったく変わらない上に、管理規模が大きくなったらChef Serverへの移行も簡単に行えるという利点もあります。
Infrastructure as CodeをやってみたいけれどChef Serverはちょっと手に余るな、という方は、Knife-Zeroから始めてみてはいかがでしょう。本稿はなるべく平易となるように心掛けて記述したつもりです。是非その便利さを実感してみてください。


Author

Chef・Docker・Mirantis製品などの技術要素に加えて、会議の進め方・文章の書き方などの業務改善にも取り組んでいます。「Chef活用ガイド」共著のほか、Debian Official Developerもやっています。

Daisuke Higuchiの記事一覧

新規CTA