Chefのローカルモードチュートリアル + knife-zero + knife-sakura

  • 239
    Like
  • 10
    Comment
More than 1 year has passed since last update.

前回 Chefのローカルモードだけでリモートサーバを運用してみようと、Knife-Zeroを作った。Nodeの構成情報もとれるよ。 - Qiita の続きといえば続きです。

Knife-Zeroのページはこちら。 http://knife-zero.github.io/ja/

Chef11.xからローカルモードというのが加わりました。Chef-Client/Server環境の簡易版であり、Soloの代わりでもあります。

Chef-Soloからの乗り換えとしてChef-Zero(ローカルモード)検索が多いようなので、この追記を先頭に移動

このサンプルではSSH越しにローカルモードを実行していますが、単にサーバ側にChef-Repoを置いてローカルモードをしたい場合、
Chefをインストール後にChef-Repoのディレクトリに移動してchef-client -zでOKです。
SoloみたいにCookbookPathが無いとかそういうエラーもなく、簡単に実行できます。
ついでに、Knife-Soloは無くならないので、乗り換え必須ではありません。

追記1: で、Soloどうなるのよってのはこちらに書いたので合わせてどうぞ。
追記2: 200ストックの通知が来たので、コマンド等を現行(1.8.0時)向けに少し修正
追記3: Knife-Zeroのページ。

概要

今回はローカルモードを主眼において、そのままChef-Serverレスでインフラを管理していこうという試みのチュートリアルです。
本文はだいたいこんな感じですすめます。

  • ローカルモードでのChefのインフラ構築ワークフロー
  • Knife-Sakuraでサーバ調達 (※ optional)
  • Knife-Zero

ちなみに作業後のディレクトリ構成等は higanworks/chef_localmode_tutorial にアップしているので、セットアップ代わりにこちらをクローンしてから始めてもよいです。

セットアップ

Rubyプロジェクトぽく進めます、必要なディレクトリを用意して。

$ mkdir my_chefrepo
$ cd my_chefrepo/
$ bundle init
Writing new Gemfile to /Users/sawanoboriyu/my_chefrepo/Gemfile

Gemfileに使うGemsを記述して。

Gemfile
source "https://rubygems.org"

gem 'chef'
gem 'knife-zero'
gem 'knife-sakura'

Bundleします。

...
Installing chef (11.14.6)
Installing knife-zero (0.1.2)
...

Installing knife-sakura (0.0.2)
Your bundle is complete!
It was installed into ./vendor/bundle

ちなみにknife-zero(0.1.2), knife-sakura(0.0.2)以上が必須です。

--binstubsしているので、カレントの./binに実行ファイルが来ます。

$ tree . -I vendor
.
├── Gemfile
├── Gemfile.lock
└── bin
    ├── chef-apply
    ├── chef-client
    ├── chef-service-manager
    ├── chef-shell
    ├── chef-solo
    ├── chef-zero
    ├── coderay
    ├── erubis
    ├── ffi-yajl-bench
    ├── fog
    ├── htmldiff
    ├── knife
    ├── ldiff
    ├── nokogiri
    ├── ohai
    ├── pry
    ├── rackup
    ├── restclient
    └── shef

ローカルモードの準備

knifeコマンドのデフォルト動作をローカルモードにするためknife.rbを作ります。この記述はコマンドラインの--local-modeオプションと同じ働きです。

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

これでローカルモードで動作するようになります。
Chef-Client/Server環境のコマンド、knife environment list等を叩いてみましょう。

$ ./bin/knife environment list -V
WARN: No cookbooks directory found at or above current directory.  Assuming /Users/sawanoboriyu/Dev/worktmp/my_chefrepo.
INFO: Starting chef-zero on host localhost, port 8889 with repository at repository at /Users/sawanoboriyu/Dev/worktmp/my_chefrepo
  One version per cookbook


$ ./bin/knife node list -V
WARN: No cookbooks directory found at or above current directory.  Assuming /Users/sawanoboriyu/Dev/worktmp/my_chefrepo.
INFO: Starting chef-zero on host localhost, port 8889 with repository at repository at /Users/sawanoboriyu/Dev/worktmp/my_chefrepo
  One version per cookbook

