社内で Chef 勉強会をして色々教えてもらった

自分の働いている会社は、ロリポップや heteml, Sqale などのホスティング事業をしてたり、また mizzy さんをはじめとして Puppet などを使ったプロビジョニングへの知識・経験がある人が多く、インフラエンジニアの人も多い。

開発側としては正直ものすごく楽なことが多々ある。けれどそうやって頼ってると、個人的な遊びとか開発に必要な簡単な VM とか以外ではなかなか Puppet や Chef を使ってという機会が少ないんで、まずは適当なネタをでっちあげて偉大なプロビジョニングマスターの人たちから少しずつ色々教えてもらおうと思いました。

ということでまず最初にやったのは rails-dev-box を chef で移植してみました。

rails-dev-box

rails-dev-box は Contributing to Ruby on Rails / edgeguides.rubyonrails.org で紹介されている Puppet + Vagrant を使って Rails 自体の開発をするための環境を簡単に作るというプロジェクトです。

rails-dev-box は本当に簡単に rails 環境を構築することができて、VirtualBox と Vagrant がインストールされていれば以下のコマンドをたたくだけです。

host $ git clone https://github.com/rails/rails-dev-box.git
host $ cd rails-dev-box
host $ vagrant up

host $ vagrant ssh # で接続
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
...
vagrant@rails-dev-box:~$

port 3000 が port forward されているので host の localhost:3000 で vagrant の VM で rails がが起動していれば見ることができる

host $ ls
README.md   Vagrantfile puppet
host $ git clone git://github.com/rails/rails.git # rails を clone

vagrant@rails-dev-box:~$ ls /vagrant # リモートの /vagrant 以下に mount される
puppet  rails  README.md  Vagrantfile

ローカルで開発して、テストは vagrant の VM 上で流す、というのが想定される使い方だと思う

chef-rails-dev-box

ここからは rails-dev-box と同じものを chef を使って構築していきます。 chef-solo に関しては入門Chef Solo - Infrastructure as Codeがとても参考になりました。

だんだん書くのがめんどくさくなってきたので、以下コマンドにコメントつけるだけにします。

host $ gem install knife-solo --pre # install 0.3.0 # knife-solo は 0.3.0 以上が 入門Chef Solo で勧められていたので従う
host $ gem install librarian # librarian は Chef の cookbooks を管理するための Ruby でいう bundler

# box の種類がたくさんあってどれがいいのか全然分からなかった、なるべくミニマムなのを選ぶのがいいとのことだけどどれがミニマムかも分からない
host $ vagrant box add ubuntu-1204 http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-1204-x64.box
host $ vagrant list # 追加した box が表示されることを確認

host $ mkdir chef-rails-dev-box
host $ cd chef-rails-dev-box

host $ vagrant init ubuntu-1204 # これで Vagrantfile が作成される

host $ vagrant up
host $ vagrant ssh # で接続できる

host $ vagrant --help # 確認できる

host $ vagrant provision # chef を適用

host $ knife configure # 今回は chef サーバ使わないので全部エンターで
host $ knife solo init chef # rails-dev-box にしたがって chef のレシピを作るディレクトリを作成

以下のような階層のディレクトリが作られる。シンプルで分かりやすい。ちょっと前は https://github.com/opscode/chef-repo を落としてきて、自分色に染めるというのがやり方だった気がするけど、その作法は忘れてよさそう。

└── chef
    ├── cookbooks
    ├── data_bags
    ├── nodes
    ├── roles
    └── site-cookbooks

このレシピ専用の cookbook を作る時は -o site-cookbooks として指定する

$ knife cookbook create hello -o site-cookbooks

librarian と berkshelf

cookbooks 管理で有名なものは librarian と berkshelf があるようです。(その他もあるかも)

とりあえず librarian を使ってみた

$ librarian-chef init # で Cheffile ができる
$ vi Cheffile
$ librarian-chef install # で bundle install のようにインストールできる

