Edited at

Chef-soloからItamaeに完全移行した話

More than 3 years have passed since last update.

※2016/04/24 追記

昨年末にItamae meetupで話した時のスライドリンクを追記しました。

Databag > itamae-secret の話やConsul連携の話が追加されています。

http://www.slideshare.net/tsuyoshitorii5/itamae-meetup-vol1public


現在自分が運用管理しているChef-soloプロビジョニングの仕組み 1

Itamaeに移行した時のお話をしようと思います。

管理規模としては大規模ではなく、小〜中規模的なところかと思います。

(ロールによってレシピ切り分けたり、環境毎にレシピ用意したりなど…)



最初に: Itamaeについて

https://github.com/itamae-kitchen/itamae

軽量なChef と考えればよいでしょう。

Chefの複雑さを取り除き、必要十分な部分のみ機能として提供しています。

こちらの資料 を見ると大体把握できると思います。

Chefのようにディレクトリ構造の規約に縛られることもありませんし、

リモートサーバにItamaeをインストールする必要もありません。

ローカルでItamaeを gem install して レシピファイルを1枚用意するだけで

すぐに動かすことができます。

このシンプルさは何事にも代えがたい!


Itamae Quick Start

# install

gem install itamae

# 適当なレシピ作る
echo "package 'sl'" > recipe.rb

# レシピ実行(ローカルホスト)
itamae local recipe.rb
# レシピ実行(リモートホスト)
itamae ssh -u hogeuser -h xxx.xxx.xxx.xxx recipe.rb
# attributeを定義したjsonを指定して実行
itamae local -j node.json recipe.rb
# レシピを複数つなげて実行
itamae local recipe01.rb recipe02.rb recipe03.rb

# dry-run
itamae local --dry-run recipe.rb
# ohai情報を参照する場合
itamae local --ohai recipe.rb



Itamae移行モチベーションについて

旧環境では vagrant-aws + berkshelf + chef-solo でプロビジョニングしていましたが

以下のような不満点がありました。


  1. 遅い

  2. chef-zeroに移行しないといけないらしい


1. 遅い

これはVagrant-awsを通してプロビジョニングしていることもありますが、とにかく遅い。 2

berkshelf実行してrsyncが転送してchef-solo自体の実行までにもタイムラグが結構ありましたし、

プロビジョニング自体もそれなりに時間がかかっていました。


2. chef-zero に移行しないといけないらしい

chef-soloは終焉を迎え、今後はchef-zeroを使う必要があるようです。

いやもちろん移行しようと思えば出来るんですけど

なんかもう面倒になってきてしまい…

俺はただ、書いたレシピをサーバ上で実行したいだけなんだ!!

...その他、コミュニティクックブックを使いまくっていたのを直したかったりと

細かいところを挙げるとまだまだ理由はあるのですが、

大きくはこの2つを解消したいと思いItamae移行を考えました。

(もちろんAnsibleも検討しましたが、レシピをyamlに全書きかえするのは移行コストに雲泥の差があるので除外…)



移行するにあたって注意したところ


  1. プロビジョニングフローは変えない

  2. ある程度ディレクトリルールを設ける


1. プロビジョニングフローは変えない

現在、プロビジョニングは以下のようなフローで行っています。1

これを変えずにItamae化することを考えました。

※以下rakeコマンドはvagrantコマンドをラップしている感じです 


  1. 独自のconfigファイルにvagrantのvm情報を書く

  2. nodes/<vm名>.json というファイルを作る

  3. rake aws:up vm=<vm名> でVM起動

  4. rake aws:provision vm=<vm名> でプロビジョニング実行(chef-solo)

  5. rake aws:spec vm=<vm名> でテスト

  6. rake aws:create_ami vm=<vm名> でAMI作成


2. ある程度ディレクトリ構造ルールを設ける

これはAnsibleなどでも同じ問題が発生すると思いますが、

ディレクトリ構造に制限が無いため

好き勝手にレシピ作ると構造がカオスになり

結局メンテナンスコストが増大する問題が発生すると考えられます。

