Edited at

Chefレシピ逆引きメモ

More than 3 years have passed since last update.

よく使うものを逆引きできるように。


アンチパターンを知る

http://www.slideshare.net/JulianDunn/beginner-chef-antipatterns

http://www.creationline.com/lab/3080


  1. すべてのChefデータを1つの巨大なGitレポジトリに入れてしまう


    • cookbooksにはバージョンがあるが、environmentsやrolesにはない

    • cookbooksとして分割すべきものはリポジトリを分けるべき



  2. 会社名つきの巨大なCookbookを作ってしまう


    • 本来組み合わせるべきでないものが混ざる危険がある

    • プロジェクト別に分けるべき



  3. Environmentsを論理的な環境以上の目的で使ってしまう


    • developmentとかproductionとか論理的な環境で使い、クラスタとかデータセンターといった割り当てに使わない



  4. Community Cookbookをフォークしてしまう


    • 開発元のバグ修正や機能追加といった恩恵を受け取れない、なるべくラップする方が良い



  5. Role内でrun_listを管理してしまう


    • roleはバージョンが付かない、代わりに include_recipe を使いrecipeでまとめる



  6. 無秩序なdata bagを作ってしまう


    • data bagとdata bag itemという2階層なので作る前に計画しておく



  7. chef-shellを知らない、使わない


    • Cookbook開発、デバッグに適している



  8. LWRPを怖がってしまう


    • 言うほどLWRPの実装は難しくない



  9. 外部発祥だから利用しない症候群に陥ってしまう


    • まず使えるものがあるか探し、変更が必要ならコントリビュートする



  10. 孤独なChef使いになってしまう


    • あるセットアップに自分より詳しいメンバーがいるなら任せ、チームで責任を持つ




レシピをチェックする

http://acrmp.github.io/foodcritic/

gem i foodcritic

foodcritic -C .

FC001など警告の内容についてはサイトに載っている。


FC001以外をチェックする

FC001はdeprecatedになった。FC001を除外して検証するには以下のようにする。

foodcritic -t ~FC001 site-cookbooks


ログを出す

logリソースを使う。でもレシピの一時的なデバッグならrubyのputspでもいいかもしれない。

log "a debug string" do

level :debug
end

log "message" do
message "This is the message that will be added to the log."
level :info
end


Vagrantのプロビジョニングでログレベルを変更する

log_level属性を使う。

http://docs.vagrantup.com/v2/provisioning/chef_common.html

config.vm.provision :chef_solo do |chef|

chef.log_level = :debug


nodeの属性を出力する

とりあえずjsonで

puts JSON.pretty_generate(node)

またはレシピ内で使いそうなものだけ確認。

[:platform, :platform_version, :ipaddress, :fqdn, :hostname, :domain].each do |key|

puts "node['#{key}'] = #{node[key]}"
end


置き換わったファイルのバックアップを見る

templateリソースなどでファイルを置き換えた場合に、元のファイルはリモートサーバの /var/chef/backup/ に保存されている。


パスワードのハッシュを生成する

Unixではパスワードを $<ハッシュ方式>$<salt>$<ハッシュ後のパスワード> で表現している。以下のコマンドでそれに対応したMD5のhashを出力できる。

openssl passwd -1 'password'


Environmentで分岐する

node.chef_environment を見る

if node.chef_environment == 'development'

end


OSで分岐する


OS

case node["platform"]

when "debian", "ubuntu"
# do debian/ubuntu things
when "redhat", "centos", "fedora"
# do redhat/centos/fedora things
end


OSカテゴリ

xx系で分岐する場合。yumかaptでpackage名が変わったりパスが変わったりするときなどで使う。

case node["platform_family"]

when "debian"
# do things on debian-ish platforms (debian, ubuntu, linuxmint)
when "rhel"
# do things on RHEL platforms (redhat, centos, scientific, etc)
end


テンポラリファイルのパスを組み立てる

foodcritic の FC013/tmp ではなく Chef::Config[:file_cache_path] を使えとある。

remote_file "#{Chef::Config[:file_cache_path]}/large-file.tar.gz" do

source "http://www.example.org/large-file.tar.gz"
end


事前に用意した静的ファイルを配置する

cookbook_fileリソースを使う。

デフォルトではファイルは上書きになる。上書きが困る場合は action: create_if_missingnot_if {File.exist?} などを使う。

# files/default/testfile

cookbook_file "/#{Chef::Config[:file_cache_path]}/testfile" do
source "testfile"
mode 00644
owner 'root'
group 'root'
end

配置する元ファイルは以下の順番で files のサブディレクトリから検索される。


  1. ホスト名 host-#{node[:fqdn]}

  2. OS-フルバージョン #{node[:platform]}-#{node[:platform_version]}

  3. OS-メジャーバージョン #{node[:platform]}-#{version_components}

  4. OS node[:platform]

  5. default

files/

host-foo.example.com
ubuntu-10.04
ubuntu-10
ubuntu
default


テンプレートを使ってファイルを配置する

templateリソースを使う。

