サーバー設定ツール「Chef」の概要と基礎的な使い方

chef-soloを使ったスタンドアロン構成

Chefで用いられるRecipeは、スタンドアロン構成でもクライアント/サーバー構成でも、どちらの場合でも基本的には同じものが利用できる。そのため、まずはスタンドアロン構成でChefを利用してRecipeの作成方法やCookbookの管理方法などを把握すると良い。また、クライアント/サーバー構成を取る場合はサーバーのインストールや設定などが必要であるため、管理するサーバーが少数の場合はそれぞれのマシンでchef-soloを使ったスタンドアロン構成を取ったほうが手間がかからない場合もある。

Chefクライアントのインストール

Chefはまだ歴史の浅いソフトウェアということもあり、ディストリビューションの公式パッケージとしては提供されていない場合が多い。また、提供されていてもそのバージョンが古いという場合もある。たとえばDebianでは安定版/不安定版の両方でパッケージが提供されているものの、提供されているのは現在の最新版であるバージョン11系(2013年8月現在でバージョン11.6.0)ではなく、その1つ前であるバージョン10系だ。そのため、最新版を利用したい場合はRubyのパッケージ管理システムであるRubyGemsを使ってChefクライアントを含む「chef」パッケージをインストールするのがおすすめだ。

CentOSの場合、RubyGemsを利用するにはRubyだけでなく、rubygemsパッケージのインストールが必要だ。そのほか、バイナリのビルドのためにruby-develやgcc、makeといったパッケージも必要となる。これらは次のようにyumコマンドでインストールできる。

# yum install ruby ruby-devel rubygems make gcc

続いて「gem install」コマンドでChefクライアントを含むchefパッケージをインストールする。

# gem install chef

これで、Recipeを実行するchef-soloコマンドやCookbook管理ツールであるknifeコマンドなどが利用できるようになる。

リポジトリとCookbookの作成

続いて、Cookbookの作成方法について紹介していこう。Chefでは、Cookbookなどのリソースを格納するディレクトリを「リポジトリ」と呼ぶ。まずは適当なディレクトリにリポジトリとして使用するディレクトリを作成する。

$ mkdir chef-repo

次に、リポジトリ内にCookbookを格納するディレクトリを作成する。

$ mkdir chef-repo/cookbooks

Cookbookはテキストファイルとディレクトリから構成される。手動で作成することも可能だが、「knife cookbook create <Cookbook名>」コマンドを利用することでそのひな形を自動生成できる。たとえば「setup-user」というCookbookを作成するには、以下のようにする。

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

knifeコマンドの「-o」オプションは、Cookbookを作成するディレクトリを指定するものだ。ここでは「.」を指定してカレントディレクトリに作成するよう指示している。なお、これを省略した場合は「/var/chef/cookbooks/」以下にCookbookが作成される。

Cookbookの構造

「knife cookbook create」コマンドで作成されたCookbookには、表1のようなディレクトリおよびファイルが用意される。

表1 Cookbookディレクトリ内のファイルおよびディレクトリ
ファイル/ディレクトリ名 説明
CHANGELOG.md Cookbookの変更履歴を記述する
README.md Cookbookの概要などを記述する
attributes Cookbookで使用するデフォルトのAttributeを記述したファイルを格納するディレクトリ
definitions 「Definition」と呼ばれる、リソースを組み合わせて新たなリソースを作成するための設定ファイルを格納するディレクトリ
files Cookbook内で利用されるファイルを格納するディレクトリ
libraries 「Library」と呼ばれる、Chefの機能を拡張するためのRubyコードを格納するディレクトリ
metadata.rb Cookbookに関する情報(メタデータ)を記述するファイル
providers 「Provider」と呼ばれる、リソースに対する処理を実行するための設定ファイルを格納するディレクトリ
recipes Recipe本体を格納するディレクトリ
resources 「Resource(リソース)」と呼ばれる、Recipe内で使われる設定対象を定義するための設定ファイルを格納するディレクトリ
templates Cookbook内で利用されるテンプレートファイルを格納するディレクトリ

このように並べると複雑そうに見えるが、多くの場合使われるのはこの一部のみで、Chefの機能を拡張したり新しいリソースタイプを定義しようとしない限りはdefinitionsやlibraries、providers、resourcesといったディレクトリは不要だ。不要なディレクトリについては削除して構わない。

