最近の人気なインフラ自動化ツールChef soloを利用して、開発環境の構築を自動化してみます。
参考サイト
最近Chef soloに関する記事はだいぶ増えています。本文は以下の記事を参考しました。
そのほか、伊藤直也さんのブログでchef-soloを紹介され、入門Chef Solo – Infrastructure as Codeが達人出版からも発売しています。
上の記事を読んでから、Chefの公式ドキュメントを読みやすくなると思います。結構の量がありますので、最初からドキュメントを読むとめちゃくちゃわかりにくいんです。
Chefとは?
ChefはOpscode社によりRubyで開発されたインフラ自動化ツールです。ソースはGithubに公開サれています。利用者はRubyのDSLでサーバ環境構築の手順を定義し、Rubyスクリプトを実行してサーバ環境を構築できます。
Chefは「料理人」という言葉が由来になります。ChefはKnifeを使って、Recipeに従って、料理(サーバー構築)を作り上げます。構築対象サーバーは「Node」と呼ばれます。そのRecipeの管理単位を「Cookbook」と呼びます。CookbookにはRecipeを加え、設定ファイルのテンプレート「Template」や、環境に応じてその値を変更できる変数を定義した「Attribute」などが含まれています。後ほどそれらの要素を詳細に解説します。
ClientとServer
大規模のサーバ群の設定を一括管理する場合、C/S構造のChefを利用します。Chef Serverは構築対象の情報とCookbookを集中管理し、Chef clientはChef serverからCookbookをダウンロードして実行することで自分の環境を構築します。事前にChef clientを構築対象サーバー(Node)でインストールします。
上記の図を示すようにインフラ作業者は自分のマシンでNode情報、Cookbookなどを作成し、Gitで管理します。作成したCookbookをChef serverに配布して、各NodeはChef serverから最新のCookbookなどを取得して、ローカルでChef clientを実行し、環境を構築します。
Chef serverはCouchDB、RabbitMQ、Solrなどのミドルウェアを使用しますが、構築手間がかかります。Opscode社はChefにいくつかの機能を追加した有償版の「Private Chef」やクラウド型の「Hosted Chef」といったサービスを提供しています。
Chef soloとKnife solo
Chef soloはChef serverが不要、構築対象サーバー(Node)でCookbookの作成管理、実行などをすべて完結させるスタンドアロンChef clientです。多くの場合、構築対象サーバーはデータセンターに置かれますので(あるいはクラウドVMなど)、Cookbook作成管理はローカルマシンで行って、SSH経由でNodeに配布し、NodeにChef clientコマンドでCookbookなどを実行します。Knife soloはKnife機能を拡張し、Cookbookのリポジトリ作成、SSH経由のNodeに配布、リモートでNodeにChef client実行等を追加します。
今回の環境
今回knife soloとchef soloで開発環境を構築してみましょう。
ローカル環境:
- Mac osx 10.9
- Ruby: 1.9.3p448
- Chef: 11.6.0
構築対象サーバー(ホスト名: tcserver1):
- Debian GNU/Linux 7.1 (wheezy) 32bit
- Ruby: 1.9.3p194
また、SSH鍵認証およびdebain作業アカウントのsudo設定(NOPASSWD)を事前に実施しました。
インストール
まず、ローカルマシンでchef soloとknife soloをいれましょう。
1 2 3 4 5 |
|
作業手順
Knife soloは以下のコマンドがあります。init、prepareとcookをよく使っています。
1 2 3 4 5 6 7 8 9 10 |
|
リポジトリの作成
「knife solo init リポジトリ名」でリポジトリの雛形を生成します。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
構築対象サーバー設定
「knife solo prepare wang@tcserver1」でtcserver1を構築対象サーバーとしてChef clientをインストールし、構築設定ファイルnodes/tcserver1.jsonを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
サーバー構築
「knife solo cook wang@tcserver1」でtcserver1を構築してみましょう。(tcserver1.jsonは空なので、実際に何もしません)
1 2 3 4 5 6 7 8 9 10 |
|
Opscode communityに公開されたCookbookを取得
Cookbookを一から作成する必要ではありません。Opscode communityに数多くのCookbookを公開しています。「git clone」でGithubから取得しますが、Berkshelfというツールを利用すれば、Rubyのbundler風に扱うことができます。
Opscode CommunityからCookbookをダウンロードするため、ユーザ登録し、秘密鍵をダウンロードしておく必要があります。 秘密鍵をDownloadしたら、~/.chef/username.pemにパーミッション600で保存しておきましょう。更にリポジトリの.chef/knife.rbに以下の記述を追記します。
client_key “/Users/wang/.chef/username.pem”
- まずリポジトリにBerksfileを作成します。
1 2 3 4 5 |
|
- Berkshelfでcookbookをダウンロードします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Cookbook新規作成
「knife cookbook create demo -o site-cookbooks」でdemoというCookbookの雛形をsite-cookbooksフォルダに新規作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
demoにいくつかの子フォルダーを生成しました。各フォルダーの内容を以下に紹介しましょう。
アーキテクチャと構成要素
上記のdemo cookbookのフォルダー構造によって、Chef soloの各要素を解説します。
リポジトリ
リポジトリは「knife solo init」コマンドにより生成したChef client実行用のファイルの置く場です。料理人に対して、料理を作る場所(キチン)の意味です。 リポジトリに構築対象サーバーの情報(Nodes)と構築手順(Cookbooks)を含めます。
Cookbooks
サーバー構築の作業手順(Recipe、Attribute、Template)をまとめるものです。サーバー環境を構築する時、様々なミドルウェア、システム設定及びアプリケーション・インストールの作業を行います。一般にあるソフトのインストールと設定を1つのRecipeに集約します。
ソフトの設定ファイルがNodeの情報により動的に生成される場合は多いですので、Rubyのテンプレート・ツールeRubyを利用して、設定ファイルの雛形を定義します。Chef clientを実行する時にNode環境と合わせる設定ファイルを生成します。
JavaのビルドツールAntと比較すると、build.xml(<project />タグ)と同等なものです。
上記のdemoのフォルダーにいくつかの子フォルダーはありますが、その中にattributes、recipes、templatesをよく使っています。
Recipe
Recipeはサーバー構築手順を定義するものです。Cookbookに複数のRecipeを定義できますが、保守性の観点からRecipeにNode構築作業を適当に分割して、それぞれのRecipeに手順をまとめます。
例えば、LinuxでMysqlサーバーを構築する場合、システム設定(ベースシステムソフトGccなどのインストールと設定、ユーザアカウント管理)とMysqlのインストール、設定、サービス起動を別々のRecipeに記述したほうが良いかと思います。
Antと対照すると、Recipeは<task />と同等なものです。<task />に<mkdir />、<copy />、<javac />などの内部タスクを組み合わせて、ビルド作業を記述しますが、Recipeでは様々なResourceを組み合わせて、構築作業を記述します。
resource
構築作業の1つのステップです。ファイルコピー、パッケージ・インストール等の作業を定義します。ChefにあらゆるResourceを用意しますが、自分でRubyの関数を作成し、カスタマイズなResourceとして利用できます。
構築作業は冪等性(べきとうせい)を求めます。同じ作業を何度実行しても同じ結果になるべき特性です。それで、自分が作成したResourceまたはbashスクリプト再利用の場合、作業前のサーバー状態と作業後の状態をきちんと管理する必要です。
attribute
RecipeはRubyのコードですので、自由にRuby変数を定義できます。複数のRecipeの間に変数を共有する場合、Attributeを利用します。
例えば:
attributesにdefault連想配列を定義します。
1
|
|
recipeにnode連想配列からdefaultの値を取得します。
1 2 3 |
|
Chefを実行する時に値を代入して、構築作業を行います。
1 2 3 |
|
template
eRubyで記述したソフトの設定ファイルの雛形です。Chef clientを実行する時、<%= >で囲む変数の値を代入し、構築対象サーバーの環境と合わせる設定ファイルを生成します。
例えば:
1 2 3 4 5 |
|
recipeのtemplate resourceの定義に変数hadoop_tmpの値を渡します。
1 2 3 4 5 6 7 8 9 10 11 |
|
Chefを実行して、生成した設定ファイルの内容は以下のようです。
1 2 3 4 5 |
|
nodes
構築対象サーバーの情報を置く場所です。サーバーごとにjsonファイルで構築内容を記述します。
他にRoles、data_bags、Enviroments等のフォルダーも存在しますが、公式ドキュメントを参考すれば良いです。ここで割愛します。 Rolesはサーバー役割(DBサーバかWebサーバーか)を分けて定義します。Enviromentは環境種類(開発環境か本番環境かテスト環境か)によって構築内容を別々記述します。 data_bagsは暗号化したいDB接続パスワードなど情報を定義する場所です。
サンプル
これから環境構築の一般な作業をChef soloで試してみましょう。
Hello Chef
メッセージを出力します。
1 2 3 4 |
|
パッケージのインストール
ソフトをインストールします。Chef内部でDebian系(apt-get)とRedhat系(yum)の差異を吸収します。
1 2 3 4 5 |
|
JDKのインストール
JDKのインストールファイルをコマンドライン(wgetまたはcurl)でダウンロードできませんので、事前にブラウザでダウンロードして、site-cookbooks/demp/files/defaultに置いて、cookbook_file resourceを使用して、どこかにコピーして、JDKをインストールします。
例:
1 2 3 4 5 |
|
1 2 3 4 5 6 7 8 |
|
シェールスクリプトの例
Resourceに存在しない処理を行うため、bashスクリプトで構築作業を実現するのは普通の考えです。 上記のJDKをbashスクリプトでインストールしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
ここで冪等性を考慮する必要です。スクリプトを何回実行しても同じ結果を得るのは重要です。
Chefでは様々なResourceを用意しました。それぞれを組み合わせて、ほとんどのサーバー構築の作業を対応できます。以下ではよく使う便利なResourceです。
Resource | 機能 |
---|---|
users | OSのユーザ管理 |
group | OSのグループ管理 |
cookbook_file | ファイル配布 |
directory | ディレクトリ管理 |
template | テンプレートファイルを扱う |
package | パッケージ管理 |
service | OSサービスの起動・停止・有効化・無効化 |
bash | bashスクリプトの実行 |
cron | cronジョブの管理 |
Recipeの呼び出し
site-cookbooks/demo/recipes/default.rbはcookbook名(demo)を直接に呼びます。
1
|
|
default以外のrecipe(site-cookbooks/demo/recipes/hadoop.rb)を::で引用します。
1
|
|
まとめ
以上、Chefの概要や基本的な使い方を一通り説明しましたが、ここで紹介した機能はChefの機能のほんの一部です。また経験不足なので、今までのChef soloを使った感想をまとめます。
Chefを使って、文字記述の手順を省け、Rubyコードで環境構築を手順化します。大量サーバーの構築は楽になります。
Chefが便利なのは、Opscode communityやサードパーティが公開しているCookbookを流用することで、設定ファイルの記述を少なくできる点です。
ResourceやCookbookはOSやLinuxディストリビューションの種別が異なっても同じように利用できることから、管理対象のOSを問わず同じ手順で管理が行えます。
公開されているCookbookやChefのソースは複雑になっており、Cookbookの依存関係を管理するツールもありませんので、動作内容の把握や問題発生時の解決に手間取ることもあります。
個人的にすべてのファイルをRubyで記述し、jsonファイルを使わない方が良いかなと思います。なお、フォルダ構造は複雑すぎで、もっと簡単な構成を改善できるはずです。
attributesの変数をroles, recipe等に上書きできるのは大変わかりにくい仕組みです。
Recipeの記述自由度は高すぎて何が正しいか、あるいは何がベスト・プラクティスであるかよくわかっていません。
以上個人の見解ですが、間違い等あれば指摘していただきたいです。もっと深く勉強すれば、ぜひnaoyaさんの本を読んで頂ければと思います。