LoginSignup
2
2

More than 5 years have passed since last update.

Chef memo3

Posted at

Chef実践入門 ~コードによるインフラ構成の自動化 のまとめノート

3 レシピの書き方

3.1 リソースとは

  • service package templateといった部品。
  • Chefのレシピを書くということは、「Chefというフレームワークが用意したserviceやpackageといったDSLでリソースを定義する」ということ。

3.2 td-agentのレシピを読む

  • 複数のリソースをうまく使ったレシピ例を見る

groupとuser

  • それぞれOSのグループとユーザを定義するためのリソース。
  • アクションとして:createが定義されている。
group 'td-agent' do
  group_name 'td-agent'
  gid        403
  action     :create
end

user 'td-agent' do
  comment  'td-agent'
  uid      403
  group    'td-agent'
  home     'var/run/td-agent'
  shell    'bin/false'
  password nil
  supports :manage_home => true
  action   [:create, :manage]
end

  • userリソースいろいろ
user リソース名 do
 action
  :create(作成:デフォルト)
  :remove(削除)
  :modify(変更:該当ユーザーが存在しない場合エラー)
  :manage(変更:該当ユーザーが存在しない場合何もしない)
  :lock(ロック)
  :unlock(ロック解除)
  :nothing(何もしない)
 username "ユーザー名(デフォルト値:リソース名)"
 comment "コメント(デフォルト値:nil)"
 uid uid(デフォルト値:nil)
 gid "グループ名(デフォルト値:nil)"
 home "ホームディレクトリーのパス(デフォルト値:nil)"
 system
   nil(デフォルト)
   true(システムユーザー)
   false(非システムユーザー)
 shell "デフォルトシェルのパス(デフォルト値:nil)"
 password "パスワードのハッシュ値(デフォルト値:nil)"
 supports
  :manage_home => 
    false(ホームディレクトリーを作成しない:デフォルト)
    true(ホームディレクトリーを作成する)},
  :non_unique =>
    false(uidの重複を認めない:デフォルト)
    true(uidの重複を認める)
 retries リトライ回数(デフォルト値:0)
 retry_delay リトライ間隔[秒](デフォルト値:2)
 ignore_failure
   false(エラー時に終了:デフォルト)
   true(エラー時も継続) 
end

directory

  • 任意のディレクトリを定義するためのリソース
directory '/etc/td-agent' do
  owener 'td-agent'
  group  'td-agent'
  mode   '0755'
  action :create
end

caseによるOSの判定

  • node['platform']という変数に入っている値を軸にcase文で分岐処理を行っている。
  • ubuntu系とRedHat系の場合で分けている。
case node['platform']
when "ubuntu"
  dist = node['lsb']['codename']
  source = (dist == 'precise') ? "http://packages.treasure-data.com/precise/" : "http://packages.treasure-data.com/debian/"
  apt_repository "treasure-data" do
    uri source
    distribution dist
    components ["contrib"]
    action :add
  end
when "centos", "redhat"
  yum_repository "treasure-data" do
    url "http://packages.treasure-data.com/redhat/$basearch"
    action :add
  end
end

AttributeとOhai

Attrbute

  • テンプレートやレシピの中から参照できるkey-valueの値を管理する仕組み。
  • node['platform']はまさにそのAttrbuteで、ubuntuやredhatといった値が入ってくる。
  • Attrbuteはnodeオブジェクトに自分で設定できる。
  • Chefがシステムからあらかじめ抽出した値も入ってくる。

Ohai

  • ChefはOSから各種情報を集めてAttrbuteを構成するのにOhiとういRubyのライブラリを使う(Chefにpreinstall済み)。
  • データをJSON形式で生成してくれる。