この記述 Starting chef-zero on host localhost, port 8889 with repository at repository at /Users/sawanoboriyu/Dev/worktmp/my_chefrepo がポイントです。
ローカルのディレクトリをベースにChefZeroが起動して、ChefServerの代わりをしています。

なおWARNが出ていますが、単に./cookbooksディレクトリが無いためです。
あとで勝手にできるので、これ以降WARN: No cookbooks directory〜は省略します。

Environmentをつくる

新しいEnvironment、developmentを作ってみましょう。knife environment create developmentです。

$ ./bin/knife environment create development

## ---エディタが開く

{
  "name": "development",
  "description": "",
  "cookbook_versions": {
  },
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
  },
  "override_attributes": {
  }
}
## --- 保存して終了

Created development

リストに出るようになりました。

$ ./bin/knife environment list
development

ファイルとして保存されています。

$ tree environments/
environments/
└── development.json

knife searchenvironmentを対象に探せばちゃんと見つかります。

$ ./bin/knife search environment 'name:dev*'
1 items found

chef_type:           environment
cookbook_versions:
default_attributes:
description:         
json_class:          Chef::Environment
name:                development
override_attributes:

余談:ChefZeroを単体で上げるknife serve

knife serveサブコマンドを使うと、ローカルのディレクトリをChef-Repoに見立てたChefZeroが起動します。
※ 通常のchef-zeroコマンドではすべてオンメモリで、リソース空っぽで起動して終了時に何も保存しません。

$ ./bin/knife serve
Serving files from:
repository at /Users/sawanoboriyu/Dev/worktmp/my_chefrepo
  One version per cookbook

>> Starting Chef Zero (v2.2)...
>> WEBrick (v1.3.1) on Rack (v1.5) is listening at http://localhost:8889
>> Press CTRL+C to stop

この状態なら、Chef-Serveに問い合わせる要領でオブジェクトを取得することもできるので、色々動作確認してみたい場合は使える機能です。

$ curl -H 'Accept: application/json' localhost:8889/environments
{
  "development": "http://localhost:8889/environments/development"
}

Accept: application/jsonヘッダを忘れずに。

$ curl -H 'Accept: application/json' localhost:8889/environments/development
{
  "name": "development",
  "description": "",
  "cookbook_versions": {
  },
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
  },
  "override_attributes": {
  }
}

ついでに言うと、これらのオブジェクトはファイルベースなのでrmでもサクッと消せます。

Data Bagをつくる

同様にData Bagを作ってみます。

$ ./bin/knife data bag create samplebag sampleitem

## ---エディタが開くので編集する
{
  "id": "sampleitem",
  "foo": "bar"
}
## --- 保存して終了

Created data_bag[samplebag]
Created data_bag_item[sampleitem]

リストOK。

$ ./bin/knife data bag list
samplebag

$ ./bin/knife data bag show samplebag sampleitem
foo: bar
id:  sampleitem

これもファイルとして保存されています。

$ tree data_bags/
data_bags/
└── samplebag
    └── sampleitem.json

1 directory, 1 file

追記:
この段落をサーバ側で実行すれば、単体でChef-Soloを実行するのとだいたいおなじ感覚になります。

適当なNodeを用意する knife-sakura

ではChefの管理対象とするリソースとして、今回はLinuxサーバを用意します。

サーバはSSHが繋がるならば既存のものでも良いですし、aws cliでもterraformでも、ローカルのVagrantでも好きなように調達してください。

さて、今回はせっかくなのでなんかしらクラウドで。
Knifeのプラグインを利用してさくらのクラウドから調達します。みなさんたいていクーポンが遊んでいるでしょう。

Vagrant+VirtualBoxでマシンを調達するならば Vagrantでknife-zeroを使うためのベストプラクティス | 割り箸ポテチ も参考になるでしょう。

さくらのクラウド(knife-sakura)セットアップ

.chef/knife.rbをちょろちょろっと編集して、環境変数をエクスポートしておきます。

.chef/knife.rb
local_mode true

## SakuraCloud credentials
knife[:sakuracloud_api_token] = ENV['SAKURACLOUD_API_TOKEN']
knife[:sakuracloud_api_token_secret] = ENV['SAKURACLOUD_API_TOKEN_SECRET']
knife[:sakuracloud_ssh_key] = ENV['SAKURACLOUD_USER_KEY_ID']

