Vagrant+Chef Soloでのサーバー環境構築自動化を試してみる(参考: パーフェクトRuby on Rails 第8章「Railsのインフラと運用」)

ちょっと前から「パーフェクトRuby on Rails」という本をちょこちょこ読んでいる。 Railsについては、「RailsによるアジャイルWebアプリケーション開発」を一通り読んだり自分でも簡単なWebアプリ作ったりしてたのでざっくりとは理解してるつもりだったんだけど、ポロポロ知らなかった内容も取り上げられてたので楽しく読めている。

で、読んでたら第8章でVagrantとChefを使った環境構築の話が出てきて、以前から興味があった分野なので自分でも試してみる事にした。Vagrant+Chefに関しては既に色んな人がブログにまとめてて何番煎じだよ感半端無いかもだけど、気にしない事にする。最近はDockerの方が注目浴びてる気がするけどそれも気にしない事にする。

そもそも何でVagrantとかChefとかが注目を浴びたのか?

VagrantVMの設定や立ち上げをコードで表現して自動化出来るツール、Chefはマシン環境をコードで表現して環境構築を自動化出来るツールな訳だけど、この「コードで表現」と「自動化」という部分が注目を浴びた大きな理由だったと思う。

コードで表現し、環境構築を自動化する事で、「完全に制御したサーバー環境」を手に入れる事が出来る。それは手作業が無くなって楽になるとかそういうレベルの恩恵だけでは無くて、「Immutable Infrastructure」みたいな概念に繋がる。「Immutable Infrastructure」はサーバーから「状態(の変化)」を無くそうって発想で、アプリケーションのデプロイ時に新規で「完全に制御したサーバー環境」を構築して古い環境は捨て去る事で、状態の変化を無くして「移植性の高くてテストしやすいアプリケーション&サーバー環境」を作る。それによって、多くの恩恵があるんだって事で最近注目を集めてるっぽい。

この辺の話はnaoyaさんやgosukenatorさんがブログにまとめたりスライドで発表したりしてて、興味深かった。今はポータブルなコンテナ環境とかが熱いっぽいので、今後はDockerとかについても勉強したいと思う。

Immutable Infrastructureはアプリケーションのアーキテクチャを変えていく、伊藤直也氏

面白いと思ったのは、「状態」を避けてImmutable性を求める様な発想が「サーバー環境」っていう大きなものに対して自然と出てきている事。1つのアプリケーション内のオブジェクトについて考える場合でも、「状態」があると大変だから「Immutable」なValue Objectとして出来るだけ扱いたいみたいな話はあるんだけど、それと似た話が全然違うレイヤーで出てくるのは興味深いと思った。対象が何であれ、人間が感じる複雑性、扱いづらさは変わらないのかもしれない。

Vagrant と ChefでVM上に環境構築してみる

かなり脱線した上に時代はDockerとか言っちゃってやりづらいけど、タイトルにも書いたVagrant + Chefというのを試してみる。

まずは、vagrantによるVMの起動を行う。VM構築のベースイメージとしては、opscode-ubuntu-12.04を使う。 
「パーフェクトRuby on Rails」に載ってた例ではphusionpassendgerのubuntu-14.04-amd64-vboxを使ってたんだけど、それだとfnichol/chef-rbenvっていうrbenvのクックブック使ってrbenvインストールした時にrubyのビルドが上手く行かなかったから、fnichol/chef-rbenvgithubページでテスト済みになってたubuntu-12.04を使う事にした。

$ vagrant box add opscode-ubuntu-12.04 \
    http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-12.04_chef-provisionerless.box

vagrant initしてVagrantfileをローカルに作ってから、そこにvmの設定をいろいろ書く。また、chefの環境用にBerksfileも作成した。BerksfileはGemfileのcookbook版みたいなやつで、依存性を管理しながら必要なcookbookを指定して適用出来る。