そこで自分のプロダクトでは以下のようにディレクトリ構造のルールを決めることにしました。

※2015/5/25 メモ追記

itamaeベストプラクティスがWikiに記載されているのでそちらもご参照下さい、。


プロジェクト全体

割とchefを踏襲している感じ。

PROJECT_ROOT/

cookbooks/ # クックブック群
nodes/ # vm毎のnode.json
roles/ # ロール群
entrypoint.rb # Itamaeから実行されるレシピのエントリポイント(後程説明)
Gemfile # Itamaeプラグインなどの依存が書かれたGemfile


クックブック毎

実はここは割とゆるめの規約にしてあって、

レシピ数行で済むようなものはattributesやtemplatesも作らずに

1ファイルで済ませたりすることもあります。

ファイルが増えてきて見通しが悪くなってきたら以下のようにする感じですね。

<cookbook_name>

attributes.rb # attributesをまとめたファイル
xxx_recipe.rb # なんかレシピ
yyy_recipe.rb # なんかレシピ
templates/ # テンプレートファイル
xxx.conf.erb

この構成にした場合、

手動でincludeしておかないと属性情報が利用できないため

recipeファイルの先頭でattribute.rbをincludeする必要があります。

1行増えるだけだしまあこのくらいなら許容範囲かと。

include_recipe './attribute.rb'

...

また、attributeファイルを分けていると

他のレシピから属性だけ参照したい時にも利用することができますね。

(例えば、プロジェクトレシピからconsulのbinパスを取得したい場合など)



移行後の構成

サンプルプロジェクトをこちらに置いてみました。ご参考ください。

https://github.com/toritori0318/itamae-sample-project

ポイントを幾つか説明します。


VagrantからshellプロビジョナーでItamae実行

最初はvagrant-itamaeを検討し利用してみたのですが、

itamaeのオプションをすべて利用できなかったりと若干利用しづらい部分があったため

現在はレシピをsyncした後でItamaeをサーバにインストールし

サーバ上でItamaeコマンドをlocal実行するようにしています。

結果として汎用性が上がったのと、

(副作用ですが)サーバ上で直接Itamaeを実行しているため

プロビジョニングの時間が大幅に改善しました。


entrypoint.rb

chef-soloのnodes.jsonで「recipes」を指定して

レシピを実行することをItamaeでも実現したかったので

このようなファイルを用意しました。

以下のような数行の小さなスクリプトです。

node["recipes"] = node["recipes"] || []

# レシピを順番にinclude_recipeするだけ
node["recipes"].each do |recipe|
include_recipe recipe
end


attributeファイルについて

デフォルト値はレシピファイルのattributeに定義しておき、

かつnode.json側で指定した時はそちらを優先するような書き方をしています。

attirbuteファイル側でいちいちこの書き方をしないといけないので

もうすこし上手くやりたいかもしれない。。

※2015/2/23追記 コメントにてアドバイス頂きました!

# "td_agent" 項目を初期化

node["td_agent"] = node["td_agent"] || {}

# node['td_agent']['includes']が入力済みであればそちらを優先
node['td_agent']['includes'] = node['td_agent']['includes'] || []
...


プロジェクト全体で共通化しているレシピはプラグイン化する

全体で共通化しているレシピはプラグインとして作り、

プライベートリポジトリなどにおいておくと良いでしょう。

するとプロジェクト毎のレシピの見通しがよくなります。

Gemfileに以下のような記述をしておいて、bundlerで管理します。

# 独自のプライベートリポジトリに置かれた共通レシピなど

gem 'itamae-plugin-recipe-company-base', :git => 'git://hogehoge.com/fuga/itamae-plugin-recipe-company-base.git'

その他でも共通モジュール化しておきたいレシピは

プラグインとしてリポジトリに置いておくと良いと思います


基本的には include_recipe でなんでも出来る

include_recipeを使うと

attribute読み込みやroleのようにレシピをまとめる事もできます。

chefで行っていたことは大抵まかなえるでしょう。