ここで自分は cookbooks 以下にインストールされる外部の cookbooks までバージョン管理に含めてたけど、当然 bundler のように .gitignore で無視すべきだ、ということをあんちぽさんに指摘してもらった。

rails-dev-box で box の中でやっていることは以下の内容になる

  • Git
  • RVM
  • Ruby 1.9.3 (binary RVM install)
  • Bundler
  • SQLite3, MySQL, and Postgres
  • System dependencies for nokogiri, sqlite3, mysql, mysql2, and pg
  • Databases and users needed to run the Active Record test suite
  • Node.js for the asset pipeline
  • Memcached

chef-rails-dev-box では rvm と Ruby 1.9.3 (binary RVM install) をやめて以下を使うことにする

  • rbenv
  • Ruby 2.0.0-p0 (via ruby-build)

余談だけど以前 hsbt さんが rails-dev-box にrbenv のパッチをおくっているけど reject されている。 理由は rbenv がバイナリ経由でインストールすることができないから。@fxn さん (rails-dev-box の owner) は簡単にインストールできることを重視している。 (ただこれ rbenv と ruby-build だけをいれてるだけで Puppet が走るときに別に ruby-build するわけでもないから時間もかからないし、すごい殊勝な PR でマージしてもいいと個人的には思う...)

色々と話したり教えてもらったこと

  • cookbook fork とかされてる奴とかあるけどどれが正しいのか全く分からない。基本は OpsCode を使う感じにした。カオス感ある
  • apt-get -y upgrade すると文字化けして死ぬ、なぜ?
    • OS が問題なのでは? なるべくミニマムな奴使いましょう
  • database は http://community.opscode.com/cookbooks/database
    • MySQL, PostgreSQL, SQL Server などの DB 作成や User 作成が抽象化されている
    • Puppet だとそこまで抽象化したものはないよ
  • @fxn さんに質問もしたんすけど rails-dev-box 使うとテスト遅いんですけど...
    • NFS + vagrant でぐぐれ! vagrant の FAQ ですよ!!1
    • 実際に rails-dev-box で試したら3時間かかってたのが1時間くらいになって 300% パフォーマンス改善された
    • chef-rails-dev-box では NFS をデフォルト使うようにしてみる
  • パッケージのインストールはこんな風に書きました
    • レシピに書くのはダメ。必ず attributes を使うことで nodes などでも override していく正しいレシピを書くことができる
    • リファクタした
  • pre と post みたいにして 順序の依存を書いてるんですけどどうなんでしょうか?
    • こういう箇所 は bash (script) リソース使わずに direcory リソースを使うべきです!!
    • そうすれば順序に依存した書き方を減らすことができます
    • なるほどーと思ってやってみたけど direcory リソースではうまくいかなかった...
  • chef はディレクトリ構造がしっかりしている。puppet は syntax が固いが、ディレクトリ構造はゆるい。Puppet はベストプラクティスはあるけれど、そういうのを学ばないとベチャッとしたレシピ (manifest) になりがち。Puppet と Chef どっちもどっちだけど自分なら Puppet を選ぶかな(by あんちぽさん)
    • あんちぽさんもはや Puppet と Chef の哲人みたいな感じになってきてる...
  • Puppet は librarian みたいなの使われてますか?
    • まだ現場じゃそんなにつかわれてないんじゃないかな? librarian-puppet というのもあるよ
  • 今回のような開発環境としてだけ使いたいケースだと Vagrantfile に attributes を書いて vagrant provision で実行してもいいけど、通常はどこかにデプロイするわけで、そういう時は knife-solo で chef を適用するようにすることでインターフェースを共通にして適用できる

WIP of chef-rails-dev-box

  • ひと通り動くけど、bundle exec rake test とした時に止まってしまうテストがあるなー
  • インストールに時間かかるけれど、chef-rails-dev-box は rails-dev-box とは違うポリシーで動くようにしていけたらと思います