ユーザーの管理を行うRecipeを作成する

それでは、実際にRecipeを作成して実行してみよう。ここで作成するのは、指定したグループおよびユーザーを作成するというものだ。Recipeは通常、knifeコマンドで作成されたCookbookのディレクトリ内にあるrecipesディレクトリ内に記述する。このディレクトリ内に「default.rb」というファイルが作成されているはずなので、今回はこのファイルにRecipeの内容を記述していく。

$ vi setup-user/recipes/default.rb

Recipeの一般的な記述ルールは以下のとおりだ。

<リソースタイプ> <リソース名> do
  <属性> <その値>
 :
 :
  action <リソースに対し実行するアクション>
end

「リソースタイプ」は、設定対象とするリソースの種別を指定するものだ。たとえばユーザーを作成するなら「user」、グループを作成するなら「group」となる。デフォルトのChefで利用できるリソース一覧はドキュメントのCookbooks項目にまとめられているので、そちらを参照してほしい。

また、「リソース名」は設定対象とするリソースを識別するための名前だ。この値はリソースタイプによって意味が異なるが、多くの場合そのリソースの名前(たとえば設定対象がユーザー/グループであればそのユーザー名/グループ名、ファイルであればそのファイルパス、サービスであればそのサービス名)を指定する。

「属性」は、そのリソースに対する設定値を指定するもので、また「action」はそのリソースに対してどのような処理(作成する、削除する、有効にする、無効にする、など)を実行するかを指示するものだ。属性やactionはリソースごとに指定できる値が異なるので、実際にRecipeを作成する際はドキュメントを参照してほしい。

なお、Recipeファイルは先にも述べたとおりRubyスクリプトとして解釈される。そのため、その基本的な文法はRubyそのままだ。行中の「#」から行末まではコメントとして解釈され、文字列は「”」もしくは「’」で囲むことで指定する。変数や関数の定義および利用も可能だ。

さて、今回記述する内容は、下記の太字で示した部分だ。default.rbファイル内にはあらかじめCookbook名やRecipe名、コピーライトなどの文言がヘッダとして記述されているので、それに続いてRecipe内で実行する処理を記述していくことになる。

#
# Cookbook Name:: setup-user
# Recipe:: default
#
# Copyright 2013, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#

group "taro" do
  gid 1000
  action :create
end

user "taro" do
  home "/home/taro"
  password '$6$OmC3KootOURrqOaP$63rwQ2bSE8op8wXa.ZWzgxm/iGvePTzEL5lOntmkPyYh5Qwh4lWs2DtyoEHcvsbYV5Q6a2ezzrZueb2ydrkhz0'
  shell "/bin/bash"
  uid 1000
  gid "taro"
  supports :manage_home => true
  action :create
end

ここではまず、「group」で「taro」というgroup型のリソースを定義している。actionには「:create」(リソースの作成)を指定し、「gid」属性ではグループIDを指定している。つまり、ここで指定した処理内容は「taro」というグループを作成し、そのグループIDを1000とする、というものになる。

続く「user」では、user型のリソースを定義している。user型のリソースもgroup型と同様、リソース名が作成するユーザー名となる。また、ホームディレクトリやパスワード、利用するシェル、ユーザーID、所属するグループなどの属性も指定している。なお、password属性の値にはハッシュ化したパスワードを指定する。ハッシュ化されたパスワードは「grub-crypt」コマンドで生成できる。

# grub-crypt –sha-512
Password: ←ハッシュ化したいパスワードを入力
Retype password: ←再度同じパスワードを入力
$6$OmC3KootOURrqOaP$63rwQ2bSE8op8wXa.ZWzgxm/iGvePTzEL5lOntmkPyYh5Qwh4lWs2DtyoEHcvsbYV5Q6a2ezzrZueb2ydrkhz0
↑ハッシュ化されたパスワードが表示される

なお、ChefのRecipeではファイル内に記述した順番で処理が実行される。そのため、userの設定よりも先にgroupの設定を記述しておく必要がある。

chef-soloコマンド用の設定ファイルを作成する

作成したCookbookは、chef-soloコマンドで実行できる。chef-soloコマンドの挙動はコマンドラインオプションのほか、設定ファイルで指定でき、そのパスはデフォルトでは/etc/chef/solo.rbファイルとなっている。このファイルは自動的には作成されないので、手動で作成しておく必要がある。

