近年注目されているサーバー管理ツール「Chef(シェフ)」は、ファイルに記述した設定内容に応じて自動的にユーザーの作成やパッケージのインストール、設定ファイルの編集などを行うツールだ。今回はこのChefについて、基本的な環境構築方法と使い方を紹介する。
Chefは米Opscodeが開発しているオープンソースソフトウェアで、Rubyなどのオープンソースな技術を使って実装されている。ライセンスはApache License 2.0だ。同社はChefにいくつかの機能を追加した有償版の「Private Chef」やクラウド型の「Hosted Chef」といったサービスも提供しているが、本記事ではオープンソース版のChefについて紹介する。
ChefとPuppetはともに設定ファイルに応じてサーバーの設定を行うツールという点では同じだが、Chefでは「Cookbook(クックブック)」や「Recipe(レシピ)」と呼ばれる設定ファイルの再利用がしやすい構造になっている点が特徴だ。Cookbookの構成はやや複雑になっているものの、Chefの開発元やサードパーティが提供しているCookbookを利用することで、少ない記述でサーバーの設定を実行できるようになっている(図1)。

ChefのRecipeはRubyスクリプトとなっているのも特徴だ。そのためRubyとの親和性が高く、Rubyの知識がある人にとってはその動作の仕組みや構造を理解しやすいというメリットがある。ただ、エラー発生時にはRubyの出力するエラーメッセージを読まなければならないため、逆にRubyの知識がない人にとってはトラブルシューティングのハードルが高いかもしれない。
Chefのアーキテクチャと構成要素
Chefはフランス語での「料理人」という言葉が由来になっており、その構成要素も料理をモチーフにして命名されている。まず、Chefでは設定内容を記述したファイルのことを「Recipe(レシピ)」と呼ぶ。ChefのRecipeはRubyの実行ファイルとなっており、その拡張子は.rbだ。Chefは広義にはサーバー設定を行うための関数やクラスといった機能を提供するRubyライブラリおよびヘルパーアプリケーション集であるとも言える。
また、Recipeの管理単位を「Cookbook(クックブック)」と呼ぶ。CookbookにはRecipeに加え、設定ファイルを作成するための「Template(テンプレート)」や、環境に応じてその値を変更できる変数を定義した「Attribute(アトリビュート)」などが含まれている。Chefでは処理内容や対象とするアプリケーションごとにCookbookを作成するのが一般的で、Recipeでは環境に依存しないように設定を記述し、Attributeでその内容を制御する、という使い方が推奨されている。Recipe内からはほかのCookbookやRecipeを参照して利用することも可能だ。
Chefで管理対象とするサーバーの設定項目や設定ファイルなどは、「Resource(リソース)」と呼ばれる。リソースには型(リソースタイプ)があり、たとえばユーザーの作成や削除には「user」というリソースタイプを、Yumによるパッケージ操作については「yum_package」というリソースタイプを利用する。Chefでは基本的なシステム管理に必要となるリソースタイプがあらかじめで用意されているほか、Cookbook内で新たなリソースタイプを定義することも可能だ。
Cookbookは自分で作成するだけでなく、公開されているものを利用することも可能だ。Opscodeが運営するコミュニティサイト(http://community.opscode.com/)にはChefを開発するOpscodeやサードパーティの開発者によって作成されたCookbookがまとめられており、無料でダウンロードして利用できる(図1)。
公開されているCookbookは、MySQLやApacheといったアプリケーションのインストールや設定を行うものからユーザーの作成などシステム管理に関わるもの、iptablesなどOSの特定機能の設定を行うものまで、多岐にわたる。これらを利用することで、自分ではほとんどRecipeを書くことなしにサーバーの設定を行うことも可能だ。
Chefによるサーバー管理構成
Chefを利用するための構成としては、1台のサーバー内でCookbookの作成や管理、実行などをすべて完結させるスタンドアロン構成と、Cookbookをサーバーで集中管理し、クライアントはサーバーからCookbookをダウンロードして実行するというクライアント/サーバー構成の2通りがある。
まずスタンドアロン構成の場合だが、この場合はサーバーソフトウェアのインストールは不要で、クライアントのみが必要だ。Recipeの実行はクライアントに含まれる「chef-solo」というコマンドで行う。
いっぽうクライアント/サーバー構成の場合、サーバー側にはChefサーバー、「Node(ノード)」と呼ばれるクライアント側にはChefクライアントのインストールが必要となる。
クライアント/サーバー構成の場合、サーバー側でRecipeの作成や検証作業を行っても良いのだが、このような作業は別のマシン上で行うこともできる。このようにRecipeの作成や管理を行うマシンを「Workstation(ワークステーション)」と呼ぶ。Workstationでのレシピの作成や環境管理などには、「knife」というツールを利用する。knifeはChefクライアントをインストールすると同時にインストールされる。
さて、以下ではまずchef-soloを利用するスタンドアロン構成を使ってChefの基本的な使い方やCookbook/Recipeの利用方法を解説し、続いてクライアント/サーバー構成についても紹介していく。
なお、以下で利用している環境はクライアント/サーバーともにRed Hat Enterprise Linux 6.4互換であるCentOS 6.4(x86_64)だ。
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のようなディレクトリおよびファイルが用意される。
ファイル/ディレクトリ名 | 説明 |
---|---|
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を使う
続いては、Chefの開発元であるOpscodeやサードパーティが公開しているCookbookを利用する方法について述べていこう。
Chefが注目されている理由の1つに、非常に多数のCookbookが公開されている点がある。Opscodeが運営するコミュニティ向けサイト(http://community.opscode.com/)ではOpscodeやサードパーティが作成したCookbookが公開されており、その数は1000を超えている。公開されているCookbookはGCCやmakeなどの基本的なコンパイル環境を構築する「build-essential」やJava環境を構築する「java」といったものから、「apache2」や「mysql」といった特定のアプリケーションのインストールおよび設定を行うもの、「application」などの独自のCookbookやRecipe作成を支援するライブラリ的なもの、特定の設定ファイルやOS設定を操作するための「ssh_knows_hosts」や「sudo」、「iptables」など、多岐にわたる。
ChefにはCookbook実行時の処理内容を変数などで制御できるattributeや、設定処理に必要となるデータを一括管理するData Bagといった仕組みが用意されており、公開されているCookbookとこれらを組み合わせることで、Recipeを一切自作することなしにサーバー設定を行うことも可能になる。
以下ではこのような外部で公開されているCookbookを利用する例として、MySQLやそのクライアント、関連ライブラリなどをインストールする「mysql」と、データベースの作成や管理を行う「database」というCookbookを利用する例を紹介しよう。
Cookbookのインストール
Opscodeのコミュニティサイトで公開されているCookbookは、その個別ページ内にある「Download」リンクからダウンロードできる。ダウンロードしたファイルはtarおよびgzipで圧縮されており、これをCookbookを格納しているディレクトリに展開すれば良い。
$ cp mysql.tgz ~/chef-repo/cookbooks ←ダウンロードしたCookbookのアーカイブをCookbook格納ディレクトリにコピー
$ cd ~/chef-repo/cookbooks ←Cookbook格納ディレクトリに移動
$ tar xvzf mysql.tgz ←Cookbookを展開する
また、Gitなどのバージョン管理システムのリポジトリが公開されているものもある。この場合、そのリポジトリから直接ソースツリーを入手しても良い。mysql Cookbookの場合、「https://github.com/opscode-cookbooks/mysql.git」というリポジトリからの入手が可能だ。
$ cd ~/chef-repo/cookbooks
$ git clone https://github.com/opscode-cookbooks/mysql.git
なお、mysql CookbookではRuby向けのクライアントライブラリのインストールなどを行うため、build-essentialというCookbookを内部で呼び出している。また、パスワードのハッシュ化などのためにopensslというCookbookも同様に利用する。これらもダウンロードして展開しておく。
$ git clone https://github.com/opscode-cookbooks/build-essential.git
$ git clone https://github.com/opscode-cookbooks/openssl.git
なお、このように依存関係にあるCookbookについては、必要となった時点で自動的に実行されるため、明示的にユーザーが実行する必要は通常はない。
インストールが完了したら、Cookbookを実行してみよう。たとえばMySQLクライアントをインストールするには、「mysql::client」というRecipeを実行する。
# chef-solo -o mysql::client
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
Converging 2 resources
Recipe: mysql::client
* package[mysql] action install
- install version 5.1.69-1.el6_4 of package mysql* package[mysql-devel] action install
- install version 5.1.69-1.el6_4 of package mysql-develChef Client finished, 2 resources updated
Recipeの実行結果から、「mysql」および「mysql-devel」というパッケージがインストールされていることが分かる。ここではCentOS環境でこのRecipeを実行しているが、たとえばDebianなど異なる環境では、それぞれの環境に対応したパッケージ(Debianの場合「mysql-client」および「libmysqlclient15-dev」)がインストールされる。これは、環境に応じて適切なパッケージをインストールするようにRecipeが記述されているからだ。
mysql Cookbookでは、RubyからMySQLにアクセスするために必要なgemパッケージ(mysqlパッケージ)をインストールするための「mysql::ruby」というRecipeも用意されている。
# chef-solo -o mysql::ruby
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
Recipe: build-essential::rhel
* package[autoconf] action install
- install version 2.63-5.1.el6 of package autoconf
:
:
Recipe: mysql::ruby
* chef_gem[mysql] action install
- install version 2.9.1 of package mysql
この場合、gemをビルドしてインストールするために必要な関連ツールも同時にインストールされていることが分かる。これらは、build-essential Cookbookを利用してインストールされている。
MySQLサーバーをインストールするためのRecipeは「mysql::server」となっている。このRecipeを利用する場合、MySQLサーバーのルートパスワードの指定が必要となる。これはRecipeやCookbook内ではなく、chef_soloコマンドの-jオプションで指定するJSONファイル内で指定する。たとえばパスワードを「FooBar13579」に設定する場合、JSONファイルは以下のようになる。
{ "mysql": { "server_root_password": "FooBar13579", "server_repl_password": "FooBar13579", "server_debian_password": "FooBar13579" }, "run_list": [ "recipe[mysql::server]" ] }
なお、「server_root_password」だけでなく、「server_repl_password」や「server_debian_password」の設定も必須のようだ。設定ファイルを作成したら、次のように実行することでMySQLサーバーをインストールできる。
# chef-solo -j /etc/chef/solo.json
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
:
:
Recipe: mysql::client
* package[mysql] action install (up to date)
* package[mysql-devel] action install (up to date)
Recipe: mysql::server
* package[mysql-server] action install
- install version 5.1.69-1.el6_4 of package mysql-server
:
:
* template[/etc/mysql_grants.sql] action create
- create new file /etc/mysql_grants.sql
- update content in file /etc/mysql_grants.sql from none to 2b12ef
:
:
* service[mysql] action start (up to date)
Chef Client finished, 11 resources updated
実行結果は一部省略しているが、Recipeを実行するとMySQLサーバーのインストールや設定ファイルの作成、サービスの実行、rootユーザーのパスワード設定などが行われる。
ここではrootユーザーのパスワードのみをJSONファイル内で指定しているが、それ以外にも設定ファイルのディレクトリやPIDファイルの作成先、待ち受けを行うIPアドレスやポートなどを同じくJSONファイル内で指定することが可能だ。これらについては、ドキュメントを参照してほしい。
Cookbookダウンロードツールを利用する
さて、CookbookはOpscodeのコミュニティサイトやGitリポジトリから入手できるが、先のmysql Cookbookの場合でもあったように、Cookbookを利用する際に別のCookbookが必要になることがある。依存するCookbookが多い場合、それぞれを手動でダウンロードするのは面倒だ。そこで、そのような作業を自動で行うための「librarian-chef」や「berkshelf」といったツールが公開されている。
両者ともに「依存するCookbookをまとめてインストールする」という機能は同じだが、最近ではberkshelfが勧められている。しかし、berkshelfの実行にはRuby 1.9.3以上が必要であるため、環境によっては利用できないことがある。そこで、今回はRuby 1.8系でも利用できるlibrarian-chefのほうを紹介しておこう。
librarian-chefはRubyGemsで公開されており、gemコマンドでインストールできる。
# gem install librarian-chef
librarian-chefでは、「Cheffile」と呼ばれる設定ファイルを作成して「librarian-chef install」コマンドを実行することでCookbookをインストールできる。Cheffileのひな形は、「librarian-chef init」コマンドで作成可能だ。
$ librarian-chef init
create Cheffile
インストールするCookbookは、このファイル内の「cookbook」行で指定する。たとえば「database」というCookbookをインストールするCheffileの内容は以下のようになる。
#!/usr/bin/env ruby
#^syntax detectionsite ‘http://community.opscode.com/api/v1′
cookbook ‘database’
ここで、太字の行がひな形に追記した部分だ。続いて「librarian-chef install」コマンドを実行すると、実行したディレクトリにcookbooksディレクトリが作成され、そこに指定したCookbookと、依存するCookbookがインストールされる。
$ librarian-chef install
Installing aws (0.101.2)
Installing apt (2.0.0)
Installing build-essential (1.4.0)
Installing openssl (1.0.2)
Installing postgresql (3.0.2)
Installing mysql (3.0.2)
Installing xfs (1.1.0)
Installing database (1.4.0)
なお、このコマンドを実行すると既存のcookbooksディレクトリは上書きされてしまうため、実行の際は注意したい。
既存のCookbookを利用してMySQLデータベースを作成する
さて、先にlibrarian-chefでインストールしたdatabase Cookbookは、MySQLなどのデータベースやそのユーザー設定を行うものだ。続いてはこのCookbookを使って、データベースおよびユーザーを作成する例を紹介しておこう。
まず、データベースやユーザーを作成するためのCookbookのひな形をknifeコマンドで作成する。今回は「mysql-db」という名称でこのCookbookを作成することとした。
$ knife cookbook create mysql-db -o .
次に、作成したCookbookのRecipeのひな形を編集する。
$ vi mysql-db/recipes/default.rb
Recipeの内容は以下のようにした。処理内容はコメントを参照してほしいが、始めに「include_recipe “database::mysql”」でdatabase Cookbook内の「mysql」というRecipeを読み込んでいる。これにより、database Cookbookで定義されている「mysql_database」や「mysql_database_user」といったリソースが利用可能となる。これらのリソースについては、database Cookbookのドキュメントを参照してほしい。それぞれのリソースでは「connection」属性でデータベース接続に使用するアカウントを定義するが、ここでは「connection_info」変数にそれらの情報を格納して利用している。
# database::mysqlレシピを使用する include_recipe "database::mysql" # データベース接続に使用するアカウント情報を定義する # パスワードはJSONファイル内に記述されたものを使用する connection_info = ({ :host => "localhost", :username => "root", :password => "FooBar2000" }) # 「testdb」データベースを作成する mysql_database 'testdb' do connection connection_info action :create end # 「testuser」ユーザーを作成しそのアクセス権とパスワードを設定する mysql_database_user 'testuser' do connection connection_info password 'testpassword' database_name 'testdb' host '%' privileges [:all] action :grant end
Recipeを作成したら、続いてchef-soloを実行する際に指定するsolo.jsonファイルを以下のように変更する。
{ "run_list": [ "recipe[database::mysql]", "recipe[mysql-db]" ] }
最後にchef-soloコマンドを実行すると、以下のようにデータベースやユーザーの作成、権限の設定が行われる。
# chef-solo -j /etc/chef/solo.json
Starting Chef Client, version 11.6.0
Compiling Cookbooks…
:
:
Recipe: mysql-db::default
* mysql_database[testdb] action create
* mysql_database_user[testuser] action grantChef Client finished, 2 resources updated
Chefをクライアント/サーバー構成で利用する
ここまでは、Chefを単一のサーバー内で完結するスタンドアロン構成で利用していたが、クライアント/サーバー構成でChefを利用する方法についても簡単ではあるが紹介しておこう。クライアント/サーバー構成を取る場合、Cookbookなどをサーバー側で集中管理できるのが特徴となる。
Chefサーバーのインストール
クライアント/サーバー構成でChefを利用する場合、まずChefサーバーを構築する必要がある。Chefサーバー(バージョン11以降)はErlang言語を使って実装されているため、RubyGemsでは配布されていない。そのため、自分でソースコードからビルドするか、Opscodeが配布しているパッケージを利用してインストールすることになる。
Opscodeが配布しているパッケージは、Opscodeのダウンロードページから入手できる。ただし、対応プラットフォームはRed Hat Enterprise Linux(RHEL) 5/6とUbuntu 10.04~12.10のみで、またx86_64版のみしか用意されていないので注意したい。
なお、この配布パッケージは/opt/chef以下にChefサーバーやRubyおよびErlangのランタイム環境、そしてPostgreSQL、RabbitMQ、rsync、OpenSSLといったChefサーバーが依存するソフトウェアをすべてインストールするもので、500MB程度の容量が必要となる。また、すでにPostgreSQLやRabbitMQなどがインストールされているサーバーの場合、ポート番号の競合などが発生する可能性があるので注意したい。
また、Chefサーバーには「example.com」のようなFQDNが必要だ(「example」などの非FQDNなサーバー名では不可)。そのため、ローカルネットワークなどで運用する場合はネットワーク内にDNSサーバーを用意したり、/etc/hostsファイルを利用するなどしてFQDNとIPアドレスの相互変換ができるように設定しておく必要がある。
/etc/hostsファイルを利用する場合、たとえばホスト名が「centos」なら次のような項目をこのファイルに記述しておけば良い。
<ホストのIPアドレス> centos.<適当なドメイン> centos
ここで、hostnameコマンドで確認できるホスト名からIPアドレスに変換できるように設定しておく必要がある点に注意したい。
Opscodeが配布しているパッケージをインストールすると、サーバーの設定や起動/停止/再起動などを行うための「chef-server-ctl」コマンドがインストールされる。パッケージのインストール後は、まず「chef-server-ctl reconfigure」コマンドを実行して設定を行う必要がある。
# chef-server-ctl reconfigure
また、ChefサーバーとクライアントはTCPの443ポートで通信を行うので、このポートに外部から接続できるようファイアウォールやネットワークの設定をしておこう。
Workstationの設定
始めに述べたとおり、ChefではChefサーバーの操作を行う端末を「Workstation」と呼ぶ。続いてはこのWorkstationの設定を行っていく。WorkstationはChefサーバーと同じマシンでも構わないが、その場合でも下記の設定は必要となる。
Workstationで必要なソフトウェアはスタンドアロン構成の場合と同様、chefパッケージに含まれているのでこれをインストールする。
# yum install ruby ruby-devel rubygems make gcc
# gem install chef
また、Chefサーバーに接続するための証明書なども必要となる。Chefサーバーをインストールしたマシンの/etc/cheef-server以下に証明書が格納されているので、これを以下のようにscpなどでコピーして~/.chef以下に配置しておく。
$ mkdir ~/.chef
$ scp <Chefサーバーのホスト名>:/etc/chef-server/admin.pem ~/.chef/
$ scp <Chefサーバーのホスト名>:/etc/chef-server/chef-validator.pem ~/.chef/
なお、デフォルトではサーバー側の/etc/chef-server以下のファイルはroot以外読み取りアクセスができないパーミッション設定になっているので、必要に応じてパーミッションを修正するなりしておこう。
証明書をコピーしたら、クライアント側で「knife configure -i」コマンドを実行して対話式の初期設定を行う。ここではChefサーバーのURLや設定ファイル、Cookbookを格納するディレクトリなどを指定しておく。
$ knife configure -i
WARNING: No knife configuration file found
Where should I put the config file? [/home/hylom/.chef/knife.rb]
Please enter the chef server URL: [https://centos02.office.osdn.jp:443] https://example.com:443 ←「https://<ChefサーバーのFQDN>:443」と指定する
Please enter a name for the new user: [hylom]
Please enter the existing admin name: [admin]
Please enter the location of the existing admin’s private key: [/etc/chef-server/admin.pem] ~/.chef/admin.pem
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key: [/etc/chef-server/chef-validator.pem] ~/.chef/chef-validator.pem
Please enter the path to a chef repository (or leave blank): ~/chef-repo ←Cookbookが格納されているディレクトリを入力
Creating initial API user…
Please enter a password for the new user: ←パスワードを入力
Created user[hylom]
Configuration file written to /home/hylom/.chef/knife.rb
以上で設定は完了だ。
WorkstationからChefサーバーへのCookbookのアップロード
Workstationで作成したCookbookをChefサーバーにアップロードするには、「knife cookbook upload」コマンドを利用する。ここで「-a」オプション付きでこのコマンドを実行すると、設定時に指定したCookbookディレクトリに格納されているCookbookすべてがサーバーにアップロードされる。
$ knife cookbook upload -a
Uploading apt [2.0.0]
Uploading aws [0.101.2]
Uploading build-essential [1.4.0]
Uploading database [1.4.0]
Uploading mysql [3.0.2]
Uploading openssl [1.0.2]
Uploading postgresql [3.0.2]
Uploading xfs [1.1.0]
Uploaded all cookbooks.
クライアント(ノード)の設定
最後に、ChefサーバーからCookbookをダウンロードして設定を実行するクライアント(ノード)の設定を行う。ノードで必要となるソフトウェアはスタンドアロン構成の場合と同様、chefパッケージに含まれている。
# yum install ruby ruby-devel rubygems make gcc
# gem install chef
また、Chefサーバーからscpなどで/etc/chef-server/chef-validator.pemをコピーし、「/etc/chef/validation.pem」として保存しておく。
# mkdir -p /etc/chef
$ scp <Chefサーバーのホスト名>:/etc/chef-server/chef-validator.pem /etc/chef/validation.pem
次に、設定ファイル「/etc/chef/client.rb」を作成する。内容は以下のようになる。
chef_server_url 'https://<ChefサーバーのFQDN>' node_name '<クライアントのノード名>'
また、クライアント側でもサーバーのFQDNの名前解決ができる必要がある。DNSや/etc/hostsファイルなどの設定をしておこう。
以上の設定が完了したら、chef-clientコマンドでChefサーバー上にあるCookbookが実行できるようになる。たとえば、「mysql::client」というRecipeを実行するには、以下のようにする。
# chef-client -o mysql::client
異なるOSが混在している環境でも効果を発揮
以上、Chefの概要や基本的な使い方を一通り説明してきたが、ここで紹介した機能はChefの機能のほんの一部である。今回紹介できなかった機能としては、サーバーの設定内容をJSON形式のファイルで管理する「Data Bag」という機能や、Webベースの管理コンソールを使ったGUIでのサーバー管理、サーバー側からのノードの操作などがある。現時点ではChefに関する日本語でのまとまった資料は少ないため、英語リファレンスを読み進めていく必要があるのがややハードルの高いところだろう。
Chefが便利なのは、Opscodeやサードパーティが公開しているCookbookを流用することで、設定ファイルの記述を少なくできる点だ。公開されているCookbookはOSやLinuxディストリビューションの種別が異なっても同じように利用できることが多いため、管理対象のOSを問わず同じ手順で管理が行える点もメリットだ。いっぽうで公開されているCookbookの中身はそれなりに複雑になっており、またほかのCookbookに依存しているものも多いため、動作内容の把握や問題発生時の解決に手間取ることもある点には注意したい。また、より踏み込んだ作業をしようとすると、ある程度Rubyの知識も必要になる。
なお、同様の設定管理ツールには前回記事で紹介したPuppetがある。設定ファイルの作成方法などは異なるものの、どちらも基本的な機能などは同じであるので、設定管理ツールを導入する際は両者を比較してどちらを使うかを検討してみると良いだろう。
この記事についてコメントする