VirtualBox + Vagrant + CentOS + Ansible + Docker + Railsで1コマンド起動開発環境構築

なんとなく1コマンドで起動するRails開発環境が欲しくなったので作成

# 目的
- VirtualBoxとVagrantとvagrant-vbguestが設定済みならvagrant upのみで開発環境の構築が完了する所まで自動化
- WindowsでもMacでも同様に動くようにする

# 成果物
[githubに公開しています](https://github.com/toshi-click/rails_local_develop)  
ちょいちょい不要だろと思うところを削ってるのでこちらと見比べ推奨

# バージョン情報
- VirtualBox バージョン 5.1.22 r115126 (Qt5.6.2)
- Vagrant 1.9.3
- vagrant-vbguest 0.13.0
- CentOS Linux release 7.3.1611 (Core)
- Ansible 2.3.0.0-3.el7
- ruby 2.4.1
- Rails 5.0.2

# 事前準備
Vagrant、VirtualBox 、vagrant-vbguestはそれぞれインストールしてください。
- [Vagrant](https://www.vagrantup.com/downloads.html)
- [VirtualBox ](https://www.virtualbox.org/)

###### Vagrantインストール後にコマンドプロンプト(Windows) or ターミナル(OSX)で下記コマンド実行して下さい。
```
vagrant plugin install vagrant-vbguest
```

# Vagrantfile の編集
```ruby:.Vagrantfile
# 環境構築に必要なコマンド。初回・reload時に実行される
$setup = <<SCRIPT
# 必要なパッケージの導入
yum -y groupinstall "Development Tools"
# epel導入 
yum install -y epel-release
yum clean metadata && yum upgrade ca-certificates --disablerepo=epel
yum install -y ansible sshpass

# インベントリのサーバへの実行時に鍵のyes/noを確認しないように
mkdir /root/.ssh && touch /root/config
echo "Host 192.168.*.* \n StrictHostKeyChecking no \n UserKnownHostsFile=/dev/null" >> /root/.ssh/config

# 遅いPCでやった際にIPが付かない問題が発生する。その場合のための対応
nmcli connection reload
systemctl restart network.service

# ansibleプレイブックの実行
ansible-playbook \
    -i /app/ansible/app/playbook/hosts/dev \
    /app/ansible/app/playbook/site.yml

# railsの最初に必要。railsのファイルをもうプロジェクト内に用意してある場合は不要
#cd /app ; /usr/local/bin/docker-compose build
#docker exec -i rails_web bash -c 'rails new . --force --database=postgresql'

# DBコンテナが用意できるであろう時間待機させる。ここでエラーが出てしまう場合は時間延長
sleep 1m
docker exec -i rails_web bash -c 'rake db:create'
SCRIPT

# VM再起動時にコマンド実行する場合はここに書く
$start = <<SCRIPT
# 遅いPCでやった際にIPが付かない問題が発生する。その場合のための対応
nmcli connection reload
systemctl restart network.service

# ansibleプレイブックの実行
ansible-playbook \
    -i /app/ansible/app/playbook/hosts/dev \
    /app/ansible/app/playbook/site.yml
SCRIPT

# Vagrant バージョン2を指定
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure("2") do |config|
  # 公式のCentOS7で作る
  config.vm.box = "centos/7"
  # 共有フォルダの設定 /vagrantは入れておかないとWindowsでエラー
  config.vm.synced_folder ".", "/vagrant", type: "virtualbox"
  config.vm.synced_folder ".", "/app", type: "virtualbox"

  config.ssh.guest_port = 22
  # 構築に必要なリソース
  # VirtualboxのGUI上で見える名前など設定
  config.vm.provider "virtualbox" do |v|
    v.memory = 2048
    v.cpus = 2
    v.name = "rails"
  end

  # プライベートネットワーク
  config.vm.network "private_network", ip: "192.168.250.250"

  # VM初回作成時に実行するべきコマンド実行
  config.vm.provision "shell", inline: $setup

  # VM起動時にコマンド実行
  config.vm.provision "shell", run: "always", inline: $start
end
```

# Ansibleの準備
## 説明面倒になったのでgithub見て下さい
.ansible 以下にansibleのレシピ等全部入ってますのでプロジェクトルートにコピーでもして下さい。

# Railsの準備
## Gemfileの作成。railsだけ記述
```ruby:.Gemfile
source 'https://rubygems.org'
gem 'rails', '5.0.2'
```
## Gemfile.lockの作成
```ruby:.Gemfile.lock
# 空でいいのでファイルだけ作成しておく
```

# Dockerの準備
## 基本は下記のQuickStartをベースに作成
- [https://docs.docker.com/compose/rails/](https://docs.docker.com/compose/rails/)  

#### jwilder/nginx-proxyをそのまま使用してもいいですが、後で設定足したくなるかもしれないからDockerfile作っておいたほうが楽です
```ruby:.docker/proxy/Dockerfile
# https://github.com/jwilder/nginx-proxy
FROM jwilder/nginx-proxy
RUN { \
      echo 'server_tokens off;'; \
      echo 'client_max_body_size 100m;'; \
    } > /etc/nginx/conf.d/my_proxy.conf

```
#### proxyの設定。docker-compose.ymlは分けておいたほうがあとあと楽です。
```yaml:.docker/proxy/docker-compose.yml
# docker-composeバージョンの宣言
version: '2'
services:
   nginx-proxy:
    build: .
    container_name: nginx-proxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/nginx/htpasswd
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
    restart: always

# ネットワークの記述
# ネットワークの事前作成が必要
# docker network create --driver bridge nginx_proxy
networks:
  default:
    external:
      name: nginx_proxy
```


## rails用のDockerの設定
```ruby:.Dockerfile
FROM ruby:2.4.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs postgresql-client
RUN mkdir /app
WORKDIR /app
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN bundle install
ADD . /app
```

```yaml:.docker-compose.yml
# docker-composeバージョンの宣言
version: '2'
services:
  db:
    image: postgresql:9.6.1
    container_name: rails_db
    volumes:
      - data:/var/lib/postgresql/data

  web:
    build: .
    container_name: rails_web
    command: bundle exec rails s -p 80 -b '0.0.0.0'
    environment:
      VIRTUAL_HOST: rails.dev
    volumes:
      - .:/app
    ports:
      - "80"
    depends_on:
      - db

volumes:
  data:
    driver: local

# ネットワークの記述
# ネットワークの事前作成が必要
# docker network create --driver bridge nginx_proxy
networks:
  default:
    external:
      name: nginx_proxy
```

# 仮想マシンの起動
```
# Windowsはコマンドプロンプト(管理者権限はNG)で実施です。
vagrant up
```
## レシピ実行には時間が結構掛かるのでまったり待って下さい。

## Vagrantで上げたVMにアクセスするには
```
# windowsはsshクライアントをコマンドプロンプトに追加していない場合は接続情報が表示されるのでsshクライアントでアクセスしてください
vagrant ssh

# VMに入れてrootユーザになりたい場合(vagrantユーザにはsudo no passwordついてます)
sudo su -
```

## ブラウザからアクセス出来るようにWindows・OSXのhostsに設定を追加する
```
# ruby on rails ローカル開発環境
192.168.250.250 rails.dev
```

## Vagrantで上げたVMをシャットダウンする場合に実行
```
# このファイルが存在するディレクトリまでcdした後で実施すること
# Windowsはコマンドプロンプト(管理者権限はNG)で実施です。
vagrant halt
```