# mkdir /etc/chef
# vi /etc/chef/solo.rb

このファイルの内容についてはsolo.rbに関するドキュメントを参照してほしいが、今回はCookbookを格納しているディレクトリの指定のみを行うこととする。たとえば「/home/hylom/chef-repo/cookbooks」というディレクトリ内にCookbookを格納している場合、以下のように記述すれば良い。

cookbook_path [“/home/hylom/chef-repo/cookbooks”]

solo.rbファイルを作成したら、chef-soloコマンドでCookbookを実行してみよう。なお、実行にはroot権限が必要だ。実行するRecipe名は「-o」オプションで指定できる。Recipe名は「<Cookbook名>::<Recipe名>」という形で指定する。Recipe名を省略してCookbook名のみを指定することも可能だ。その場合、recipesディレクトリ内の「default.rb」というRecipeが実行される。

以下の例は、先ほど作成したsetup-userのdefault.rbというRecipeを実行したものだ。

# chef-solo -o setup-user
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
Converging 2 resources
Recipe: setup-user::default
* group[taro] action create
– create group[taro]

* user[taro] action create
– create user user[taro]

Chef Client finished, 2 resources updated

出力結果からは、Recipeファイルに記述したとおりにグループとユーザーが作成されていることが分かる。ちなみに、同じCookbookを再度実行すると、次のようにメッセージが表示される。

# chef-solo -o setup-user
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
Converging 3 resources
Recipe: setup-user::default
* group[taro] action create (up to date)
* user[taro] action create
* You must have ruby-shadow installed for password support!

ここでは「ruby-shadow」が必要と表示されているが、gemコマンドでこのパッケージをインストールすればこのメッセージは表示されなくなる。

# gem install ruby-shadow

実行するRecipeを指定する

先の例では-oオプションで実行するRecipeを指定したが、通常は実行するRecipeをファイルに記述し、そのファイルをコマンドラインオプションで指定するのが一般的だ。実行するRecipe一覧はJSON形式で記述し、chef-soloコマンドの-jオプションでそのファイルを指定する。

たとえば、先の「setup-user」Recipeを実行する場合、JSONファイルは以下のようになる。

{
  "run_list": [
    "recipe[setup-user]"
  ]
}

/etc/chef/solo.jsonというファイルにこれを記述した場合、次のようにしてchef-soloを実行する。

# chef-solo -j /etc/chef/solo.json

なお、ここで指定したJSONファイルではRecipeやCookbookに与えるパラメータ(Attribute)を記述することも可能だ。こちらについては後述する。

パッケージをインストールさせる

続いては、Chefのデフォルトで用意されているリソースタイプを使ったRecipeをいくつか紹介しておこう。まず、yum経由でパッケージをインストールするには「yum_package」リソースタイプを利用する。

yum_package <パッケージ名> do
  action :install
end

たとえば「sudo」パッケージをyumでインストールするRecipeは以下のようになる。

yum_package "sudo" do
  action :install
end

また、RPMファイルからパッケージをインストールするには、「rpm_package」リソースタイプを利用する。

rpm_package <パッケージ名> do
  source <RPMファイルのパス名>
  action :install
end

ただし、rpm_packageリソースタイプではローカルにあるファイルしかインストールできない。リモートにあるRPMファイルをインストールしたい場合、リモートからファイルをダウンロードする「remote_file」リソースタイプと組み合わせて利用する必要がある。

remote_file <ダウンロードしたファイルの保存先パス名> do
  source <ダウンロードするURL>
end

以下のRecipeは、「http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm」というURLで公開されているRPMファイルをダウンロードしてインストールするものだ。

remote_file "#{Chef::Config[:file_cache_path]}/epel-release-6-8.noarch.rpm" do
  source "http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm"
  not_if "rpm -qa | grep -q '^epel-release'""
  action :create
  notifies :install, "rpm_package[epel-release]", :immediately
end

rpm_package "epel-release" do
  source "#{Chef::Config[:file_cache_path]}/epel-release-6-8.noarch.rpm"
  action :nothing
end