cookbook_fileリソースとの違いは用意できるファイルがerbテンプレートであり動的に出力を変えられるところ。テンプレートのデフォルトのコンテキストはnodeオブジェクトで、variables属性で任意のhashをテンプレートに渡すことも可能。

template "/etc/apache2/ports.conf" do

source 'apache/ports.conf.erb'
mode '0644'
end

ソースのテンプレートファイルは files ディレクトリではなく、templates ディレクトリに配置する。

templates/

host-foo.example.com
ubuntu-10.04
ubuntu-10
ubuntu
default


書き換えてしまったファイルの前のバージョンを見る

cookbook_fileリソースやtemplateリソースで既存のファイルを上書きしてしまった場合に世代バックアップが/var/chef/backup にある。


空のファイルを作成する

fileリソースの: create_if_missingアクションを使う。(ファイルが無い時限定)

file "/tmp/something" do

action :create_if_missing
end


ファイルを削除する

fileリソースを使う。

file "/tmp/something" do

action :delete
end

削除対象がシンボリックリンクの場合は警告がでるので、linkリソースを使うのがエレガント。

link "/tmp/mylink" do

action :delete
only_if "test -L /tmp/mylink"
end


ディレクトリを作成する

directoryリソースを使う。

directory "/var/lib/foo" do

owner "root"
group "root"
mode 00755
action :create
end

親ディレクトリが存在しないと失敗する。recursive trueをつけると親ディレクトリを再帰的に作成する。


シンボリックリンクを作成する

linkリソースを使う。

link "/tmp/passwd" do

to "/etc/passwd"
end

link "/tmp/passwd" do
to "/etc/passwd"
link_type :hard
end

link "/tmp/mylink" do
action :delete
only_if "test -L /tmp/mylink"
end


ファイルがなければリソースを実行する

not_ifでファイルをチェックする。

execute "create file hoge" do

command "touch /tmp/hoge"
not_if {File.exist?("/tmp/hoge")}
end

Dir.exist? も使える(rubyの世界)


コマンドを実行する

executeリソースを使う。

execute 'bundle install' do

cwd '/myapp'
not_if 'bundle check' # This is not run inside /myapp
end


シェルファイルを実行する

正確には以下の例はbashリソースからコマンドを実行。

bash "install_ruby_build" do

cwd "#{Chef::Config[:file_cache_path]}/ruby-build"
user "rbenv"
group "rbenv"
code <<-EOH
./install.sh
EOH
environment 'PREFIX' => "/usr/local"
end


Gitリポジトリからファイルを取得する

gitリソースを使う。revision属性にタグなどを指定できる。

git "/home/#{node[:user]}/redmine"  do

repository "git://github.com/edavis10/redmine.git"
revision '2.5.1'
user node[:user]
group node[:user]
end


ウェブにあるアーカイブファイルを展開する

remote_fileリソースでダウンロード。bashリソースで展開。

#  the following code sample is similar to the ``upload_progress_module`` recipe in the ``nginx`` cookbook: https://github.com/opscode-cookbooks/nginx

src_filename = "foo123-nginx-module-v#{node['nginx']['foo123']['version']}.tar.gz"
src_filepath = "#{Chef::Config['file_cache_path']}/#{src_filename}"
extract_path = "#{Chef::Config['file_cache_path']}/nginx_foo123_module/#{node['nginx']['foo123']['checksum']}"

remote_file src_filepath do
source node['nginx']['foo123']['url']
checksum node['nginx']['foo123']['checksum']
owner 'root'
group 'root'
mode 00644
end

bash 'extract_module' do
cwd ::File.dirname(src_filepath)
code <<-EOH
mkdir -p
#{extract_path}
tar xzf
#{src_filename} -C #{extract_path}
mv
#{extract_path}/*/* #{extract_path}/
EOH
not_if { ::File.exist?(extract_path) }
end


hostsファイルにエントリを追加する

hostsfile cookbook を追加し、hostsfile_entry リソースを使う。

hostsfile_entry '1.2.3.4' do

hostname 'www2.example.com'
aliases ['foo.com', 'foobar.com']
comment 'Append by Recipe X'
action :append
end


ファイルを置き換えたのでサービスを再起動する

Notificationsを使う。

template '/etc/httpd/conf/httpd.conf' do

source 'httpd/httpd.conf.erb'
notifies :restart, 'service[httpd]'
end
service 'httpd' do
action [ :enable ]
end

notifiesで指定するリソース名が存在しないといけないので serviceリソースで :enable:nothingなどのActionで記述しておく。


Ohaiで取得して使える属性

属性
説明

node['platform']
nodeのプラットフォーム

node['platform_version']
プラットフォームのバージョン

node['ipaddress']
IPアドレス。nodeがデフォルトルートを持っている場合はIPv4アドレス、もっていない場合はnil

node['macaddress']
MACアドレス

node['fqdn']
完全修飾ドメイン名

node['hostname']
ホスト名

node['domain']
ドメイン

node['recipes']
関連付けられたレシピのリスト

node['roles']
関連付けられたroleのリスト

node['ohai_time']
Ohaiが最後に実行された時刻。knife statusサブコマンドでサーバに保存し参照できる