さくらのクラウド(knife-sakura)でサーバ調達

サーバを調達するには、knife sakura server createです。

server1,server2,server3として、3台ほど調達を試みます。
ついでに--no-bootstrapとして、Chef-Server連携用のbootstrapをキャンセルします。 (※ この後のknife-zeroのため)

$ for x in {1..3} ; do echo ./bin/knife sakura server create  --server-plan 1001 --disk-plan 4 --source-archive 112500463685 --no-bootstrap -n server${x}; done

Instance ID: 112600642xxx
Server Plan: プラン/1Core-1GB
Public IP Address: 133.242.231.xxx

Instance ID: 112600642xxx
Server Plan: プラン/1Core-1GB
Public IP Address: 133.242.230.xxx

Instance ID: 112600642xxx
Server Plan: プラン/1Core-1GB
Public IP Address: 133.242.237.xxx

新鮮なサーバが3台とれました。

$ ./bin/knife sakura server list
ID                                    Name                                  Status                                Created at                          
112600642xxx                          1a966089-d6bb-42cb-a7df-08beda84cxxx  up                                    2014-08-25Txx:xx:xx+09:00           
112600642xxx                          aa897042-ecf0-49fd-9eaa-05dea1be3xxx  up                                    2014-08-25Txx:xx:xx+09:00           
112600642xxx                          9bd5969f-a682-465d-b3c0-6e86148a4xxx  up                                    2014-08-25Txx:xx:xx+09:00

じゃあこれらをChefローカルモードの管理下においていきます。

knife-zeroでnodeを管理下に

knife zero bootstrapをすることで、前回のようにします。

-E developmentをつけて、Environent => developmentのノードとして登録しましょう。

## server1をbootstrap
$ ./bin/knife zero bootstrap 133.242.231.xxx -x ubuntu -E development --sudo -N server1
...
133.242.231.xxx Chef Client finished, 0/0 resources updated in 3.692237549 seconds


## server2をbootstrap
$ ./bin/knife zero bootstrap 133.242.230.xxx -x ubuntu -E development --sudo -N server2
...
133.242.230.xxx Chef Client finished, 0/0 resources updated in 3.692237549 seconds


## server3をbootstrap
$ ./bin/knife zero bootstrap 133.242.237.xxx -x ubuntu -E development --sudo -N server3
...
133.242.237.xxx Chef Client finished, 0/0 resources updated in 3.692237549 seconds


無事Zero Bootstrapが終わったので、nodeのリストが取れることを確認しましょう。

$ ./bin/knife node list
server1
server2
server3

もちろんファイルとしてローカルにありつつ。

$ tree nodes/
nodes/
├── server1.json
├── server2.json
└── server3.json

0 directories, 3 files

knife node showなどで情報を表示することができます。

$ ./bin/knife node show server1
Node Name:   server1
Environment: development
FQDN:        localhost
IP:          133.242.231.xxx
Run List:    
Roles:       
Recipes:     
Platform:    ubuntu 12.04
Tags:        

Environent => developmentなNodeをサーチすれば、それぞれがちゃんと引っかかりますね。

$ ./bin/knife search node 'chef_environment:development'
3 items found

Node Name:   server1
Environment: development
FQDN:        localhost
IP:          133.242.231.xxx
Run List:    
Roles:       
Recipes:     
Platform:    ubuntu 12.04
Tags:        

Node Name:   server2
Environment: development
FQDN:        localhost
IP:          133.242.230.xxx
Run List:    
Roles:       
Recipes:     
Platform:    ubuntu 12.04
Tags:        

Node Name:   server3
Environment: development
FQDN:        localhost
IP:          133.242.237.xxx
Run List:    
Roles:       
Recipes:     
Platform:    ubuntu 12.04
Tags:        

標準のknife sshもローカルモードで動作させれば、このとおり。

$ ./bin/knife ssh 'chef_environment:development' -x ubuntu --attribute ipaddress uptime 
133.242.231.xxx  xx:40:51 up  1:41,  1 user,  load average: 0.00, 0.01, 0.05
133.242.230.xxx  xx:40:51 up  1:40,  1 user,  load average: 0.00, 0.02, 0.05
133.242.237.xxx  xx:40:51 up  1:38,  1 user,  load average: 0.00, 0.02, 0.05

