Ansible と Vagrant を使って Rails 開発環境(Ubuntu + rbenv + MySQL5.6 + node.js)を構築する

More than 3 years have passed since last update.


バージョン&記載ソースリポジトリ

version

ansible 1.9.1

Vagrant 1.7.2

VirtualBox 4.3.28

ポイントとなるソースのみ載せています。全てのソースが見たい場合は、以下のリポジトリを参照してください。

Ansible で構築したサーバーのアプリの各バージョン

version

Ubuntu 14.04.2 LTS

ruby 2.2.2p95 (rbenv)

mysql 5.6.19

Rails 4.2.3

Bundler 1.10.5

nodejs 0.12.5

npm 2.11.2

bower 1.4.1

grunt-cli 0.1.13


概要

Ansible を使って、Rails 開発環境のテンプレートを作りました。

Docker で作るべきか悩みましたが、みんなのローカル環境に展開するための環境を Docker とするべき理由を理解することができませんでした。

Docker での開発環境構築については、これから勉強していきます。

今回は、Amazon Linux ではなく、Ubuntu(Vagrant + VirtualBox) で作っています。


rbenv, ruby のインストール

https://github.com/avsej/ansible-rbenv/blob/master/tasks/main.yml

これを参考にしました。

Ansible では、rbenv のモジュールが提供されていないので、shell:, command: を使うことになります。

Ansible のモジュールはたくさん出ているので、いつか rbenv モジュールが提供されるかもしれません。そうすれば、もっとスッキリした感じで書けると思います。

ignore_errors: というパラメーターを知りました。

Ansible はエラーが出た時点で処理が止まりますが、このパラメーターを使うことで、エラーが無視されます。

コンソールに赤文字で「failed:...」と表示され、その下に「...ignoring」が表示されるます。

問題はないのですが、failed と表示されることが気になります。

ignore_errors: を使わない方法があるのであれば、その方法を利用したほうが良いと思いました。


ansible/roles/rbenv/tasks/main.yml

---

- name: Install dependencies for rbenv
apt: name={{ item }} state=latest
with_items:
- git

- name: Install rbenv
sudo: yes
sudo_user: "{{ rbenv_user }}"
git: repo=https://github.com/sstephenson/rbenv.git dest=~/.rbenv

- name: Add ~.rbenv/bin to PATH
sudo: yes
sudo_user: "{{ rbenv_user }}"
lineinfile: >
dest="~/.profile"
line="export PATH=$HOME/.rbenv/bin:$PATH"

- name: Eval rbenv init in ~/.profile
sudo: yes
sudo_user: "{{ rbenv_user }}"
lineinfile: >
dest="~/.profile"
line='eval "$(rbenv init -)"'