移行コストについて

コミュニティクックブックを多用していたにも関わらず、

思ったより工数はかかりませんでした。

実はあまり難しいことはしていなかったということですね:)

ただし、便利に使っていたクックブックに関してはItamaeでも使いたかったので

一部はプラグインにしてgithubにあげています 3

https://github.com/toritori0318/itamae-plugin-recipe-supervisor

https://github.com/toritori0318/itamae-plugin-recipe-consul

コミュニティクックブックを利用せずにレシピを書いているプロジェクトであれば

かなり楽に移行できるのではないかな〜と思います。



移行後改善したところ

※以下、改善された点をあげていますが

cookbook自体のスリムアップも行っているためchefだけが要因というわけではありません。

参考程度にお願い致します。


導入の敷居が低くなった

gem install itamae でインストールできますし、レシピの実行も簡単〜♪


軽くなった/速くなった

明らかにプロビジョニングにかかる時間が改善されました。

またメモリ利用率も改善され t2.smallインスタンスが必要だったプロビジョニングが

t2.microインスタンス でも問題なく動くようになりました。


レシピを追いやすくなった

これはコミュニティクックブックを使わなくなったというところもありますが

レシピの構造がそれほど複雑ではなくなったので追いやすくなったように感じました。

あと、Itamaeではあまり複雑なリソースを使わずにレシピを書く必要があるため

相対的に読みやすくなったというのもあるかもしれません。

(package/execute/template/serviceでほとんど事足りる)


ツールのコードを追いやすくなった

Itamae自体のコード量はそれほど多くないため、何か問題があっても追いやすいです。



移行後不満なところ


Chefサーバーに相当する機能がない

ありません。


エコシステム周り

Chefと比べるとまだそれほどweb上には情報も多くはありませんし

Itamae用プラグイン(レシピ)もまだまだこれかなかなという感じです。

この辺りはユーザが増えてくると改善されてくるはずなので

みなさんどんどん利用すると良いですね:)


DataBag機能がない

今のところDatabagのような仕組みはありません。

が、単にリポジトリ内に秘密のものを置きたくない、

ということであれば環境変数を使う方法があるようです。

http://qiita.com/nownabe/items/8576c17f864aeefa03d0

とはいえ機能として欲しいところではありますね。



まとめ

Itamae、 導入もラクですし小回りが効くということで扱いやすい印象でした。

小/中規模であればプロビジョニングツールの候補としてオススメです。

ユーザが増えてより改善されると良いですね!!



おまけ:ChefとItamaeの差分メモ


リソース全般: modeの書き方

mode は stringである必要がある。

# Chef

template 'a' do
mode 0644 # 数値でも文字列でもOK
end

# Itamae
template 'a' do
mode '644' # 文字列限定
end


リソース全般: only_if/not_ifの書き方

ブロックではなく、文字列を指定する必要がある。

# Chef

template "a" do
not_if { File.exists?("/tmp/a.conf") } # ブロックでも文字列でもOK
end

# Itamae
template "a" do
not_if "test -e /tmp/a.conf" # 文字列のみOK
end


リソース全般: notifiesのタイミング指定

:delayed ではなく :delay になっている。

(デフォルト指定がdelayなので、typoしてても実質無害ではあるが…)

# Chef

template "a" do
notifies :restart, "service[httpd]", :delayed
end

# Itamae
template "a" do
notifies :restart, "service[httpd]", :delay
end


directory: recursive属性が無い

# recursive付けなくてもOK

directory "/tmp/hoge/fuga" do
action :create
end


同じリソースでも出来る事が異なる

というか異なる部分はかなり多いので

きちんとドキュメントを読んだほうが良いでしょう。



Ref






  1. この辺りのブログにも書いてます ( http://d.hatena.ne.jp/toritori0318/20130916/1379355060 ) ( http://d.hatena.ne.jp/toritori0318/20140829/1409296637



  2. vagrant-cachierも利用済み。 



  3. API変える予定ありますしアルファ版ということでご容赦ください:(