[http://wiki.opscode.com/display/chef/Chef+Basics:title=Chef Basics]を訳しました

Chefを使うならどのような機能をもっているか把握するべきです。このページでは機能の概要を説明し、それらの詳細のリンクがついています。

Modeling Your Infrastructure

Nodes

nodeはChef-clientを実行するhostです。Chefからみたnodeの主な役割は変数と実行リストを所持する事です。
NodeはRecipeとRoleで構成されたものです。あなたがNodeを好きなときに実行するときは以下の事をします。

  • systemにRecipeを追加する
  • 変数を更新する
Run List

最も簡単な場合、Run listはnodeが所持しているRecipeのリストです。Cookbookのmetadataが正しいと仮定するとrun listにRecipeを登録するだけでそれらは必要に応じて自動的に実行されるでしょう。

より進んだ使い方として、Runlistにはnodeが特定のnodeのレシピをRoleとして持つ事ができます。この場合Chef-clientを走らすと、roleに指定されたRecipeが"拡張された"listとして実行されます。

Node Attributes

NodeとRoleはattributesによって関連づけされています。attributesはnestされたkey-value形式の構造を持っています。NodeとRoleのAttributesはresource attributesの入力として共通に利用できます。例えば本番環境ではnginxのあるバージョンしか使いたくないが開発環境で最新版を入れたいときがあったとしましょう。nodeもしくはroleの変数を利用する事で一つのRecipeで両方の環境を実現する事ができます。

Chefではattributeファイルにセットされたattributeのみ有効です。Chefが実行されたときにnodeがattributeファイルを参照するコード及び変数はnode上に直接管理されます。Ruby上ではattributeファイルの中にselfで指定されたものがnodeです。attributeファイルを利用する事でnode上のデータが正しいと信頼することができます。

Chefのヘビーユーザはたくさんのnode上でattributeを管理しています。

Roles

Roleは似たようなnodeの似たような機能をグルーピングするものです。Webのscaleを行うときは何か一つに着目せずにnodeグループの設定を共通化しその設定部分を表現するためにRoleを使います。Roleはnode同様attributesとrun listを持っています。Chef-clientが実行されたとき、node自身のattributeとRoleのattributeがmergeされることになります。

Configuring Nodes

Cookbooks

cookbookはChefが設定したrecipe,resource definition, attribute, library, cookbook fileとtemplate fileとmetadataの集まりです。Cookbooksは一つのpackageやserviceの設定周りがまとまったものです。例えばclientとserver両方のRecipeを含んだMySQLのcookbookの場合それにattributesファイルが追加されることになります。

CookbooksはChef内で共有、配布される単位になります。Chefを利用する人のほとんどぽがCookbookを書く事になるでしょう。

Recipes

Recipesはあなたのresourcesが書かれているファイル群です。RecipesにはちょっとしたChefの文法を覚える必要があります。
Chefを実行する際は二つのプロセスがあります。一つ目は結合と呼ばれるプロセスです。二つ目はChef内の各Resourceでのactionを実行することです。単なるrubyコードは実行プロセスではなく結合プロセスで実行されます。Chefの実行プロセスで実行したい場合はRuby block resourceを利用するようにしてください。これより詳細は、anatomy of a chef runを参照してください。

Metadata

Cookbooksではよく必要な機能を他のcookbooksを信頼します。clientが利用しているcookbooksがどのサーバで稼働しているか知るためにcookbooksではある情報を見ています。それがcookbook metadataです。metadataにはauthorship, licening, cookbookの概要、cookbookがどのプラットフォームで動く事を期待しているかなどの情報が入っています。Chefは実際に動くときよりmetadataによっていろいろな値をもっていますが正確な依存情報を持つ事が本質であり情報が全て入ったから問いって必要な全てのcookbookが手に入るわけではないです。

Resources

resourceはhost上の設定差異を吸収します。たとえばpackages resourceなどプラットフォームによってコマンドが変わるところを吸収できます。
ResouceはRecipeやDefinitionsで利用できます。それらはChefで動く基本の単位です。

Actions

ActionはChef resourceで何をしたいか記述します。例えばあるパッケージをインストールするのかアップグレードするのかはたまた削除するのかといったことをResourceに記述します。

Providers

providerはプラットフォームに特化したresourceの概念です。RedhatCentOSではpackage resourceはyumpackageを使ってインストールするでしょうしDebianUbuntuではaptを利用するでしょう。Providerはその辺りを知的に行います。systemに関連するアクションがあった場合はそれに帯する責任を背負います。そして各パッケージは最初にコマンドに何が必要なのかチェックします。Chefを実行するさいProvierについて心配する事はありません。あなたが何かしてもChefはshortcut resourceを提供してくれます。例えばdpkg_packageやrpm_packageはファイルシステムから直接インストールすることを許します。

ProvidersはResource上のactionをとってきます。与えられたNodeは基本のProviderを指定しますがResourceで直接Providerを指定することもできます。

Search

SearchはChef serverによって構成され、データの検索にを行います。ほとんどの場合はrecipe内でsearch callsを経由して利用します。

Data bags

DatabagsはChef-server上にもつkey-value形式の構造化されたものです。DataBagは検索でき、かつrecipe内で名前を呼んで直接指定する事ができます。Chef全体で所持できる変数と考えるのがいいでしょう。

Managing Chef

Knife

KnifeはChef-serverのCUIです。Chef-soloを利用する場合でもいくつかの機能を利用できます。

Shef

ShefはChefのconsoleです。Recipeのデバッグとかに使えます。

Anatomy of a Chef Runの訳

Anatomy of a Chef Runを訳しています。

Anatomy of a Chef Run

Chefを動かすならChef-clientの実行の仕組みは覚えておいた方がいいですよ。

Convergence

Chef-clientやChef-soloでプロセスを呼んだときは"Convergence"リソースを呼ぶ必要があります。
Convergenceはシステム内で自動的に"各動作を実行するときはシステムを正しい形でくださいね"ということを意味します。理想としてはChef-clientを一つのサーバで走らせるとき中途半端な状態ではなく完全な状態のシステムを利用できる事です。
うまく完了しなかった場合は続けてシステムに要求を送り続けます。

Chef-clientの実行

  • Chef-Clientを実行
  • Node作業
    • 構築
    • 登録
    • 認証
  • Cookbookの同期
    • ライブラリを同期
    • 変数を同期
    • 定義を同期
    • レシピを同期
  • リソースをコンパイル
    • ライブラリ読み込み
    • 変数読み込み
    • 定義読み込み
    • レシピ読み込み
  • Nodeを設定
    • 保存
  • Chef-client終了

Build, Register, and Authenticate the Node

Chef-clientもしくはChef-soloを実行する際、最初にNodeをたてます。Nodeは以下で構成されています。

  • Ohai:OSから情報を持ってきます
  • Chef-serverから前回のNode情報を持ってきます(Chef-solo使わないときのみ)
  • JSONの変数とレシピを追加します
  • Ohaiで取得してきた情報を追加します

一度Nodeが構築されるとChef-Clientは毎回/etc/chef/client.pemという非公開キーを参照するようになります。
それがない場合自身でそれを作ろうとします。それ自身を登録するときはChef-validaterを一意のものだと仮定します。Chef-validatorは特殊なクライアントでそれを利用する事で新しいユーザを作成することができます。Chef-validatorはデフォルトで/etc/chef/validation.pemに非公開キーを持ちます。一回作ってしまえば次回からは/etc/chef/client.pemを参照するようになります。

Synchronize Cookbooks

Chef-ClientはChef-Serverにライブラリ、変数、定義、レシピの一覧を取得しローカルのファイルキャッシュに溜め込みます。

Compile Resource Collection

COOKBOOKから情報を得た後、nodeに必要なリソースを収集します。

  • ライブラリをロードする
    • 言語拡張はRubyのクラスを使用可能にします
  • 変数をロードする
    • レシピやNodeの変数から変数をロードします
  • 定義をロードする
    • 定義はレシピの前に読み込まれている必要があり、それからリソースが生成されます
  • レシピをロードする
    • この時にレシピは評価されます。この時点ではリソースは実行されず、一度Resource Collectionという場所に保持されます。Resource Collectionはいくつかのヘルパーがついたリソースが評価されたものをつめた配列です。しかしリソースの外で定義されたただのRubyも評価されます。もしあなたが他のリソースを利用したいならRuby Block Resourceを利用するとよいでしょう。コンパイル時にRuby Resourceを実行することも可能ですよ。

Configure Node

Chefはこの時点でシステムとして設定できる準備ができています。

  • Converge
    • 各リソースはProviderにマッピングされます。ProviderとはChef上で動作可能なオブジェクトです。
  • Save node
    • Convergeした後Nodeを保存し、検索対象内にセットします。
  • Run Notifications
    • 最後には、設定した通知が動きます

Chef-Clientが失敗した場合exception handlerに登録した動作が実行されます。

Architectureの訳

Architectureを訳してみます。

Server Architecture

Chef-serverは以下の機能から成り立っています。

  • Chef server
    • WebUI, node, clientからHTTP API リクエストを受け付ける
  • Chef server web ui
    • WebベースのChef-server管理ツール。
  • CouchDB
    • Chef serverのデータをためるDB
  • RabbitMQ
    • Chef ServerからChef Solr Indexerへデータを転送する。これによりindexが更新される。
  • Chef solr indexer
    • Chef solrにデータを書き込む事で検索できるようにする
  • Chef solr
    • Apache solrのラッパー。

Clients

ChefはいくつかのClientを提供しています。

  • Chef Client
    • メインクライアント。Chef-serverから情報を受けて実行する。
  • Chef Solo
    • 自身のサーバ上で完結するChef client
  • knife
  • Shef

Chef-clientの訳

Chef-clientを訳してみます。

Chef Client

Chef-clientはChefができることを大体どこでも実行できます。Chef-clientは署名付きリクエストをREST形式でChef-serverに送り、COOKBOOKをコンパイルして実行します。

Clients do work for one or many Nodes

Chef-clientはNodeを利用して動きます。一つのChef-Clientで複数Nodeのレシピを実行できます。

Clients do all the work

Clientが全てのタスクを実行します。Chef-serverやChef-IndexerはChefに情報を供給するだけです。

You can run the client periodically

もしChef-clientをdaemonとして動かしたいなら以下のようにするとよいですよ。

$ chef-client -i 3600 -s 600

iオプションはNodeに聞きにいく間隔を、-sはプロセス一杯のときのランダムな間隔をあけるための設定です。
他に以下のようなオプションがあります。

指定表記 オプション内容
-S, --server CHEFSERVERURL Chef-serverのURLを指定
-k, --client_key KEY_FILE Client keyファイルの場所を指定
-c, --config CONFIG 設定ファイルを指定
-d, --daemonize daemonで動かしたいときに指定
-g, --group GROUP グループを指定
-i, --interval SECONDS 継続的にChef-clientを実行するときの間隔を指定
-j JSON_ATTRIBS jsonファイルを指定
-l, --log_level LEVEL ログレベルを指定(debug, info, warn, error, fatal)
-L, --logfile LOGLOCATION ログファイルを指定(デフォルトは標準出力)
-N, --node-name NODE_NAME Nodeを指定
-P, --pid PIDFILE pitファイルを指定(デフォルト:/tmp/chef-client.pid)
-s, --splay SECONDS 間隔を指定
-u, --user USER ユーザを指定
-K, --validation_key KEY_FILE validationファイルを指定
-V, --verbose ログを標準出力にも表示する
-v, --version バージョンを表示する
-h, --help ヘルプを表示する

APIの認証について

pemっていうファイルで認証しているのはなんとなくわかる。
このなんとなくを解消したいと思う。
本エントリはWikiの誤訳だと思ってほしいです。

API Clients

nodeデータはChef serverからの認証リクエストによって別々に管理されており、それはすなわちAPI Clientごとに管理されているということです。どのAPI Clientも公開/非公開キーを所持しています。
公開キーはChef server側で所持され、非公開キーはAPI Clientのほうで所持しています。nodeを実行したとき、非公開キーが自動的に/etc/chef/client.pem上に生成されます。knifeコマンドを利用するのが管理者の場合~/.chef/USERNAME.pemに非公開キーは生成されます。
全てのChef serverへのリクエストはHTTP headerに認証情報が入っています。署名はClient側のリクエストにClientの非公開キーを用いて暗号化したものを利用します。

The Validation Client

Chef Clientの初回アクセスはAPI Clientのキーをまだ生成できておらずChef serverへ認証リクエストを作る事ができません。
そこでデフォルトで"validation-client"という特殊なClientを使います。Chef clientが実行されて、最初にキーがなかったときChef serverに自分自身を登録するためvalidation-clientを一時的に借りるようにします。それをするために、validation clientの非公開キーをChef clientホストの/etc/chef/validation.pemにおくようにしてください。
一度Chef server側に登録できればこの特殊なClientは必要なくなります。一度validation clientを利用してChef serverに登録したらそのホストにおいてあるキーを削除する事をおすすめします。

Signed Header Authentication

APIの認証は基本的にリクエストごとに実施します。そしてそのリクエスト自体はClientがキーを利用して作成しています。つまるところ、結局HTTP headerに毎回ユニークな認証キーを作成しているだけです。リクエストは以下の項目を所持しています。

  • The HTTP Method (GET/PUT/POST/DELETE)
  • The Request Body in Base64
  • A Timestamp
  • Your Client ID

リクエストはClient側の非公開キーによって暗号化され、HTTP headerにセットされ、Chef server側でそれを解釈します。さらに受け取ったリクエストが本当にChef client側から送られてきたものなのかどうかをbodyがかわっていないかHTTP methodに変わりはないか必要な回数以内のリクエストなのかということから判断します。
全てのリクエストはHTTPS経由で行う事をお勧めします。
Chef Clientにはclient keyが発行されることになります。

Under the hood

新しいAPI Clientが作成されたとき、Chefは新しい公開/非公開キーを作成します。公開キーはChef serverで保持され、非公開キーはAPI Client側で保持されます。リクエストがきたときChef server側では以下のように検証を行います。(公開キーを利用します)
この検証は以下のメリットをもっています。

  • 全てのリクエストで認証が必要
  • Sessionを持たなくてよい
  • リクエストを改ざんされても問題ありません
  • end-to-endの認証なのでいかなるトランスポート層を通る事ができます

Chef Clientの認証の仕組みは以下の通りです。

  • 最初にChef clientがclient keyを持っているか確認します
    • もし持っていたら認証リクエストの発行を開始します
  • もし持っていなかった場合validation keyをもっているか確認します
    • もし持っていたらAPIを利用するためのリクエストを作成します
    • もし持っていなかったら、失敗です。。。
  • もしClient keyを作成できた場合、それを使って再度リクエストを作成します

The Web UI key

Chef web UIはChef APIのようなものです。違いはインストール時にキーが発行されることです。(同時にvalidation keyも発行されます)

Creating new API Client Keys with Knife

もしChef-server上にデフォルトのユーザでリクエストを送りたくなければ絶対に自分自身のキーを作った方がいいですよ。
API clientを生成する際は、まず以下のknifeコマンドを発行しましょう。

$ knife client create monkey
INFO: Created (or updated) client[monkey]

これから利用する非公開キーが発行されます。さらに以下のコマンドを発行しましょう。

knife client create monkey -f /tmp/monkey.pem

この例でいえば/tmp/monkey.pemに非公開キーができるはずです。

まとめ

  • Chef-serverは公開キー持ってればいい
  • Chef-Clientは非公開キーが必要
  • 上記のAPI Clientの作り方だと失敗したよ(僕の環境)
    • でもChef-webuiから発行できるよ
    • 発行したものをChef-clientサーバのpemファイルに保存すれば問題なく動きます
追記

API Clientの作り方失敗しませんでした

  • Client上に/etc/chefディレクトリ作成
  • /etc/chef/client.rbに最低限以下のものを設定したファイルをおく
    • client_key
    • chef_server_url
  • /etc/chef/validation.pemに非公開キーをおく
  • chef-clientを実行
    • chef-validatorが新しいclient_keyを作成してくれる
  • ~/.chef/knife.rbにclient.rbにnode_nameあたりを追加したものをコピー
    • knife node listで出力確認

なんかApacheインストールするためだけのレシピ

%w(#{node[:apache][:work_dir]} #{node[:apache][:install_dir]}).each do |dir|
  directory dir do
    owner "root"
    group "root"
    mode 0644
    action :create
    recirsive true
  end
end

cookbook_file File.join(node[:apache][:work_dir], "httpd.tar.gz") do
  source "httpd-2.2.17.tar.gz"
  action :create
  owner "root"
  group "root"
  mode 0644  
end

script "install apache" do
  interpreter 'bash'
  user 'root'
  cwd node[:apache][:work_dir]
  code <<-EOC
    tar -zxvf httpd.tar.gz
    cd httpd-2.2.17
    ./configure #{node[:apahe][:install_options]}
    make
    make install
  EOC
end