よく使うものを逆引きできるように。
アンチパターンを知る
http://www.slideshare.net/JulianDunn/beginner-chef-antipatterns
http://www.creationline.com/lab/3080
- すべてのChefデータを1つの巨大なGitレポジトリに入れてしまう
- cookbooksにはバージョンがあるが、environmentsやrolesにはない
- cookbooksとして分割すべきものはリポジトリを分けるべき
- 会社名つきの巨大なCookbookを作ってしまう
- 本来組み合わせるべきでないものが混ざる危険がある
- プロジェクト別に分けるべき
- Environmentsを論理的な環境以上の目的で使ってしまう
- developmentとかproductionとか論理的な環境で使い、クラスタとかデータセンターといった割り当てに使わない
- Community Cookbookをフォークしてしまう
- 開発元のバグ修正や機能追加といった恩恵を受け取れない、なるべくラップする方が良い
- Role内でrun_listを管理してしまう
- roleはバージョンが付かない、代わりに
include_recipe
を使いrecipeでまとめる
- 無秩序なdata bagを作ってしまう
- data bagとdata bag itemという2階層なので作る前に計画しておく
- chef-shellを知らない、使わない
- Cookbook開発、デバッグに適している
- LWRPを怖がってしまう
- 言うほどLWRPの実装は難しくない
- 外部発祥だから利用しない症候群に陥ってしまう
- まず使えるものがあるか探し、変更が必要ならコントリビュートする
- 孤独なChef使いになってしまう
- あるセットアップに自分より詳しいメンバーがいるなら任せ、チームで責任を持つ
レシピをチェックする
gem i foodcritic
foodcritic -C .
FC001など警告の内容についてはサイトに載っている。
FC001以外をチェックする
FC001
はdeprecatedになった。FC001
を除外して検証するには以下のようにする。
foodcritic -t ~FC001 site-cookbooks
ログを出す
logリソースを使う。でもレシピの一時的なデバッグならrubyのputs
やp
でもいいかもしれない。
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_missing
や not_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
のサブディレクトリから検索される。
- ホスト名
host-#{node[:fqdn]}
- OS-フルバージョン
#{node[:platform]}-#{node[:platform_version]}
- OS-メジャーバージョン
#{node[:platform]}-#{version_components}
- OS
node[:platform]
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サブコマンドでサーバに保存し参照できる |