tkak's tech blog

This is my technological memo.

今更Chef Cookbookベストプラクティス

去年Chefが大流行して今更Chefの話を書くのも恥ずかしい気がするけど、@kajikenからリクエストがあったので、僕が思うChefのCookbookのベストプラクティスを書いてみる。

Berkshelf way

まずはBerkshelf について。BerkshelfはCookbookの依存関係を解決してくれる便利ツール。基本的にCookbookはプロジェクトとは別なリポジトリで管理して、プロジェクトごとに必要なCookbookをBerkshelfで取ってきて使うのがいいと思う。Cookbookのバージョン管理を厳密にできるので、毎回同じサーバ環境が構築できる。あと、人が作ったCookbookを使い回せるので、車輪の再発明しなくてすむ。素晴らしい。

ただ、Berkshelfはバージョンが3系になって、Berkshelf用のAPIサーバを立てないといけないので、僕は未だに2系を使ってる。Chefを使う人や管理するCookbookが多くなってきたらAPIサーバをたてたほうがいいと思う。

あと、これはちょっとしたTipsになるけど、Berksfileはrubyのファイルになってるので、cookbookごとにgitのブランチを指定するよりも、こんな感じできれいにかくことができる。

# before
cookbook 'mysql', git: 'https://github.com/tkak/hoge.git'
cookbook 'nginx', git: 'https://github.com/tkak/fuga.git'
cookbook 'vim', git: 'https://github.com/tkak/piyo.git'


# after
def oreno_cookbook(name, options = {})
  cookbook(name, {
    git: "https://github.com/tkak/#{name}.git"
  }.merge(options))
end

oreno_cookbook 'hoge'
oreno_cookbook 'fuga'
oreno_cookbook 'piyo'

Cookbookの粒度

基本的に一つのCookbookは一つのリポジトリで管理するべき。馬鹿でかいCookbookを作ったりするとメンテナンスが大変になることが多いので避けた方がいい。ただ、一つのCookbookにどこまで処理を盛り込めばいいのか、Cookbookの粒度について時々迷うことがある。とりあえず、最初から大きなCookbookにするのではなく、最低限の機能を持つCookbookを何個か作って、そのあとそれらをまとめたCookbookを作ればいいと思う。

Cookbookをタイプ別にわけるとこんな感じになる。

Element Cookbook

最低限の機能、それ自体で完結するCookbook。

Library Cookbook

recipeが存在しない、Definitions, LWRPs, Librariesで構成されたCookbook。

Wrapper Cookbook

他のCookbookをラッピングするCookbook。

Role Cookbooks

Roleを定義するためのCookbook。基本的にRoleは使わない、バージョン管理ができないから。代わりにRole Cookbookを使う。

# oreno_app/recipes/base.rb
include_recipe "hoge"
include_recipe "fuga"
include_recipe "piyo"

# oreno_app/metadata.rb
name             'oreno_app'
maintainer       'tkak'
maintainer_email 'hoge@mail.com'
license          'All rights reserved'
description      'role cookbook'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.0.1'
depends          'hoge'
depends          'fuga'
depends          'piyo'

Cookbookの名前

Cookbookの名前は、-(ハイフン)を使わない。-だとLWRPがうまく動かないっていう地雷があるので、代わりに_(アンダースコア)を使ってる。あと、名前は動詞ではなく名詞になるようにしてる。

chef-repoの構成

oreno-chef-repo/
├── Berksfile
├── Gemfile
├── README.md
├── conf
├── cookbooks
│   ├── fuga
│   ├── hoge
│   └── piyo
├── data_bags
├── environments
└── site-cookbooks
    ├── oreno_app
    └── oreno_db

http://shibayu36.hatenablog.com/entry/2014/08/04/073000chefリポジトリ構成はこんな感じ。特にcookbookssite-cookbooksは、Berkshelfで取ってきたCookbookかそうでないかの違いで分けてる。cookbooksにはBerkshelfで取ってきたcookbooks、site-cookbooksには自分のアプリ用のcookbooksを配置する。Berkshelfのデフォルトでは、.cookbooks配下にCookbookが置かれるが、cookbookの場所を明確にしておきたいのであえてberks install --path cookbooksでインストールしている。

CookbookのTestについて

CookbookのTestはServerspecを使ってる。深淵な理由でTest-kitchenは使ってない。ProxyとかProxyとかProxyとか。CIは、Jenkins + Vagrant + Chef + Foodcritic + Serverspecでまわしてる。よくある感じ。

アプリケーションレイヤーのCookbookはDockerを使って開発するのがいいと思ってはいるが、まだVMを多用している。毎回VMの起動に時間がかかるので早くコンテナを導入したい反面、OSのカーネルに依存するような部分のCookbookに関しては地道にVMを使うしかないのかなぁ、なんて感じてる。適材適所で使うのは全然ありだと思う。

まとめ

2、3年前くらいからChefを使い初めたんだけど、何度Cookbookを書き直したか分からない…w 試行錯誤してようやく今の形に落ち着いた感じ。これからChefを導入する人やCookbookを書き直す人の参加になれば幸いです。もう少し知見ある気がするけど、疲れたので今日はこの辺で。でわでわ。

あ、Chefの使い方とかかなり詳しく知りたい時は、「Chef活用ガイド」がオススメです。かなり細かくChefについて書いてあります。ちょっとした国語辞典並みの厚さですがw よかったらぜひ手に取ってみてください。

Chef活用ガイド コードではじめる構成管理

Chef活用ガイド コードではじめる構成管理