ようへいの日々精進XP

よかろうもん

(ショロカレ 19 日目)もうすぐ 2015 年が終わろうとしているけど 2015 年版 Chef 再入門(1)

「初老丸の独り Advent calendar 2015」の十九日目の記事です。

tl;dr

Chef 等の構成管理ツールの使い方をすっかり忘れていることに気付いたので手を動かして再入門してみることにした。

ちなみに、自分の Chef 知識は 2013 年位で止まっているので、階級的には Hello World 準一級(そこそこ初心者)であるので記事内の用語などについては誤りなどがあるかもしれないので注意。

参考

今回の目標

  • Chef-Client のローカルモードを体感する
  • knife zero を利用してリモートホストにレシピを適用する

今回の環境

  • Workstation
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"

$ chef-client --version
Chef: 12.5.1
$ knife ssh 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu 'cat /etc/lsb-release'
xx.xxx.xx.xx DISTRIB_ID=Ubuntu
xx.xxx.xx.xx DISTRIB_RELEASE=14.04
xx.xxx.xx.xx DISTRIB_CODENAME=trusty
xx.xxx.xx.xx DISTRIB_DESCRIPTION="Ubuntu 14.04.2 LTS"

$ knife ssh 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu 'chef-client --version'
xx.xxx.xx.xx Chef: 12.5.1

今回の教材

EC2 を構築するための terraform テンプレートのみ。

github.com

早速、t2.nano を使った。


Chef-Client のローカルモードを体感する

ChefDk のインストール

Chef をサクッと始めたい場合には Chef 社が配布する ChefDk(Chef Development Kit)を利用するのが手っ取り早いようだ。

上記から環境に合わせたセットアップファイルをダウンロードしておく。

$ wget https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chefdk_0.10.0-1_amd64.deb
$ sudo dpkg -i chefdk_0.10.0-1_amd64.deb

インストールが完了したら chef-client のバージョンを確認する。

$ chef-client --version
Chef: 12.5.1

はじめての Chef リポジトリ

ChefDk のインストールが終了したら Chef の Cookbook を管理する Chef リポジトリを作成する。Chef リポジトリの作成には chef generate コマンドを利用するとよさそう。

$ chef generate repo chef-repo

カレントディレクトリに chef-repo というリポジトリが作成されたのでディレクトリ構造を見てみる。

$ tree  --charset=x chef-repo
chef-repo
|-- chefignore
|-- cookbooks
|   |-- example
|   |   |-- attributes
|   |   |   `-- default.rb
|   |   |-- metadata.rb
|   |   |-- README.md
|   |   `-- recipes
|   |       `-- default.rb
|   `-- README.md
|-- data_bags
|   |-- example
|   |   `-- example_item.json
|   `-- README.md
|-- environments
|   |-- example.json
|   `-- README.md
|-- LICENSE
|-- README.md
`-- roles
    |-- example.json
    

既に example という Cookbook が作成されている。

初めての Chef-Client ローカルモード

作成した Chef-repo に移動して以下のように Chef-Client をローカルモードで実行してみる。

$ chef-client -z -o example

以下のように出力される。

Starting Chef Client, version 12.5.1
[2015-12-19T19:36:26+09:00] WARN: Run List override has been provided.
[2015-12-19T19:36:26+09:00] WARN: Original Run List: []
[2015-12-19T19:36:26+09:00] WARN: Overridden Run List: [recipe[example]]
resolving cookbooks for run list: ["example"]
Synchronizing Cookbooks:
  - example (1.0.0)
Compiling Cookbooks...
Converging 1 resources
Recipe: example::default
  * log[Welcome to Chef, Sam Doe!] action write

[2015-12-19T19:36:26+09:00] WARN: Skipping final node save because override_runlist was given

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

ローカルホストに対して log リソースを使ったレシピが適用された。おお、簡単。

ちなみに、前後するが -z-o オプションについて確認する。

$ chef-client --help 2>&1 | egrep '\-o|\-z'

(snip)

    -z, --local-mode                 Point chef-client at local repository

(snip)

    -o RunlistItem,RunlistItem...,   Replace current run list with specified items for a single run
        --override-runlist

-z オプションがローカルモード、-o で適用するレシピや role を直接指定している。

以下のように knife コマンドについてもローカルモードで動作するとのことなので、node のリストについても取得することが出来る。

$ knife node list
vagrant-ubuntu-trusty-64

おお。確認してみるとレシピを適用した段階で自動的に chef-repo/nodes/ 以下にローカルホストの情報を登録してくれていた。

$ tree  --charset=x chef-repo
chef-repo
|-- chefignore
|-- cookbooks
|   |-- example
|   |   |-- attributes
|   |   |   `-- default.rb
|   |   |-- metadata.rb
|   |   |-- README.md
|   |   `-- recipes
|   |       `-- default.rb
|   `-- README.md
|-- data_bags
|   |-- example
|   |   `-- example_item.json
|   `-- README.md
|-- environments
|   |-- example.json
|   `-- README.md
|-- LICENSE
|-- nodes
|   `-- vagrant-ubuntu-trusty-64.json
|-- README.md
`-- roles
    |-- example.json
    `-- README.md

