不格好エンジニア

wordpress.comから引っ越しました。

【5分で学べる】Vagrant上にRailsをAnsibleでかんたんクッキング(CentOS6, MySQL, Rails4, Unicorn)

概要

VagrantとAnsibleでRailsの開発環境を構築したら便利すぎて鼻血吹きました。 ソースコードを公開しておりますので、ご自由にお使い下さい。

https://github.com/tjnet/vagrant_sakuravps_rails

最低限のシンプルな構成になっており、把握/カスタマイズしやすいと思います。 今後は、Production環境として用いるVPS(さくらVPS)の環境構築やデプロイも実装して自動化したいと考えています。

想定している読者様

・サーバ構築の自動化に取り組みたい小規模チームの開発者
・AnsibleとかVagrantとか使ったことないけど「5分で習得したい」人
・シンプルなVagrant+CentOS+Railsの開発環境を構築して、VPS/AWS上でも動かしたい人

※開発環境(vagrant)用のものであり、nginx, capistrano,production環境(さくらVPS)用のplaybookは未完成です。今後、実装予定です。 ※playbook_vagrant.ymlをコピーして少しカスタマイズすれば、さくらVPSAWSに転用できるはずです。

経緯

とある事情から、プロダクション環境をHerokuからVPSに移す事になりました。 その為の構築手順をブログやWikiにドキュメント化し、それをコピー&ペーストするのが前時代的でダルくなってきました。 ここでは手作業で行っていた内容をAnsibleで「InfraStructure as Code」にしていく過程をご紹介します。

なぜAnsibleを使うのか?

AnsibleではChefと異なり、構築サーバ側に何かをインストールする必要は、ほぼありません。 また、僕自身はChefやPuppetを使用した事はありませんが、動作がシンプルゆえに学習コストが低いと言われています。現時点でのオフィシャルドキュメントは十分に充実しており、シンプルな構成や小規模な構成での運用事例はググればすぐに見つかると思います。

検証環境

OS X 10.9上にてコマンドを実行し、Vagrant上で開発サーバを構築しています。

Virtual Box, Vagrant, Ansibleの導入

vagrantのインストールは、ここを確認して行って下さい。

最新版Ansibleのインストールは、次のようにHomebrewを利用します。

$ brew update
$ brew install ansible

詳細はこちらをご確認ください。

仮想マシン構築の為の準備

まずは、こんな感じで任意の場所にサブディレクトリを作って、そこに仮想サーバのひな形をcloneします。

mkdir -p VM/projects
cd VM/projects
git clone https://github.com/tjnet/vagrant_sakuravps_rails.git

ディレクトリ名が長過ぎてイケてないので、任意の名前に変更します。

mv vagrant_sakuravps_rails myapp
cd myapp

ここで、仮想マシンの設定を記述したVagrantfileを確認します。

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

  config.vm.define :web do |web_config|
    web_config.vm.box = "centos64"
    #web_config.vm.box_url = "http://files.vagrantup.com/precise64.box"
    web_config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.5-x86_64-v20140110.box"
    web_config.vm.network :private_network, ip: "33.33.33.33"
    web_config.vm.network :forwarded_port, guest: 3000, host: 8080

    web_config.vm.hostname = "develop-centos"

    web_config.vm.provider :virtualbox do |vb|
      vb.memory = 1024
    end

    config.vm.provision :ansible do |ansible|
      ansible.playbook = "provision/playbook_vagrant.yml"
      ansible.inventory_path = "provision/dev_hosts"
      ansible.limit = 'all'
      ansible.verbose = 'vvv'
    end
  end

end

主要部分について、少し補足します。

    web_config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.5-x86_64-v20140110.box"
    web_config.vm.network :private_network, ip: "33.33.33.33"
    web_config.vm.network :forwarded_port, guest: 3000, host: 8080

まず、この仮想マシンはCentOS6.5を使用します。ホストOS(Mac)のポート番号8080へのアクセスは、ゲストOS(VM上のCentOS)3000へ転送されます。

    config.vm.provision :ansible do |ansible|
      ansible.playbook = "provision/playbook_vagrant.yml"
      ansible.inventory_path = "provision/dev_hosts"
      ansible.limit = 'all'
      ansible.verbose = 'vvv'
    end