- name: Install dependencies for ruby-build (see. https://github.com/sstephenson/ruby-build/wiki)
apt: name={{ item }} state=latest
with_items:
- autoconf
- bison
- build-essential
- libssl-dev
- libyaml-dev
- libreadline6-dev
- zlib1g-dev
- libncurses5-dev
- libffi-dev
- libgdbm3
- libgdbm-dev

- name: Install ruby-build as rbenv plugin
sudo: yes
sudo_user: "{{ rbenv_user }}"
git: repo=https://github.com/sstephenson/ruby-build.git dest=~/.rbenv/plugins/ruby-build

- name: Check if version is installed ruby
shell: "sudo -iu {{ rbenv_user }} rbenv versions | grep {{ rbenv_ruby_version }}"
register: rbenv_check_install
changed_when: False
ignore_errors: yes

- name: Install ruby
command: "sudo -iu {{ rbenv_user }} rbenv install {{ rbenv_ruby_version }}"
when: rbenv_check_install|failed

- name: Check if version is the default ruby version
shell: "sudo -iu {{ rbenv_user }} rbenv version | grep {{ rbenv_ruby_version }}"
register: rbenv_check_default
changed_when: False
ignore_errors: yes

- name: Set default ruby version
command: "sudo -iu {{ rbenv_user }} rbenv global {{ rbenv_ruby_version }}"
when: rbenv_check_default|failed



mysql インストール

以下のエラーが発生して、悩みました。

invoke-rc.d: initscript mysql, action "start" failed.

dpkg: error processing package mysql-server-5.6 (--configure):
subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
mysql-server-5.6
E: Sub-process /usr/bin/dpkg returned an error code (1)

仮想環境のメモリが少ないためにエラーが発生していました。メモリを 1G 以上割り当てればエラーを回避できることを確認しました。Vagrant ファイルは別途記載します。

ホストからも mysql に接続できるようにするために IPアドレスによる制限をかけないようにしています。これはローカルで動かす開発環境ならではの設定です。

絶対に本番環境で、このような設定にはしないでください。


ansible/roles/mysql/tasks/main.yml

---

- name: Install mysql
apt: name={{ item }} state=latest
with_items:
- mysql-server-5.6
- python-mysqldb

- name: Set mysql service to start on boot
service: name=mysql state=started enabled=true

- name: Put my-develop.cnf
template: src=my-develop.cnf.j2 dest=/etc/mysql/conf.d/my-develop.cnf backup=true mode=0644
notify: restart mysql

- name: Set the root privileges
mysql_user:
user: root
host: "{{ item }}"
password: ""
with_items:
- "%"
- 127.0.0.1
- ::1
- localhost


以下のテンプレートの設定は、外部から接続をさせないローカル環境ならではの設定です。本番環境では絶対にしてはダメな設定です。

conf.d 配下に設定ファイルを置くことで上書きできるようになったので、my.cnf を修正しなくても設定変更できます。

上書きしたい設定内容が増えてきたら設定情報の変数化を行う予定です。


ansible/mysql/templates/my-develop.cnf.j2

# {{ ansible_managed }}

[mysqld]
bind-address = 0.0.0.0



node.js のインストール

therubyracer でも良いのですが、Javascript の開発ツールを使うことが多いので、node.js をインストールします。

node.js は setup 用のシェルをダウンロードしてから実行するタイプです。

shell: モジュールを使っていて、ansible を実行するたびに changed と判断されてしまっています。この箇所は改善すべき箇所ですが、良い方法を思いついていません。


ansible/roles/nodejs/tasks/main.yml

---

- name: Download setup shell for nodejs
get_url: url="https://deb.nodesource.com/setup_0.12" dest="/tmp/setup_node.sh" mode=0755

- name: Setup nodejs
shell: /tmp/setup_node.sh

- name: Install nodejs
apt: name=nodejs state=latest



開発ツールのインストール

rbenv の gem に対してインストールする方法は、現時点(2015.06.28)ではこの方法がスマートだと思います。

shell:, command: モジュールを利用する方法もあるようですが、gem: モジュールを使ったほうがスッキリ書けます。


ansible/roles/env/tasks/main.yml

---

- name: Install mysql
apt: name={{ item }} state=latest
with_items:
- libmysqld-dev

- name: Install rails and bundler
sudo_user: "{{ rbenv_user }}"
gem: name={{ item }} executable=.rbenv/shims/gem user_install=False
with_items:
- rails
- bundler

- name: Install javascript tools
npm: name={{ item }} state=latest global=yes
with_items:
- bower
- grunt-cli



Vagrant と Ansible のファイル

今回、roles の位置を ansible 配下に移動したので、ansible.cfg でパスを変更しています。


ansible.cfg

[defaults]

roles_path = ./ansible/roles/

playbook は単純です。各ロールを呼んでいるだけです。


develop.yml

---

- name: Build a Rails development environment
hosts: all
sudo: yes
sudo_user: root

roles:
- apt-upgrade
- rbenv
- mysql
- nodejs
- env


Vagrant ファイルです。

MySQL5.6 の起動時のエラー回避のためにメモリを 1G(vb.memory = "1024")にしています。

その他は特に変わった設定はしていません。

2015.07.12 開発をしていると MySQL のプロセスが落ちることがわかりました。メモリを2G(vb.memory = "2048")へ、さらに変更することで安定して開発を行えています。

2015.07.25 仮想環境の時刻を HOST に合わせる設定を追加しました。


Vagrantfile

# -*- mode: ruby -*-

# vi: set ft=ruby :

Vagrant.configure(2) do |config|

config.vm.box = "ubuntu/trusty64"

config.vm.network "forwarded_port", guest: 3000, host: 3000
config.vm.network "private_network", ip: "192.168.33.20"

config.vm.synced_folder "../", "/home/vagrant/projects", type: "nfs"

config.vm.provider "virtualbox" do |vb|
# Customize the amount of memory on the VM:
vb.memory = "2048"
# Set the time to HOST
vb.customize ["setextradata", :id, "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled", 0]
end

config.vm.provision "ansible" do |ansible|
ansible.playbook = "develop.yml"
end
end



実行方法

VirtualBox, Vagrant, Ansible をインストールして、以下のコマンドを入力すれば、開発環境を構築できます。

$ git clone https://github.com/katsuhiko/template-rails-ansible.git

$ cd template-rails-ansible
$ vagrant up


感想

Ansible Galaxy で調べて参考しながら、作っていくことに慣れてきました。

今回は、rbenv のインストールが一番勉強になりました。

全体的に変数化しなかったので、各 role は使い回しができなくなっています。

これをベースとして、作り込み、使い回しができるようにしていきたいです。

Mac で動作を試しました。Windows で動作するかを試せていません。

Windows でも動かしたい場合、Windows に Ansible をインストールするより、Ansible を仮想環境上で実行するほうが、ハードルは低いかもしれません。

Ansible は関係ないですが、Windows のファイル共有問題については、

http://tech.respect-pal.jp/vagrant-synced_folder-type/

こちらのサイトが役に立ちそうです。