9 directories, 15 files

尚、Chef-Client のローカルモードについては以下の記事を参考にさせて頂いた。


knife zero を利用してリモートホストにレシピを適用する

knife zero に関する情報

knife zero に関する情報は検索すると多くの情報を目にすることが出来たが、まずは以下の公式ドキュメントと記事を読むと良いと思った。

レシピをリモートホストに適用するまで(ざっくり)

で、Chef-Client を体感したところでリモートホストに knife zero を使ってレシピを適用するまでの流れを整理してみる。

  1. Workstation で Chef を使えるようにする(ChefDk をインストールする)→済んでる
  2. knife zero をインストールする
  3. knife zero bootstrapリモートホストに Chef-Client をインストールする
  4. 対象ノードに適用する cookbook を追加する
  5. knife zero converge --why-run で確認
  6. knife zero convergeリモートホストに適用する
  7. 余裕があれば Cookbook を追加してみる

ということで、上記の流れに沿ってやってみる。

knife zero のインストールと knife の設定

以下のように knife zero をインストールする。

$ chef gem install knife-zero

合わせて knife.rb に以下を設定する。

$ cd chef-repo
$ cat knife.rb
current_dir = File.absolute_path( File.dirname(__FILE__) )
cookbook_path ["#{current_dir}/cookbooks"]
node_path     "#{current_dir}/nodes"
role_path     "#{current_dir}/roles"
ssl_verify_mode  :verify_peer
local_mode true
knife[:use_sudo] = true
knife[:identity_file] = "~/.ssh/key.pem"

key.pem は対象のリモートホストに合わせたキーのファイル名を指定すること。

リモートホストの構築

リモートホストの構築には terraform を利用する。以下のように EC2 を terraform で作成しておく。(教材を利用する前提)

$ make tf-apply

以下のようにインスタンスのグローバル IP とインスタンス ID が出力されるので控えておく。

Outputs:

  EC2 IP address  = xxx.xxx.xxx.xxx
  EC2 Instance ID = i-xxxxxxxx

リモートホストに Chef-Client をインストールする

インスタンスの構築が完了したら Chef-Client をインストールする。インストールは knife zero bootstrap を利用する。

$ knife zero bootstrap xxx.xxx.xxx.xxx -i ~/.ssh/key.pem -x ubuntu --sudo

以下のように chef-repo/nodes 以下にノード情報が作成されている。

$ cd chef-repo
$ ls -l nodes/ip-xx-x-x-xx.ap-northeast-1.compute.internal.json

以下のように JSON ファイルになっている。

$ cat nodes/ip-xx-x-x-xx.ap-northeast-1.compute.internal.json
{
  "name": "ip-xx-x-x-xx.ap-northeast-1.compute.internal",
  "normal": {
    "knife_zero": {
      "host": "xx.xxx.xx.xx"
    },
    "tags": [

    ]
  },

(snip)

リモートホストに適用したいレシピを登録する

インスタンスに Chef-Client のインストールが完了したら、適用したいレシピを登録する。登録には knife node run_list add を利用する。

$ knife node run_list add -z ip-xx-x-x-xx.ap-northeast-1.compute.internal recipe[example]

以下のように出力される。

ip-xx-x-x-xx.ap-northeast-1.compute.internal:
  run_list: recipe[example]

そして、以下のようにノード情報の JSON ファイルに run_list が追加されている。

$ cd chef-repo
$ cat nodes/ip-xx-x-x-xx.ap-northeast-1.compute.internal.json

(snip)

  },
  "run_list": [
    "recipe[example]"
  ]
}

knife zero converge --why-run で適用されるレシピを確認する

まずはレシピがちゃんと適用されるかを確認してみる。

$ knife zero converge 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu--why-run

以下のように出力される。