# Ohaiの実行委結果
$ ohai | head
{
  "cpu": {
    "real": 2,
    "total": 4,
    "mhz": 2400,
    "vendor_id": "GenuineIntel\n",
    "model_name": "Intel(R) Core(TM) i5-2435M CPU @ 2.40GHz\n",
    "model": 42,
    "family": 6,
    "stepping": 7,

# 引数にキーを指定すると任意の値のみ取得できる
$ ohai platform
[
  "mac_os_x"
]
  • Ohaiの値をChefで実行したい場合には、レシピ内で node[:platform]のように書いて取得できる。

template、package、service

template "/etc/td-agent/td-agent.conf" do
  mode "0644"
  source "td-agent.conf.erb"
end

package "td-agent" do
  options value_for_platform(
    ["ubuntu", "debian"] => {"default" => "-f --force-yes"},
    "default" => nil
  )
  action :upgrade
end

service "td-agent" do
  action [ :enable, :start ]
  subscribes :restart, resources(:template => "/etc/td-agent/td-agent.conf")
end
  • 以上がtd-agentのレシピ。

3.3 主要なリソース解説

  • Chefが標準で提供しているリソースのうちよく使うものを中心に説明する。

package

基本的な使い方

  • OSのソフトウェアパッケージを扱うためのリソース。
  • プラットフォームにあわせてパッケージを選択してくれる。
package "git" do
  action :install
end

複数パッケージをインストールする

  • Rubyのシンタックス使う。
%w{gcc make git}.each do |pkg|
  package pkg do
    action :install
  end
end

バージョンを指定する

  • バージョン指定でバージョンを固定できる。
  • action:installを:upgradeにすると、レシピを複数回実行したとき既存のパッケージが古い場合に最新版に入れ替える。
package "perl" do
  action :install
  version "5.10.1"
end

パッケージを削除する

package "perl" do
  action :remove
end

パッケージを指定する

  • パッケージを指定したファイルからインストールする
package "tar" do
  action :install
  source "/tmp/tar-1.16.1-1.rpm"
end

オプションを指定する

package "debian-archive-keyring" do
 action :install
 options :"--force-yes"
end

service

  • Webサービスやデータベースのような「サービス」の状態を記述するのがserviceリソース。

基本的な使い方

  • Apacheを起動する
  • action行でサービスを有効かつ起動している。
  • support行でstatus,restart,reloadを有効にしている。
service "httpd" do
  action [ :enable, :start ]
  supports :status => true, :restart => true, :reload => true
end

Notificationとserviceを組み合わせる

  • httpd.confが更新された場合にreloadする
  • notifiesは第一引数にアクション、第二引数にresource_type[resource_name]の形式で記述する。
  • notifies(通知先)に指定できるのはserviceに限らない。以下のようにexecuteリソースも実行できる。
    notifies :run, "execute[test-nagios-config]"
service "httpd" do
  supports :status => true, :restart => true, :reload => true
  action [ :enable, :start ]
end

template "httpd.conf" do
  path "/etc/httpd/conf/httpd.conf"
  owner "root"
  group "root"
  mode 0644
  notifies :reload, 'service[httpd]'
end

Notificationのタイミング

  • Notificationの実行は、Chef全体の実行の限りなく終盤。
  • これにより通知を送る側はあまり順番を気にしなくていい。
  • notifiesの第三引数に :immediately を渡すと即座に実行される。

Subscribe

  • なんらかのリソースに変化があったらアクションに利用するのがSubscribe。
  • 以下は、td-agent.confが更新されたらサービスをrestartするというアクション。
service "td-agent" do
  support :status => true, :restart => true, :reload => true
  action [ :enable, :start]
  subscribes :restart, "template[ts-agent.conf]"
end

template

  • 設定ファイルなど外部ファイルを使うリソース。
  • Attrbuteの値をテンプレート内で展開したい場合に利用する。
  • Attrbuteを使わなければ静的ファイルを操作する目的のcookbook_fileを使って定義する。

基本的な使い方

  • httpd.confをテンプレートから生成する。
  • テンプレートはクックブックディレクトリ内のtemplates/default/httpd.conf.erbが利用される。
template "httpd.conf" do
  path "/etc/httpd/conf/httpd.conf"
  source "httpd.conf.erb"
  owner "root"
  group "root"
  mode 0644
end

// 簡略化
template "/etc/httpd/conf/httpd.conf" do
  source "httpd.conf.erb"
  owner "root"
  group "root"
  mode 0644
end

// さらに簡略化(templates/default/httpd.conf.erbが利用される)
template "/etc/httpd/conf/httpd.conf" do
  owner "root"
  group "root"
  mode 0644
end

テンプレート内ではAttrbuteが使える

  • たとえば、node[:platform] は <%= node[:platform] %> と書く。
  • ChefのtemplateリソースはERBが前提。

userとgroup

user

  • ユーザー定義の例
user "naoya" do
  comment "naoya"
  home "/home/naoya"
  shell "/bin/bash"
  password nil
  supports :manage_home => true // ユーザを新規作成した時にホームディレクトリを一緒に作る
  action   [:create, :manage]
end

group

  • グループ追加の例
group "webdb" do
  gid 999
  members ['naoya', 'inao']
  action :create
end
  • 既存グループへのユーザ追加の例
group "admin" do
  action :modify
  members [ 'dikeda' ]
  append true
end

directory

  • ディレクトリの定義
directory '/etc/td-agent/' do
  owner  'td-agent'
  group  'td-agent'
  mode   '0755'
  action :create
end

cookbook_file

  • cookbook_fileを使うと、クックブックに同梱したファイルを任意のパスへ転送できる。
  • templateはAttrbuteを使いたい場合に。cookbook_fileは静的なファイルを扱いたい場合に。

基本

  • RPMファイルをテンポラリディレクトリに転送する
  • テンポラリディレクトリのパスはハードコードせずにChefが設定で持っているパスを使用する。
cookbook_file "#{Chef::Config[:file_cache_path]}/supervisor-3.0a12-2.el6.noarch.rpm" do
  mode 00644
end
  • ソースファイルを明示的に指定する。(転送先で名前を変更する)
cookbook_file "#{Chef::Config[:file_cache_path]}/supervisor-3.0.rpm" do
  source "supervisor-3.0a12-2.el6.noarch.rpm"
  mode 00644
end

チェックサムを利用する

  • 破損や改さん防止にチェックサムを使う。
  • チェックサムが合致しない場合は実行時エラーになる。
  • ChefのファイルチェックサムはSHA-256が前提。
cookbook_file "#{Chef::Config[:file_cache_path]}/supervisor-3.0a12-2.el6.noarch.rpm" do
  source "supervisor-3.0a12-2.el6.noarch.rpm"
  mode 00644
  checksum "012f34db9e08f67e6060d7ab8d16c264b93cba82fb65b52090f0d342c406fbf7"
end

インフラレイヤーのリソース

ifconfig

ifconfig "192.168.30.1" do
  device "eth0"
end

mount

mount "/mnt/volume1" do
  device "volume1"
  device_type :label
  fstype "xfs"
  options "rw"
end

script

  • scriptリソースは内部に定義したシェルスクリプトなどのスクリプトをroot権限で実行できる。
  • 冪等性は自分で保証する必用がある。

script(bash)

  • perbrewをインストールする際にcurlでインストーラーを実行するが、シェルスクリプトによるインストーラーの扱いがpackageでは難しいので以下のように記述する。
# shellの場合
$ curl -kL http://install.perlbrew.pl | bash
// Chefの場合
bash "install perlbrew" do
  user 'vagrant'
  group 'vagrant'
  cwd '/home/vagrant' // カレントワーキングディレクトリ
  environment "HOME" => '/home/vagrant' // 環境変数
  // ヒアドキュメントでscriptを定義
  code <<-EOC
    curl -kL http://install.perlbrew.pl | bash
  EOC
  creates "/home/vagrant/perl5/perlbrew/bin/perlbrew"   // このコマンドがこのファイルを作成するであろうことを指示し、かつすでにそのファイルがある場合はこのコマンドを実行しない
end
  • perlbrewの実行ファイルが存在するかどうかをインストールの有無の判定に使っているのが欠点。

not_if, only_if

  • not_if: 指定した条件が真でないならコマンドを実行する。
  • only_if: 指定した条件が真のときのみコマンドを実行する。
  • たとえば、createsと同じ事は、
    not_if {File.exists?("/home/vagrant/perl5/perlbrew/bin/perlbrew")}
    と記述することもできる。
// not_ifの使用例
// rubybuildの存在有無をガード節に使っている
bash "install-rubybuild" do
  not_if 'which ruby-build'
  code <<-EOC
    cd /tmp/ruby-build
    ./install.sh
  EOC
end
// not_ifやonly_ifでの条件判定の例
not_if <<-EOC, :user => 'vagrant', :environment => { 'HOME' => '/home/vagrant' }
    略
EOC

3.4 そのほかのリソース

  • ドキュメント参照

3.5 AttributeとData Bag

  • Attribute: ノードに紐つく属性のうち、固定的にあつかうものではないもの。
  • Data Bag: ユーザの各種データなどノードの属性でもない、リソース属性でもないものを定義する。

Attribute

  • Nodeオブジェクトの記述例
{
  "httpd" : {
    "port" :80
  },
  "run_list": [
    "recipe[git]",
    "recipe[apache]",
    "recipe[mysql]"
  ]
}
  • node['httpd']['port']のようにキーに文字列を使うのが慣習。

Attributeの初期値

  • Attributeはデフォルト値を決めておくことができる。
  • 初期値があらかじめクックブック内に定義しておく
  • JSONファイルでノードごとに値を定義しておく
default["apache"]["dir"] = "/etc/apache2"
default["apache"]["listen_ports"] = [ "80", "443" ]

Data Bag

  • 各ノードで共有するようなデータはDataBagを使って定義する。
  • 複数ユーザがいる状態を定義したい場合など。

各ノードで共有したいデータを準備する

  • DataBagで扱うデータは<リポジトリ>/data_bagsディレクトリに置く。
# Data Bagディレクトリの構造例
├─ Berksfile
├─ Vagrantfile
├─ cookbooks
├─ data_bags
    ├─ users
        ├─ naoya,json
        ├─ inao.json

{
"id" : "naoya",
"username" : "naoya",
"home" : "/home/naoya",
"shell" : "/bin/bash"
}
```

{
  "id" : "inao",
  "username" : "inao",
  "home" : "/home/inao",
  "shell" : "/bin/inao"
}

データを利用する

  • Data Bagからの値の取得例
# login_users/recipes/default.rb
data_ids = data_bag('users')

data_ids.each do |id|
  u = data_bag_item('users', id)
  user u['username'] do
    home  u['home']
    shell u['shell']
  end
end

データを暗号化する

  • Data Bagにはパスワードや鍵等のデータを暗号化して格納しセキュアに扱う方法もある。
    • chef solo encrypted data bags
    • knife solo data bag

3.6 クックブックのディレクトリレイアウト

  • ドキュメント参照
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2