VagrantとChef-soloについて初歩の備忘

開発環境を管理する

遅まきながら触ってみたら、予想以上に簡単だったのでちゃっちゃと備忘する次第。

ということで、開発環境をどうにかしたかったので、VagrantとChefによる管理を試してみました。ついでに、Amazon S3のようなインスタンスを対象にもセットアップできるようにすることも想定してます。

本記事は、ほんとに備忘録ノリなので、「Chefとは」「Chef soloとは」「Vagrantとは」などについては各自ググってください。

前提

  • 現状は、開発環境のVMが秘伝のタレと化している
  • 新しくVMをセットアップする際の作業にも秘伝のスクリプトが点在する
  • phpやnginxのconfigが、複数のリポジトリに偏在していて集めるの大変
  • それぞれが個別に設定しなくても、開発環境を一斉に更新できるようにしたい
  • 新しい人がジョインしたときも同じ水準の開発環境をすぐに用意できるようにしたい

で、今回はプロダクション環境までは手を伸ばさずに、フロントエンド実装者の開発環境という用途に限定して用意しました。ミドルウェアのバージョンがプロダクションとは異なるなど、再現の精度はテキトーです。

業務用にこしらえているので、GitHubには公開されてないです。社内のGHEで管理してるようなもの。

Vagrantのセットアップ

まずVirtualBoxとVagrantをインストールします。今回は記事では下記のバージョンを利用しています。

% vboxmanage -v
4.2.16r86992 
% vagrant -v
Vagrant version 1.2.2

Vagrantfile

vagrant init でVagrantfileが作成されるので、下記のように設定しました。(実際に自動で設定されるVagrantfileは、コメントがモリモリ載ってます)

Vagrant.configure("2") do |config|

  # 利用するboxの名前
  config.vm.box = "centos64"

  # 利用するboxのurl
  # centos64 という名前のboxがなければ、ここで指定したboxが自動でDLされる
  config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130427.box"

  # ホストマシンからのみ参照できるようにプライベート化
  config.vm.network :private_network , ip: "192.168.50.4"

  # ホストの ../proj-repo を ゲストの /var/www/として共有フォルダ化
  # ここでのホスト側のパスは、Vagrantfileからの相対
  config.vm.synced_folder "../proj-repo", "/var/www/"

  # やたらネットワークが遅い現象の対策 (ipv6絡み)
  # see https://github.com/mitchellh/vagrant/issues/1172
  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
  end

end

ネットワーク設定の補足

入門Chef Solo - Infrastructure as Codeを参考にしていましたが、最近のVagrantは設定フォーマットのv2がデフォルトになっているようで、ネットワーク設定の記述が異なりました。

Vagrant Documentationを見ると載ってますが、:private_network だったり ip の指定が必要だったりしました。

# たぶんv1の書き方(動かないほう)
config.vm.network :hostonly , "192.168.50.4"
# v2の書き方
config.vm.network :private_network , ip: "192.168.50.4" 

その他、ネットで調べて設定するときは、この設定のバージョンの違いに気をつけた方がよいかもしれません。

Chefの設定

今回はGemfile的に表現すると、下記のバージョンを利用しています。

source 'https://rubygems.org'

gem 'chef', '11.6.0'
gem 'knife-solo', '0.3.0'
gem 'berkshelf', '2.0.7'

chef用のリポジトリを作成します。

% knife solo init chef-repo
% cd chef-repo
% git init
% git add .
% git commit -m "create kitchen"

Cookbookを作成

大層な設定を必要としていなかったので、configファイルを管理するくらいの用途でcookbookを、./site-cookbooks 内に作成します。ここではサンプルとして、iptablesの管理をするレシピにします。

% knife cookbook create iptables -o site-cookbooks
% cd site-cookbooks/iptables
% ls
CHANGELOG.md attributes   files        metadata.rb  recipes      templates
README.md    definitions  libraries    providers    resources

receipes/default.rbを下記のようにして...

# iptablesのサービスを指定
service "iptables" do
  supports :status => true, :restart => true, :reload => true
  action [:enable, :start]
end

# テンプレートから設定を上書き作成
template "/etc/sysconfig/iptables" do
  source "iptables"
  owner "root"
  group "root"
  mode 0600
  notifies :restart, 'service[iptables]'
end

