fbpx

CL LAB

HOME > CL LAB > Chef > [English Translation] Let’s begin Infrastructure as Code with Knife-Zero #getchef

[English Translation] Let’s begin Infrastructure as Code with Knife-Zero #getchef

 ★ 20

This article was posted in more than a year ago. This information may be old, please note.

This is the English translation of Knife-ZeroでInfrastructure as Codeを始めよう (2014/12/24).

What is Chef?

Chef is a tool for centralized management of IT infrastructure information. Chef is described as follows in "An Overview of Chef":

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

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

The real value of Chef is: enables centralized management of IT infrastructure information, separates each component of the infrastructure into more detailed part so that they can be reused, and then converges those components to desired state.

One of the great features of Chef, which is enabling centralized management of IT infrastructure information, tends to be overlooked in many cases. Chef can be used simply as an automated setup tool, too. However, it would be a waste not to utilize this great feature.

Installing Chef

Now, let's try to install Chef. You don't need Chef Server this time. We will use Ubuntu 12.04 LTS as a workstation and install only the client package.
We will also use Ubuntu 12.04 LTS as a remote node to be managed.

Installing Chef Development Kit

The client package for workstation is Chef Development Kit, commonly called "Chef DK". It contains not only the Chef client program, but also tools necessary to do development works with Chef, and Ruby that is required to operate Chef. This means you do not need to either install Ruby separately, or use RubyGems to install Chef.

Chef DK is available for download from Chef Development Kit | Chef Downloads | Chef. Select OS, Chef DK version and OS version that suit your environment. This time, we have downloaded chefdk_0.3.5-1_amd64.deb. Let's install it now.

ubuntu@ws:~$ sudo dpkg -i chefdk_0.3.5-1_amd64.deb
Selecting previously unselected package chefdk.
(Reading database ... 49102 files and directories currently installed.)
Preparing to unpack chefdk_0.3.5-1_amd64.deb ...
Unpacking chefdk (0.3.5-1) ...
Setting up chefdk (0.3.5-1) ...
Thank you for installing Chef Development Kit!
ubuntu@ws:~$

Installing Knife-Zero

Use Knife-Zero, we will not use the Chef Client program that comes with Chef DK here.

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:~$

Warning here is not related to Knife-Zero, so you can ignore it.

Preparations: Creating SSH key pair

Since Knife-Zero uses SSH to operate the remote node, create an SSH private/public key pair in advance. Here, we generate a key pair without a passphrase.

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:~$

As you may know, the SSH daemon must run on the target remote node, so start the node beforehand. Also, place the public key created in the previous step on the remote node.

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

For convenience, set the login account in such a way that enables to execute sudo without password to acquire a root privilege.

Creating a working environment

Create a directory tree to be used as an environment to execute Knife-Zero, and then place it under the management of git. This directory tree is called chef-repo and this is where the infrastructure information is transformed into code (Infrastructure as Code).

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$

Prepare the config file, which will be managed by Knife-Zero from now on.

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$

Installing Chef-Client to Node