「#{Chef::Config[:file_cache_path]}」はChefの設定データベース内で「file_cache_path」というキーに格納されている値を参照するという意味だ。ここにはファイルキャッシュとして使用するディレクトリのパス名が格納されている。また、「not_if」は指定した文字列を実行し、その結果が真でなければ処理を実行するよう指定するものだ。ここでは「epel-release」パッケージがインストールされていなければ処理を実行するよう指定している。さらに、「notifies」属性はそのリソースに対する処理が実行された際に、続けて実行するリソースを指定するものだ。ここでは「rpm_package」型の「epel-release」というリソースについて、即座に(immediately)インストールを実行するよう指定している。

「epel-release」リソースのactionに「:nothing」が指定されていることも注目したい。これが指定されたリソースは通常何の処理も実行されない。つまり、このRecipeはepel-releaseパッケージがインストールされていない場合にのみパッケージをダウンロードしてインストールする、という内容になる。

テンプレートを使う

次は、設定ファイルを指定したディレクトリに作成するRecipeを紹介しよう。内容としては、httpdパッケージをインストールしてhttpdサービスを起動し、/var/www/testというディレクトリと/etc/httpd/conf.d/mysite.confという設定ファイルを作成する、というものだ。

設定ファイルを作成する場合、そのひな形はtemplates/defaultディレクトリ内に格納する。また、テンプレートファイルはeRuby形式(拡張子は.erb)で記述する。今回の例では、templates/default/mysite.conf.erbとして設定ファイルを作成する。

NameVirtualHost *:8000
<VirtualHost *:8000>
        ServerName <%= @hostname %>
        DocumentRoot /var/www/test
        ErrorLog logs/test-error_log
        CustomLog logs/test-access_log common
</VirtualHost>

eRuby形式についての詳細は割愛するが、「<%」と「%>」 で囲まれた部分がRubyコードとして実行され、また「<%=」と「%>」で囲まれた部分はその実行結果に置き換えられる(「<% print」と「%>」で囲んだものと等価)。つまり、このテンプレートファイルでは「<%= @hostname %>」の部分がhostname変数の値に置き換えられる、ということになる。

この設定ファイルを利用するRecipeは次のようになる。

# httpdパッケージをインストールする
yum_package "httpd" do
  action :install
end

# httpdサービスを起動する
service "httpd" do
  action :start
end

# /var/www/testディレクトリを作成する
directory "/var/www/test" do
  owner "root"
  group "root"
  mode 0755
  action :create
end

# mysite.conf.erbというテンプレートから
# /etc/httpd/conf.d/mysite.confという設定ファイルを作成する
template "/etc/httpd/conf.d/mysite.conf" do
  source "mysite.conf.erb"
  owner "root"
  group "root"
  mode 0644
  action :create
  variables({ # テンプレートに与える変数の値を指定する
    :hostname => `/bin/hostname`.chomp
  })
end

設定内容はコメントに記載したとおりだが、注目したいのが「/etc/httpd/conf.d/mysite.conf」リソースでの「variables」属性だ。ここではテンプレートに与えるhostname変数の値を指定しているのだが、Rubyの「`」(バッククォート)構文を使って/bin/hostnameコマンドを実行し、その結果の行末の改行を取り除いたものを変数に格納している。このように、Rubyの機能を利用してRecipeを記述できるのがChefの特徴の1つだ。

コマンドを実行する

「execute」リソースタイプでは、特定のコマンドを実行するリソースを作成できる。実行するコマンドは「command」属性で指定する。また、actionには「:run」もしくは「:nothing」が指定できる。

execute <リソース名> do
  command <実行するコマンド>
  action <実行するアクション>
end

たとえば、sedコマンドを使って「/etc/yum.repos.d/epel.repo」という設定ファイルを編集するようなRecipeは、以下のように記述できる。

execute 'epel.repo' do
  command "/bin/sed -i -e 's/^enabled\s*=\s*1/enabled=0/g' /etc/yum.repos.d/epel.repo"
  action :nothing
  subscribes :run, "rpm_package[epel-release]", :immediately
end

ここで指定されている「subscribes」属性は、指定したリソースが実行された後に特定のactionを実行する、ということを指定するものだ。この例の場合、「rpm_package[epel-release]」というリソースが実行された場合、即座にこのリソースに対し「:run」というアクションを実行する、ということを意味している。

>>次ページ:公開されているCookbookを使う

おしらせ

banner_server

banner_writer