templates/default/iptablesとして下記のファイルを作成します。templatesという名前のとおり、erbとして変数(attributes)埋め込んだりもできますが、今回は単純にコピーするだけで利用。

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

このレシピが実行されると、22番と80番のポートが開いてる上記の設定が、/etc/sysconfig/iptablesへ勝手に書き込まれます。nginxの簡単なサンプルも置いておきます。

# nginxのパッケージをインストール
package "nginx" do
  action :install
end

# nginxのサービスを指定
service "nginx" do
  supports :status => true, :restart => true, :reload => true
  action [:enable, :start]
end

# テンプレートから設定を上書き作成
template "nginx.conf" do
  path "/etc/nginx/nginx.conf"
  source "nginx.conf.erb"
  owner "root"
  group "root"
  mode 00644
  notifies :reload, 'service[nginx]'
end

こんなノリで各ミドルウェアのpackage, service, template の3点セットを量産していけば、設定ファイルの管理に使うレシピくらいは簡単に量産できます。らくちん。

元々が秘伝のスクリプトで処理されていた部分なども、可能な限りcookbookに書き換えていく感じ。結局cookbookの中で、秘伝のrpmをアレしたり、秘伝のソースをビルドしたりとか、そういうノリなところもあるわけですが以下略。

Berkshelfを設定

Berkshelfを利用して、レシピを管理します。 下記はBerksfileという利用するcookbookの指定ファイルです。このファイルをknife solo initしたディレクトリ直下に配置します。

site :opscode
cookbook 'yum', '2.3.0' 
cookbook 'iptables', path: './site-cookbooks/iptables'
cookbook 'nginx',    path: './site-cookbooks/nginx'
cookbook 'php54',    path: './site-cookbooks/php54'
...
..
. 以下略

例えば、こんな感じで書いています。今回はyum以外のレシピが自前なので、それぞれ./site-cookbooks内の自作レシピへのパスを指定しています。下記のコマンドを実行すると、./cookbooks内にレシピが自動でインストールされます。

# Berksfileを作成したところで実行
% berks install --path cookbooks

cookbooksにサードパーティレシピ、site-cookbooksに自作レシピを入れるという運用のほうが一般的?かもしれませんが、ここでは自作レシピも並べて書いて管理したかったので、berkshelfでcookbooksに、すべてのレシピが集約されるようにしました。

roleを指定

roles/local.rb として下記のようなファイルを作成して、利用したいレシピをグループ化しました。色々用意したレシピ

name "local"
description "for local development"

run_list(
  "recipe[yum::epel]",
  "recipe[yum::remi]",
  "recipe[php54]",
  "recipe[nginx]",
  "recipe[iptables]",
  …
  ..
  . (以下略)
)

yum::epelは、yum cookbookのepelレシピ、というような意味です。このファイルに限らず、rubyと考えずに設定ファイルとして割り切って記述すれば、迷うことはあんまり無いと思います。

VagrantにChefを設定して起動

ディレクトリまとめたかったので、Vagrantfileもchef-repoにぶち込んでしまいました。(乱暴)

ここまでの流れでchef-repo内は、下記のようなファイル・ディレクトリになっています。

% tree -L 1
.
├── Berksfile
├── Vagrantfile
├── cookbooks
├── data_bags
├── nodes
├── roles
├── site-cookbooks
└── solo.rb

5 directories, 3 files

VagrantでVMを立ち上げる際に、chef soloが流れるようにVagrantfileに設定を追加します。

  config.vm.provision :chef_solo do |chef|
    # cookbooksに集約されているので、そこにだけパスを通す
    chef.cookbooks_path = "cookbooks"

    # rolesのパスも通す
    chef.roles_path     = "roles"
 
   # roleを指定
    chef.add_role("local")
  end

これでOK。あとはvagrant upすれば、boxがDLされた後にVMが立ち上がり、自動でchefが流れてセットアップされて、開発環境がすぐ使えるようになります。

この環境自体がGitで共有されるようにしているので、cloneすればすぐに使えるようになりますし、開発環境への変更自体もコードベースでGit管理され、速やかに共有できるようになります。

インスタンスやらVPSやら、余所のホストに対してchefを流す際は、knife solo prepare hostnameして./nodes/hostname.jsonにroleなりrun_listを指定して、knife solo cook hostnameすればきっと動く(投げやり)

参考