Install Chef-Client on the remote node to be managed by Chef.
Use "knife zero bootstrap" command for installation. "node.example.jp" specifies a node's host name, "-x ubuntu" specifies a login user name, and "--sudo" enables to execute sudo command for getting a root privilege.

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 Resolving www.opscode.com (www.opscode.com)... 184.106.28.90
node.example.jp Connecting to www.opscode.com (www.opscode.com)|184.106.28.90|:443... connected.
node.example.jp HTTP request sent, awaiting response... 200 OK
node.example.jp Length: 18285 (18K) [application/x-sh]
node.example.jp Saving to: `STDOUT'
node.example.jp
100%[======================================>] 18,285      --.-K/s   in 0.002s
node.example.jp
node.example.jp 2014-12-19 12:06:21 (7.52 MB/s) - stdout saved [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 Selecting previously unselected package chef.
(Reading database ... 49102 files and directories currently installed.)
node.example.jp Preparing to unpack .../chef_11.16.4-1_amd64.deb ...
node.example.jp Setting up 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-Client is automatically downloaded and installed on the node.
The node is now under the management of Chef. The data to be managed is stored in the Chef-Repo directory of the workstation, not in Chef Server.

ubuntu@ws:~/chef-repo$ cat clients/node.example.jp.json | cat
{
  "name": "node.example.jp",
  "public_key": "-----BEGIN PUBLIC KEY-----\n(snip)\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$

Let's use this opportunity to register the workstation itself.

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
total 8
-rw-rw-r-- 1 ubuntu ubuntu 511 1219 12:06 node.example.jp.json
-rw-rw-r-- 1 ubuntu ubuntu 509 1219 12:33 ws.example.jp.json
ubuntu@ws:~/chef-repo$ ls -l nodes
total 64
-rw-rw-r-- 1 ubuntu ubuntu 31169 1219 12:23 node.example.jp.json
-rw-rw-r-- 1 ubuntu ubuntu 31157 1219 12:33 ws.example.jp.json
ubuntu@ws:~/chef-repo$

Manage nodes using Knife-Zero from now on.

Managing nodes with knife command

We will now try to get the information registered by using knife command. We use knife search here. The example below shows acquiring an IP address of a node.

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$

These are coming from the data stored in Chef-Repo.
Information about each node can be displayed by using argument.

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 allows you to execute commands remotely on each node.

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$

Creating cookbooks

Chef files that enable infrastructure as code and describe the desired state are called Cookbook. You can write a cookbook without knowing Ruby. Let's forget for a moment that cookbooks are internal DSL in Ruby. All we need to know is how to write a cookbook.

Installing one package

Let's create a cookbook to install an ntp package.
Use "chef generate cookbook" command to prepare a cookbook base structure. Name this cookbook as "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 is called "default Recipe" of "ntp cookbook". Usually, cookbook is a collection of various types of data except for recipes. However, you could consider cookbooks and recipes roughly the same thing.
Now, let's edit the recipe and install the ntp package.

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

package 'ntp'

It's as simple as this. Only one line has been added except the original comments. You can't find any Ruby element.
Apply this recipe to the target node.

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$

Before executing chef-client on the node and actually applying it, try why-run (similar to dry-run) with -W option.

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$

You can see that the ntp package is being installed. Now, remove the -W option and apply recipe to converge the node to the desired state.

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$

The recipe has been applied successfully. "1/1 resources updated" indicates that there has been a change in one out of one resource of the node. Apply the recipe once again in order to check idempotency.

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" indicates that there has been no change in any resources of the node.
In order to check idempotency, uninstall the package and run the recipe once again.

ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'sudo apt-get purge -y ntp' -x ubuntu
Reading package lists... Done
Building dependency tree
Reading state information... Done
ws.example.jp   The following packages were automatically installed and are no longer required:
ws.example.jp     libopts25 libcap2
ws.example.jp   Use 'apt-get autoremove' to remove them.
ws.example.jp   The following packages will be REMOVED:
ws.example.jp     ntp*
ws.example.jp   0 upgraded, 0 newly installed, 1 to remove and 1 not upgraded.
ws.example.jp   After this operation, 1,511 kB disk space will be freed.
(Reading database ... 100642 files and directories currently installed.)
ws.example.jp   Removing ntp ...
ws.example.jp    * Stopping NTP server ntpd                              [ OK ]
ws.example.jp   Purging configuration files for ntp ...
ws.example.jp   Processing triggers for man-db ...
ws.example.jp   Processing triggers for ureadahead ...
Reading package lists... Done
Building dependency tree
Reading state information... Done
node.example.jp The following packages were automatically installed and are no longer required:
node.example.jp   libopts25 libcap2
node.example.jp Use 'apt-get autoremove' to remove them.
node.example.jp The following packages will be REMOVED:
node.example.jp   ntp*
node.example.jp 0 upgraded, 0 newly installed, 1 to remove and 1 not upgraded.
node.example.jp After this operation, 1,511 kB disk space will be freed.
(Reading database ... 61224 files and directories currently installed.)
node.example.jp Removing ntp ...
node.example.jp  * Stopping NTP server ntpd                              [ OK ]
node.example.jp Purging configuration files for ntp ...
node.example.jp Processing triggers for man-db ...
node.example.jp Processing triggers for ureadahead ...
ubuntu@ws:~/chef-repo$

<code lang="bash">
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" indicates that the recipe has been applied successfully again and the resource has been updated.
In addition, information stored in nodes/ directory of Chef-Repo directory gets updated when something like Chef-Client is executed.

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$

Installing multiple packages

Let's create a cookbook that installs the nginx and redis-server packages.

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$

Installation has been completed. Uninstall the packages for now.

ubuntu@ws:~/chef-repo$ knife ssh 'name:*' 'sudo apt-get purge -y nginx redis-server' -x ubuntu
Reading package lists... Done
Building dependency tree
Reading state information... Done
ws.example.jp   The following packages were automatically installed and are no longer required:
ws.example.jp     libjpeg-turbo8 libjpeg8 libxslt1.1 nginx-full nginx-common libgd2-noxpm
ws.example.jp   Use 'apt-get autoremove' to remove them.
ws.example.jp   The following packages will be REMOVED:
ws.example.jp     nginx* redis-server*
ws.example.jp   0 upgraded, 0 newly installed, 2 to remove and 1 not upgraded.
ws.example.jp   After this operation, 610 kB disk space will be freed.
(Reading database ... 100734 files and directories currently installed.)
ws.example.jp   Removing nginx ...
ws.example.jp   Removing redis-server ...
ws.example.jp   Stopping redis-server: redis-server.
ws.example.jp   Purging configuration files for redis-server ...
ws.example.jp   dpkg: warning: while removing redis-server, directory '/var/log/redis' not empty so not removed.
ws.example.jp   Processing triggers for man-db ...
ws.example.jp   Processing triggers for ureadahead ...
Reading package lists... Done
Building dependency tree
Reading state information... Done
node.example.jp The following packages were automatically installed and are no longer required:
node.example.jp   libjpeg-turbo8 libjpeg8 libxslt1.1 nginx-full nginx-common libgd2-noxpm
node.example.jp Use 'apt-get autoremove' to remove them.
node.example.jp The following packages will be REMOVED:
node.example.jp   nginx* redis-server*
node.example.jp 0 upgraded, 0 newly installed, 2 to remove and 1 not upgraded.
node.example.jp After this operation, 610 kB disk space will be freed.
(Reading database ... 61316 files and directories currently installed.)
node.example.jp Removing nginx ...
node.example.jp Removing redis-server ...
node.example.jp Stopping redis-server: redis-server.
node.example.jp Purging configuration files for redis-server ...
node.example.jp dpkg: warning: while removing redis-server, directory '/var/log/redis' not empty so not removed.
node.example.jp Processing triggers for man-db ...
node.example.jp Processing triggers for ureadahead ...
ubuntu@ws:~/chef-repo$

Rewrite the recipe by using loop.

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$

Installation has been completed in the same way as multiple packages are used. Note that the number of resources has not been changed. This means that there are various ways to write a recipe to get the same result.

Using a template

With Chef, it is possible to use a Template that uses ERB for the engine.
Create a cookbook that embeds the values acquired from variables (Hello, World!) into a template (tmpl.hello.erb), and outputs as a file (/tmp/hello.txt).
Start with a cookbook, which is a collection of data. Name the cookbook as "tmpl" cookbook.

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$

This is an Attribute file that describes a variable. Name this file as default attribute since it will contain the default value.

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$

This is the template file. As mentioned in the previous step, the file name is "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$

A base structure of the tmpl cookbook has been prepared now.

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$

Let's create a cookbook using structure as a base.

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$

Apply the template parameter to the node.

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$

Make sure that the file has been created.

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$

You can also embed the value collected with Ohai. Embed fqdn here.

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$

Apply the fqdn parameter to the node.

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$

Make sure that the file has been changed.

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$

Communication between resources

By using notifies or subscribes, service can be restarted as soon as the config file is changed.
Create a cookbook, which installs an nginx package, and places the config file (/etc/nginx/sites-available/default) that can only change the listen port number (listen_port).
Firstly, create a base structure of nginx cookbook.

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$

Let's create a cookbook now. We use notifies here. The same thing can be achieved by using subscribes, but we will neither go on to details nor explain the code examples now. Please check them on your own later.

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$
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$

Apply the nginx parameter to the node.

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$

Make sure that you can access to port 80 as specified.

ubuntu@ws:~/chef-repo$ curl http://node.example.jp
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>
ubuntu@ws:~/chef-repo$
ubuntu@ws:~/chef-repo$ curl http://ws.example.jp
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>
ubuntu@ws:~/chef-repo$

Change the port number to 8080. You can change the attribute of the cookbook instead, but we will edit the node information stored in Chef-Repo here.

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$

Apply the changed node information to the node.

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$

Now that the config file has been changed and nginx has been restarted. Make sure that you can access to port 8080 as specified.

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
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>
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
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.1.19</center>
</body>
</html>
ubuntu@ws:~/chef-repo$

Summary

Knife-Zero is a very helpful tool that easily enables practicing Infrastructure as Code through the use of Chef without using Chef Server. One of the advantages of using Knife-Zero is that migration to Chef Server is easy when the number of nodes scales out while retaining the usability that is equivalent to Chef Server.
For those who want to try practicing Infrastructure as Code, but think that Chef Server is too much to handle, we recommend using Knife-Zero first. We tried to describe this document as easily as possible for a better understanding of Knife-Zero. We hope you will experience the convenience of Knife-Zero.


CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post