また、VagrantはAnsibleのPlaybookを用いて構成管理する機能を提供しており、provision/playbbok_vagrant.ymlを用いてサーバの構成管理を行う事がわかります。 ansible.verbose = 'vvv'は、Ansibleによるサーバ構築時に、デバッグログを詳細に出力する為の設定です。

Ansibleで構成管理するための対象ホストは、provision/dev_hostsに記載しています。 []付きでグループ名を記述することが可能です。グループを指定することで、複数のサーバを同時に構築する事が可能です。

[dev_server]
33.33.33.33

PlayBookについて

AnsibleのPlaybookは、構築するサーバの構成内容をYAML形式で記述したものです。 Chefでいうレシピにあたるものです。 見れば何となく理解できますが、インストールするパッケージや処理、設定をrolesでグルーピングして記述していくと、記述されたroles内の処理(task:)が実行されていきます。

ねっ、学習コスト低いでしょ? (^^)/

- name: setting rails to server
  hosts: dev_server
  user: vagrant
  sudo: yes
  vars:
    app_name: myapp
    environtment: vagrant
    mysql_port: 3306
    home: "/home/{{user}}"
    user: vagrant
    src_dir: '/usr/local/src'
    ruby_version: '2.1.2'

    rails:
      dir: /var/www/rails/
  roles:
    - common
    - mysql
    - ruby
    - rails
    #- nginx

各記述項目の意味は次の通りです。

項目 説明
hosts 対象のサーバグループ
user 対象サーバで実行するユーザ
sudo 対象サーバでsudoコマンドを使用して実行するか
roles 各taskを任意の名前でグルーピングしたものです。各roleの処理はroles/role_name/tasks/main.ymlに記述されています。

PlayBook:最低限のサーバ設定を行う

provision/roles/common/tasks/main.ymlで、下記の処理を行っています。
・ルートログインの禁止
・パスワード認証の禁止
・EPELを追加して、パッケージの種類を増やす
・パッケージのインストール(よくわからないパッケージはyum info package_nameで確認)

PlayBook:MySQLのインストールを行う

provision/roles/mysql/tasks/main.ymlで、下記の処理を行っています。
MySQLのインストール

PlayBook:Rubyのインストールを行う

provision/roles/ruby/tasks/main.ymlで、下記の処理を行っています。 ・Rubyのバージョン確認
Rubyソースコード入手
Rubyソースコードを解凍
Rubyソースコードコンパイル
Rubyをインストール
・gemをアップデート
・bundlerをインストール

PlayBook:Railsのインストールを行う

provision/roles/rails/tasks/main.ymlで、下記の処理を行っています。
Railsアプリケーションを作成する為のDirを作成
・/etc/resolv.confに追記(これをしないとRailsのインストールが異様に遅くなります)
※詳細はVagrant+VirtualBox(CentOS6)で「gem install rails」がすっごい遅い時の対処法とか、 Slow networking (due to IPv6?) on CentOS 6.x #1172をご確認ください。
JavaScriptのランタイムがないと、おこられるのでNode.jsを導入

いよいよ実行

ここまでPlayBookの構成について書いてみました。では実際にVagrant上でサーバ構築を行ってみましょう。

vagrant up 
vagrant provision web
vagrant upでvagrantを起動します。このコマンドで、VagrantはCentOS6のboxをダウンロードする為、初回は少し時間がかかるかもしれません。 。お茶でもすすってお待ちください^^。 ちなみに、ここで下記のエラーが出てるかもしれませんが、Railsの導入や開発作業自体には支障はありません。
Failed to mount folders in Linux guest. This is usually because
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:

mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` vagrant /vagrant
mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` vagrant /vagrant
vagrant provision webで、ゲストOS上のサーバ構築を行います。 Node.jsの導入には、少し時間がかかるかもしれません。 このVMには、
vagrant ssh
でアクセスできます。 その後は、 ・パーミッションの調整
rails new でwebアプリのベースを作成
MySQLを起動
・必要なポートをあける
iptablesの再起動
http://localhost:8080にアクセスする

と、順次設定すると、いつものRailsのトップページが表示されます。Congratulations! 詳細はREADMEをご確認ください。

TODO(今後やりたい事)

Capistranoでのデプロイ
Unicornの導入
・Nginxの導入
・プロダクション環境(さくらVPS)用のPlaybookを用意する
・厳密な冪等性を保つにはどうしたら良いのか、勉強する
・DockerとかImmutable Infrastractureに触れてみる