複数プロジェクトをChefで運用管理するための独自ルール

私の会社でchefを本格的に導入しよう！と決めてから、色々と悩んで悩んで右往左往してましたが、ようやく形になってきました。
いやーここまで来るのに本当に寄り道しまくりました…。
現状、社内でも共有しきれていませんが２，３プロジェクトをこの方法で管理運用しています。
そこで、社内でも共有する資料作りと平行してこちらにも情報を公開してみたいと思います！

## 前提
* 一つの会社の中に複数のプロジェクト(以降PJ)がある
* chefのrecipeは一人以上の複数名で書ける
* 全社的にchef使おうぜー
* Private Git repositoryを既に運用している
* [The Environment Cookbook Pattern](http://blog.vialstudios.com/the-environment-cookbook-pattern/)をさらっと読んで、総論賛成各論反対！そのまんま適用は無理！と思った

基本となる考え方とかをしっかり理解したい方は上や下のリンクを読んでください。
細かい説明はすっ飛ばして、それでも分かるように極力気をつけますので。

### ちゃんと元ネタを理解したい人用リンク
以下に日本語で解説してくれてるサイトがあります！
[大規模にchefを使い倒すためのcookbook pattern](http://qiita.com/cazador/items/e0db714555f2f36d98c6)
[Chef Cookbook の管理方針、The Environment Cookbook Pattern について](http://easyramble.com/the-environment-cookbook-pattern.html)



## ざっくりとした全体像
* knife solo + berkshelf
* chefのroleは使わない
* site-cookbookも使わない
* depends(metadata.rb)からのinclude_recipe!
* berks-api使ってます(が、chef-serverの方がいいのかもしれないが脳内停止中)


## cookbookの種類
Cookbookは以下の命名規則に沿ってリポジトリに登録するようにしました。

|名前|利用範囲|命名規則|概要|
|---|---|---|---|
|Library cookbook|全体|lib-|LWRPを作る(中上級者用)
|App cookbook|全体|app-|アプリケーションをインストールする|
|Company cookbook|全体|<会社名>|全社共通の設定とか|
|Project base cookbook|Pj毎| \<PJ\>-base |Project共通の設定とか|
|Project wrapper cookbook|Pj毎|\<PJ\>-wrap|Project用のラッパー
|Project env cookbook|PJ毎|\<PJ\>-env|PJ用のRoleみたいなもの
|Community cookbook|全世界|-|https://supermarket.chef.io/|

上記のうち、LibraryについてはLWRPを使う前提なので、それ以外についてもう少し詳細に説明します。

### App cookbook
Appは複数PJで使う前提なので、単体で動くことを最優先にします。
また、Appは1cookbookで1アプリケーションです。(例：app-httpd, app-nginx, app-mysql56)
つまり、include_recipeでそれを読みこめば、とりあえず動く。
この「とりあえず」というのがちょっとミソで、httpdなら本当にrpmインストールして終わりレベルだったりしますが、その他個別にある程度設定を入れてたりします。
あとはちょっとした設定とかはここに作っちゃったりしてます。(EC2用のapp-amznlinux-swaponとか)
個人的には、このapp-cookbookが充実して後述するwrapperであまり色々やらなくても、attributesやdata_bagsをよしなにやるだけで環境構築できるようになるのが一番いいと思ってます。

### Company cookbook
会社共通のパッケージとか設定とかとりあえずぶっこんでます。
dstatとかvimとかvimとか。

### Project base cookbook
CompanyてほどじゃないけどPJでは共通で使うよ、というのはこちらに逃してます。
例えばrpmでlibxxxをインストール！とかそういうのは一々App cookbookを作るのが面倒なのでこっちで一括インストールしてます。

### Project wrapper cookbook
これが各PJで一番触るcookbookです。
App-cookbookやcommunity-cookbookをincludeして、設定とかサービスの上げ下げとかをここに一気に書きます。
どっかではベストプラクティスでwrapperも分けろ的な話が出てましたが、そしたらもう腐るほど増えそうだったのでPJ毎にまとめました。
各App毎にrecipeを分けて作ります。
(例：pj-wrap::httpd, pj-wrap::nginx, pj-wrap::mysql)

### Project env cookbook
ChefのRole的な役割をします。nodesファイルに書くのはこのenv cookbookだけにしています。
ここでwrapper,app,community,base,companyなどなど上で上げたcookbookをただただinclude_recipeするrecipeを書きます。
(例：pj-env::common, pj-env::web, pj-env::batch)

#### よくある議論：community cookbookは使うべき？
私は基本的には使うのは賛成ですかね。何やってるか(読まないと)よくわからないし、無駄なことも多いけど、それ以上のメリットが有ります。
ただ、簡単なものは極力自分で書いたほうが勉強にもなるから、本家を見ながらわかりやすくパッケージングしたりすることもあります。
自社開発だとdistributionも限られてるだろうからそんなに大変じゃないです。
後はcommunity cookbookの実装方法が気に食わないとか。例えば[これ](https://supermarket.chef.io/cookbooks/users)。

## berks-api
berks-apiがメジャーかどうかはよく分かりませんが、metadata.rbと同様のtagをつける以上のメリットがあると思ったので導入してみました。
berks-apiについては[ここ](http://qiita.com/cazador/items/8d05016c31a48e9c6b0f)とか[ここ](http://d.hatena.ne.jp/hirose31/20140714/1405307755)に情報があります。
なお、Atlassian stash用のプラグインがなかったので、それは自作しました。そのうち公開…。
これを使うとmetadataのversion(と、git tag)で各cookbookのバージョン管理ができるので、最初の手間と理解の壁を超えると凄くわかりやすくなると思います。

## このやり方でのメリット、デメリット
※以下のメリット・デメリットがありますが、デメリットについてはある程度自動化したりして吸収出来ちゃうので、今のところこれで行くつもりです。
### メリット
cookbookの再活用がとても捗るし、cookbookを改良した時に他のPJに適用するのもすごく楽。

### デメリット
* 立ち上げ時には全体を理解し切るまで結構苦労する。
* これはどのcookbookに入れよう…という迷いがたまに発生。
* ちょっと設定ファイルをいじったりするのにも手間が割とかかる。でもこれはchefというよりberks-api依存。


## ひとまずまとめ、と次回へ続く…
ここまでで、とりあえず「どんなルール」で進めてるかというのは書けたと思います。
ただ、これだとよくわからないので、次回は具体的にどうやって進めるのよ、というのを書きます。
ということでつまりは次回が本番です、きっと。



## その他参考サイト
以下のサイトを超参考にさせて頂きました！
[Goodbye Plain Old Chef Repository](http://maoe.hatenadiary.jp/entry/2013/07/11/185424)

あと、コレも定番？ですが、一通り見ておくといいと思います！
[[和訳] 初心者Chefアンチパターン by Julian Dunn #opschef_ja](http://www.creationline.com/lab/3080)

##