入門Chef-Soloを片手にRailsアプリを動作させるところまでやってみた
Chefについては前々から気にはなっていたけどまとまった情報があまりなく、中々じっくりと取り組めていなかったのですが、ちょうど次のプロジェクトから導入しようとしていたところに、『入門Chef Solo - Infrastructure as Code』というありがたいまとめ本が出版されたので、それを片手に色々と実験してみました。
入門Chef Soloはよくまとめられていて非常に助かったのですが、Kindleで見ると目次がなくて逆引き的に利用しながら構築するのが結構大変でしたので、自分用に手順書としてまとめてみました。(目次に関しては現在修正版が出ているようです)
とりあえずRailsのサービス開発プロジェクトで使いたいので、以前にさくらVPSの設定で行ったような感じでrvm, nginx, unicorn, mysqlでRailsアプリが動くところまでやってみました。もう1年以上前ですが、前回はこんな感じで設定していました。
Vagrantを使って仮想サーバーを立てる
まずは気軽に実験できるように仮想サーバーを立てます。
1. OracleのVirtualBoxをインストール
2. Vagrantをインストール
$ gem install vagrant
3. Vagrantで利用するOSイメージの取得
こちらでイメージ一覧が公開されていますが、今回は書籍にあったものをそのまま指定。
$ vagrant box add base http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.3-x86_64-v20130101.box
4. 適当なディレクトリでinitを実行して仮想サーバーの初期化します。
$ vagrant init (Vagrantfileが生成されます)
5. Vagrantfileのネットワーク設定を追加します。
... config.vm.network :private_network, ip: "192.168.50.12" ...
6. 仮想サーバーを起動します。
$ vagrant up
7. SSHで接続できればOK。
$ vagrant ssh
8. SSHの設定も追加しておきます。
$ vagrant ssh-config --host vagrant01 >> ~/.ssh/config $ ssh vagrant01
9. 不要になったらこれで停止、削除できます。
$ vagrant halt $ vagrant destroy
knife-soloのインストールと設定
1. knife-soloを使うと、ローカルマシンからリモートサーバー(vagrant)に対してChef Soloを実行できるようになります。
$ gem install knife-solo
2. knifeの初期設定を行います。表示される質問は全てデフォルトでOK。
$ knife configure
3. サードパーティのクックブックを利用するために設定しておきます。OPSCODEでユーザー登録を行い、プロフィールページにある get private key から秘密鍵を取得。先ほどのknife configureで生成した ~/.chef/knife.rb の client_key にこの秘密鍵を指定しておきます。
... client_key '/Users/ntaku/.chef/ntaku.pem' ...
Berkshelfのインストール
1. サードパーティのクックブックを効率よく管理するためにBerkshelfを使いたいので、こちらも先に設定しておきます。
$ gem install berkshelf
2. chef-repo/Berksfileを作成します。yum以外は自分でクックブックを作りたいところですが、まだそこまできちんと書けないので、とりあえず既存のクックブックを利用します。
site :opscode cookbook 'yum' cookbook 'mysql' cookbook 'rvm', git:'https://github.com/fnichol/chef-rvm.git' cookbook 'nodejs', git:'https://github.com/mdxp/nodejs-cookbook.git'
3. Berksfileで指定したクックブックを取得します。--pathオプションでクックブックの保存先を指定できます。指定しない場合は、~/.berkshelf/cookbooksに取得したファイルが保存されます。
$ berks --path cookbooks
クックブックとレシピの作成
オリジナルのクックブックを作成していきます。
とは言っても今回追加するのは2つだけです。
$ cd chef-repo $ knife cookbook create iptables -o site-cookbooks $ knife cookbook create nginx -o site-cookbooks
iptables
設定ファイルは実際に使っているものをそのまま持って来ました。
これで設定ファイルがそのままvagrantへ転送され、iptablesが再起動されます。
/chef-repo/site-cookbooks/iptables/recipes/default.rb
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
/chef-repo/site-cookbooks/iptables/templates/default/iptables
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :RH-Firewall-1-INPUT - [0:0] -A INPUT -j RH-Firewall-1-INPUT -A FORWARD -j RH-Firewall-1-INPUT -A RH-Firewall-1-INPUT -i lo -j ACCEPT -A RH-Firewall-1-INPUT -p icmp --icmp-type any -j ACCEPT -A RH-Firewall-1-INPUT -p 50 -j ACCEPT -A RH-Firewall-1-INPUT -p 51 -j ACCEPT -A RH-Firewall-1-INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT -A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT -A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # SSH, HTTP -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT -A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited COMMIT
nginx
設定ファイルが2つと、レシピファイルが1つです。
こちらもiptablesと同じ感じで。
/chef-repo/site-cookbooks/nginx/recipes/default.rb
package "nginx" do action :install end service "nginx" do supports :status => true, :restart => true, :reload => true action [:enable, :start] end template "/etc/nginx/nginx.conf" do source "nginx.conf.erb" owner "root" group "root" mode 0644 notifies :reload, 'service[nginx]' end directory "/etc/nginx/sites-enabled" do owner "root" group "root" mode 0644 action :create end template "/etc/nginx/sites-enabled/default.conf" do source "sites-enabled.conf.erb" owner "root" group "root" mode 0644 notifies :reload, 'service[nginx]' end
/chef-repo/site-cookbooks/nginx/templates/default/nginx.conf.erb
user nginx; worker_processes 1; pid /var/run/nginx.pid; error_log /var/log/nginx/error.log; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; gzip_disable "msie6"; gzip_proxied any; gzip_min_length 500; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; # virtual Hosts include /etc/nginx/sites-enabled/*; }
/chef-repo/site-cookbooks/nginx/templates/default/sites-enabled.conf.erb
upstream unicorn_rails_proxy { server unix:/tmp/unicorn_<%= node['nginx']['application'] %>.sock fail_timeout=0; } server { listen <%= node['nginx']['port'] %>; server_name _; root /var/www/<%= node['nginx']['application'] %>/current; access_log /var/log/nginx/<%= node['nginx']['application'] %>_log; error_log /var/log/nginx/<%= node['nginx']['application'] %>_error_log; rewrite_log on; location / { proxy_pass http://unicorn_rails_proxy; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; } location ~ ^/(images|javascripts|stylesheets|system)/ { root /var/www/<%= node['nginx']['application'] %>/current/public; expires max; break; } }
<%= node['nginx']['application'] %>は後からnodeファイルで値を指定します。
nodeファイルの編集
最後にnodeファイルでノードに反映させるレシピを指定します。
/chef-repo/nodes/vagrant01.json
{ "rvm": { "rubies" : ["ruby-1.9.3-p392"], "default_ruby" : "ruby-1.9.3-p392" }, "mysql": { "server_root_password": "test", "server_repl_password": "test", "server_debian_password": "test" }, "nginx":{ "application" : "chef_rails_template", "port" : 80 }, "run_list":[ "recipe[yum::epel]", "recipe[rvm::system]", "recipe[mysql::server]", "recipe[nginx]", "recipe[iptables]", "recipe[nodejs]" ] }
Chefの実行
いよいよChef Solo実行です。(実際は行ったり来たりなので、ここまでに何度も実行していますが..)
1. prepareを実行して指定したホストにChefの実行環境を準備します。(初回のみ実行する)
$ cd chef-repo $ knife solo prepare vagrant01
2. 適応したいホストを指定してChef Soloを実行します。レシピに問題がなければこれでサーバーの環境構築は全て完了です。
$ knife solo cook vagrant01
Railsデプロイ
ここからはおまけみたいなものなので、簡単にできるようにサンプルプロジェクトをgithubに作りました。こちらのプロジェクトをcapistranoを使ってvagrantへデプロイします。
- https://github.com/ntaku/chef_rails_template
- deploy.rbはSSH周りを自分のものに変更してください。
- unicorn.rbはそのままで行けると思います。
1. vagrant上に予めproduction用のDBを作っておきます。MySQLのパスワードはvagrant01.jsonで指定したtestです。
$ ssh vagrant01 $ mysql -u root -p mysql> create database chef_rails default character set=utf8;
2. githubからプロジェクトを取って来てデプロイ & 起動します。(ローカルマシン)
$ git clone git@github.com:ntaku/chef_rails_template.git $ cd chef_rails_template $ cap deploy:setup $ cap deploy $ cap deploy:start
3. アプリケーションにアクセスします。
http://192.168.50.12/ にアクセスして「TOP PAGE」と出れば全て正しく動作しています。
まとめ
『入門Chef Solo - Infrastructure as Code』のおかげで大分Chefと仲良くなれました。
この本がなかったら3倍は時間がかかったと思います..