Berksfileを使うにはberkshelf gemとchef gemが必要なんだけど、gem installする意外に最近だとchefdkを使うという選択肢もある。chefdkはchefを使うのに必要になりそうなツールをまとめてパッケージにしてくれてるやつで、自分もchefdkを使う事にした。公式サイトインストーラをダウンロード出来る。

chefdkインストールすると、knifeコマンド(chefの機能を使う時に必要なコマンド)とberksコマンドが使える様になる。berks vendor cookbooksを実行するとBerksfileに記述されたcookbookがインストールされる。

Berksfileには、サーバー環境構築って事でサーバーに必要そうないろいろなcookbookを記述した。

  1 source "https://api.berkshelf.com"
  2
  3 cookbook 'git'
  4 cookbook 'memcached'
  5 cookbook 'nodejs'
  6 cookbook 'database'
  7 cookbook 'xml'
  8 cookbook 'ruby_build'
  9 cookbook 'rbenv', git: 'git://github.com/fnichol/chef-rbenv.git', ref: 'v0.7.2'
 10 cookbook 'nginx'
 11 cookbook 'imagemagick'
 12 cookbook 'simple_iptables', git: 'git://github.com/dcrosta/cookbook-simple-iptables.git'

1行目はcookbookの取得元を記述する部分だけどそんなに意味は無い。後は使用するcookbookを並べてる。

berks vendor cookbooksコマンドを実行すると、./cookbooksディレクトリが生成されて、その中にダウンロードしてきたcookbookが並べられる。

これらのcookbookをVagrantfileの中でadd_recipeしてやる事で、vagrant provisionでプロビジョニングが走る様になる。以下のVagrantfileでは、vmの設定として使用するbox名やネットワークのポートフォワーディングの設定(ホストOSの8080番ポートがゲストOSの80番ポートと繋がってる)、後はバグを避ける為のちょこちょこした設定と、chefの設定を書いてある。

  1 # -*- mode: ruby -*-
  2 # vi: set ft=ruby :
  3
  4 VAGRANTFILE_API_VERSION = "2"
  5
  6 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  7   config.vm.box = "opscode-ubuntu-12.04"
  8
  9   config.vm.network "forwarded_port", guest: 80, host: 8080
 10
 11   # VMが立ち上がらないerrorを避ける為
 12   # https://github.com/mitchellh/vagrant/issues/2157
 13   config.vm.provider "virtualbox" do |vb|
 14     vb.customize ["modifyvm", :id, "--accelerate3d", "off"]
 15   end
 16
 17   config.vm.provision "chef_solo" do |chef|
 18     chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]
 19     chef.add_recipe 'build-essential'
 20     chef.add_recipe 'git'
 21     chef.add_recipe 'memcached'
 22     chef.add_recipe 'nodejs'
 23     chef.add_recipe 'database'
 24     chef.add_recipe 'xml'
 25     chef.add_recipe 'ruby_build'
 26     chef.add_recipe 'rbenv::system'
 27     chef.add_recipe 'nginx'
 28     chef.add_recipe 'imagemagick'
 29
 30     chef.json = {
 31       "rbenv" => {
 32         "global" => "2.1.2",
 33         "rubies" => [ "2.1.2" ],
 34         "gems" => {
 35           "2.1.2" => [
 36             { 'name' => 'bundler' }
 37           ]
 38         }
 39       }
 40     }
 41
 42     # provisioning実行時にSSLに関してwarningが出たので追加。
 43     # 詳しくは以下のリンク
 44     # http://stackoverflow.com/questions/22991561/chef-solo-ssl-warning-when-provisioning
 45     chef.custom_config_path = "Vagrantfile.chef"
 46   end
 47 end

ここまでで大体準備はOKで、vagrant upVMが立ち上がり、vagrant provisionでchefによるプロビジョニングが走るはずである。

これで大体はOK。オリジナルのcookbook生成の話なんかはまた後日書く。