※ 標準で接続先に使われるFQDNが全部localhostなので、--attribute ipaddressを指定してSSHの接続対象をIPにしています。

追記: Knife-Zero 1.8.0で、Bootstrapで指定したIPをnode.knife_zero.hostで保持するようにしました。
IPアドレスを複数持つ一部の環境ではnode.ipaddressが手元からつながらない場合があるため、Bootstrapでの接続実績を使い回しできるようにする更新です。
そっちを使う場合は、--attribute ipaddressの代わりに、--attribute knife_zero.hostでどうぞ。

Cookbookを作ってレシピを適用、Data Bag, SearchもOK

knife cookbook createでCookbookを作りましょう。

$ ./bin/knife cookbook create demobook
** Creating cookbook demobook
** Creating README for cookbook: demobook
** Creating CHANGELOG for cookbook: demobook
** Creating metadata for cookbook: demobook

local_modeなので./cookbooks/ディレクトリを自動でつくって、雛形をおいてくれます。

$ tree cookbooks/
cookbooks/
└── demobook
    ├── CHANGELOG.md
    ├── README.md
    ├── attributes
    ├── definitions
    ├── files
    │   └── default
    ├── libraries
    ├── metadata.rb
    ├── providers
    ├── recipes
    │   └── default.rb
    ├── resources
    └── templates
        └── default

11 directories, 4 files

Data Bagを使うレシピ

C/S環境と同様にかつ、ノード側に特にプラグイン無しでData Bagが利用できることを確認するため、次のようなRecipeを作りました。

cookbooks/demobook/recipes/data_bag.rb
text = data_bag_item('samplebag', 'sampleitem')

file '/tmp/from_databag.txt' do
  content text['foo']
end

Searchを使うレシピ

同様にSearchが利用できることを確認するため、次のようなRecipeを作りました。

cookbooks/demobook/recipes/search.rb
nodes = search(:node, "chef_environment:#{node.chef_environment}")
list = nodes.map {|n| n.to_s}

file '/tmp/nodes_from_search.txt' do
  content list.join("\n")
end

ランリストをまとめるRoleを作る

Environemntなどと同様に、knife role createでRoleを作ります。

$ ./bin/knife role create demorole

## ---エディタが開く
{
  "name": "demorole",
  "description": "", 
  "json_class": "Chef::Role",
  "default_attributes": {
  },  
  "override_attributes": {
  },  
  "chef_type": "role",
  "run_list": [
    "demobook::data_bag",    ## ここを追記
    "demobook::search"       ## ここを追記
  ],  
  "env_run_lists": {
  }
}
## --- 保存して終了

Created role[demorole]

role showで確認したりも可と。

$ ./bin/knife role show demorole
chef_type:           role
default_attributes:
description:         
env_run_lists:
json_class:          Chef::Role
name:                demorole
override_attributes:
run_list:
  recipe[demobook::data_bag]
  recipe[demobook::search]

server1role[demorole]の役割を与えてみましょう。
knife node run_list addです。

$ knife node run_list add server1 'role[demorole]'
server1:
  run_list: role[demorole]

適用するにはまたKnife-Zeroで作った拡張のknife zero convergeでOKです。
まあポートフォワードを付けてChef-Clientを叩いてくるだけなのですが。

追記: zero chef_clientzero convergeに(主に気分で)変えました。zero chef_clientも使えます。

$ ./bin/knife zero converge 'name:server1' -x ubuntu --sudo --attribute ipaddress
133.242.231.xxx Starting Chef Client, version 11.14.6

## RunListからCookbookを取得する
133.242.231.xxx resolving cookbooks for run list: ["demobook::data_bag", "demobook::search"]
133.242.231.xxx Synchronizing Cookbooks:
133.242.231.xxx   - demobook
133.242.231.xxx Compiling Cookbooks...
133.242.231.xxx Converging 2 resources