xx.xxx.xx.xx Starting Chef Client, version 12.5.1
xx.xxx.xx.xx resolving cookbooks for run list: ["example"]
xx.xxx.xx.xx Synchronizing Cookbooks:
xx.xxx.xx.xx   - example (1.0.0)
xx.xxx.xx.xx Compiling Cookbooks...
xx.xxx.xx.xx Converging 1 resources
xx.xxx.xx.xx Recipe: example::default
xx.xxx.xx.xx   * log[Welcome to Chef, Sam Doe!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx [2015-12-19T11:10:04+00:00] WARN: In whyrun mode, so NOT performing node save.
xx.xxx.xx.xx
xx.xxx.xx.xx Running handlers:
xx.xxx.xx.xx Running handlers complete
xx.xxx.xx.xx Chef Client finished, 1/1 resources would have been updated

よしよし、うまくいくようだ。

knife zero converge でリモートホストに適用する

本番。以下のように実行する。

knife zero converge 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu -i ~/.ssh/key.pem --sudo

以下のように出力される。

xx.xxx.xx.xx Starting Chef Client, version 12.5.1
xx.xxx.xx.xx resolving cookbooks for run list: ["example"]
xx.xxx.xx.xx Synchronizing Cookbooks:
xx.xxx.xx.xx   - example (1.0.0)
xx.xxx.xx.xx Compiling Cookbooks...
xx.xxx.xx.xx Converging 1 resources
xx.xxx.xx.xx Recipe: example::default
xx.xxx.xx.xx   * log[Welcome to Chef, Sam Doe!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx
xx.xxx.xx.xx Running handlers:
xx.xxx.xx.xx Running handlers complete
xx.xxx.xx.xx Chef Client finished, 1/1 resources updated in 01 seconds

おけ、おけ。

調子に乗って Cookbook を追加して別のレシピを適用してみる

まずは以下のように新しい Cookbook をこさえる。

$ cd chef-repo
$ knife cookbook create helloworld -o ./cookbooks/

以下のように出力される。

** Creating cookbook helloworld in /home/vagrant/git/oreno-chef-2015/chef-repo/cookbooks
** Creating README for cookbook: helloworld
** Creating CHANGELOG for cookbook: helloworld
** Creating metadata for cookbook: helloworld

レシピ(chef-repo/cookbooks/helloworld/recipes/default.rb)は以下のように記載。

log "Welcome to Chef, #{node["example"]["name"]}!" do
  level :info
end

レシピから呼び出されるアトリビュート(chef-repo/cookbooks/helloworld/attributes/default.rb)は以下のように記載。

default["example"]["name"] = "Komanechi!!!!"

先ほどと同様に knife node run_list add を利用して対象のノードの run_list にレシピを追加する。

$ knife node run_list add -z ip-xx-x-x-xx.ap-northeast-1.compute.internal recipe[helloworld]

以下のように出力される。

ip-xx-x-x-xx.ap-northeast-1.compute.internal:
  run_list:
    recipe[example]
    recipe[helloworld]

そして...why-run からの適用。(ここからはダイジェストで)

#
# why-run
#
$ knife zero converge 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu --why-run
xx.xxx.xx.xx Starting Chef Client, version 12.5.1
xx.xxx.xx.xx resolving cookbooks for run list: ["example", "helloworld"]
xx.xxx.xx.xx Synchronizing Cookbooks:
xx.xxx.xx.xx   - helloworld (0.1.0)
xx.xxx.xx.xx   - example (1.0.0)
xx.xxx.xx.xx Compiling Cookbooks...
xx.xxx.xx.xx Converging 2 resources
xx.xxx.xx.xx Recipe: example::default
xx.xxx.xx.xx   * log[Welcome to Chef, Komanechi!!!!!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx Recipe: helloworld::default
xx.xxx.xx.xx   * log[Welcome to Chef, Komanechi!!!!!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx [2015-12-19T11:22:21+00:00] WARN: In whyrun mode, so NOT performing node save.
xx.xxx.xx.xx
xx.xxx.xx.xx Running handlers:
xx.xxx.xx.xx Running handlers complete
xx.xxx.xx.xx Chef Client finished, 2/2 resources would have been updated

#
# 適用
#
$ knife zero converge 'name:ip-xx-x-x-xx.ap-northeast-1.compute.internal' --attribute knife_zero.host -x ubuntu
xx.xxx.xx.xx Starting Chef Client, version 12.5.1
xx.xxx.xx.xx resolving cookbooks for run list: ["example", "helloworld"]
xx.xxx.xx.xx Synchronizing Cookbooks:
xx.xxx.xx.xx   - example (1.0.0)
xx.xxx.xx.xx   - helloworld (0.1.0)
xx.xxx.xx.xx Compiling Cookbooks...
xx.xxx.xx.xx Converging 2 resources
xx.xxx.xx.xx Recipe: example::default
xx.xxx.xx.xx   * log[Welcome to Chef, Komanechi!!!!!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx Recipe: helloworld::default
xx.xxx.xx.xx   * log[Welcome to Chef, Komanechi!!!!!] action write
xx.xxx.xx.xx
xx.xxx.xx.xx
xx.xxx.xx.xx Running handlers:
xx.xxx.xx.xx Running handlers complete
xx.xxx.xx.xx Chef Client finished, 2/2 resources updated in 01 seconds

helloworld が適用されている。(example と同じアトリビュートを見ているので出力は同じ)


その他

knife search の Attribute 指定

  • name
$ knife search node 'name:*' --attribute name
2 items found

ip-xx-x-x-xx.ap-northeast-1.compute.internal:
  name: ip-xx-x-x-x.ap-northeast-1.compute.internal

vagrant-ubuntu-trusty-64:
  name: vagrant-ubuntu-trusty-64
  • knife_zero.host
$ knife search node 'name:*' --attribute knife_zero.host
2 items found

ip-xx-x-x-xx.ap-northeast-1.compute.internal:
  knife_zero.host: xx.xxx.xx.xx

vagrant-ubuntu-trusty-64:
  knife_zero.host: 
  • ipaddress
$ knife search node 'name:*' --attribute ipaddress
2 items found

ip-xx-x-x-xx.ap-northeast-1.compute.internal:
  ipaddress: xx.x.x.xx

vagrant-ubuntu-trusty-64:
  ipaddress: 

ひとまず

今回の目的は達成したものの、SuperMarket にアップロードされている Cookbook を利用する方法などについては引き続き手を動かしていきたい。

以上。