## demobook::data_bagの実行
133.242.231.xxx Recipe: demobook::data_bag
133.242.231.xxx   * file[/tmp/from_databag.txt] action create
133.242.231.xxx     - create new file /tmp/from_databag.txt
133.242.231.xxx     - update content in file /tmp/from_databag.txt from none to fcde2b
133.242.231.xxx     --- /tmp/from_databag.txt   2014-08-25 xx:15:49.135991498 +0900
133.242.231.xxx     +++ /tmp/.from_databag.txt20140825-3969-1tnpdkw 2014-08-25 xx:15:49.135991498 +0900
133.242.231.xxx     @@ -1 +1,2 @@
133.242.231.xxx     +bar  ## Data Bagの中身をファイルに出力


## demobook::searchの実行
133.242.231.xxx Recipe: demobook::search
133.242.231.xxx   * file[/tmp/nodes_from_search.txt] action create
133.242.231.xxx     - create new file /tmp/nodes_from_search.txt
133.242.231.xxx     - update content in file /tmp/nodes_from_search.txt from none to 37ab54
133.242.231.xxx     --- /tmp/nodes_from_search.txt  2014-08-25 xx:15:49.139991498 +0900
133.242.231.xxx     +++ /tmp/.nodes_from_search.txt20140825-3969-ln7sth 2014-08-25 xx:15:49.139991498 +0900
133.242.231.xxx     @@ -1 +1,4 @@   ## Searchの結果をファイルに出力
133.242.231.xxx     +node[server1]
133.242.231.xxx     +node[server2]
133.242.231.xxx     +node[server3]
133.242.231.xxx 
133.242.231.xxx Running handlers:
133.242.231.xxx Running handlers complete
133.242.231.xxx Chef Client finished, 2/2 resources updated in 4.011358121 seconds

Data Bag,Searchの機能がちゃんと使えていることがわかりますね。

ちなみにローカルモードでknife statusも有効です。
最後にknife zero convergeを実行したのが何時なのかわかって助かりますね。

$ ./bin/knife status
47 minutes ago, server2, localhost, 133.242.230.xxx, ubuntu 12.04.
45 minutes ago, server3, localhost, 133.242.237.xxx, ubuntu 12.04.
6 minutes ago, server1, localhost, 133.242.231.xxx, ubuntu 12.04.

最後にserver1の現状をnode showで確認してチュートリアルをおわりましょう。

$ ./bin/knife node show server1
Node Name:   server1
Environment: development
FQDN:        localhost
IP:          133.242.231.xxx
Run List:    role[demorole]
Roles:       demorole
Recipes:     demobook::data_bag, demobook::search
Platform:    ubuntu 12.04
Tags:        

ワークフローの補足

ここで紹介しているワークフローは先日出版された『Chef活用ガイド』の内容を踏襲しています。
Chef-Solo系では難しかったワークフローだったのですが、ローカルモードを上手く使えばChef-Serverが無くてもむしろ書籍の内容をほぼ100%実践できます。

書中でもChef-Serverについて配布用のハブであり、情報の集約をするとしていますが、ローカルモード+Knife-Zeroがその役割を全部担える以上、Chef-Server本体は特に必要ありませんね。

Chef活用ガイド

おわりに

この例ではChefなので、ローカルのディレクトリをChef-Repoとしてだけ扱いました。ローカルディレクトリで完結することにはそれなりに意味があります、他のツールと組み合わせやすいんですよね。

なにかしらCLIでs3のバケットを確保してもよし、route53やdnsimpleのCLIでDNSをいじっても良いし、kumogataでCloudFormationを作ってみたりVagrantやTerraformでDigital Oceanのホストを作ったりherokuにアプリをおいてもOK。
で、Recipeが使いたい、構成情報をとっておきたいといったノードに対してのみChefをつかったり、Chef-MetalやChef-Container(Docker)と合わせるのも良いでしょう。

Test-KitchenやServerspecのテストコードをいれて、テストが通ったらほぼシームレスにNode(Searchで抽出)に適用するようなフローも可能です。

リソースが確保できるか/それがどこにあるか、どのようにリソースを使うか/使わてれいるか、またそれらはクエリ可能か、とこういった概ね現状がわかる情報をふくめたインフラの構成内容をツールで管理しつつGit等で追跡できるようになって、Infrastructure as Codeってやつが捗るんじゃないかと思います。