DockerでRailsコンテナを構築する

## 概要

Docker上にRailsコンテナを構築する。

```
         Rails Container <- Here
---------------------------------
              Docker
---------------------------------
         Vagrant (CentOS)
---------------------------------
             VirtualBox
---------------------------------
         LocalMachine (OS X)
```

## 関連ページ

* [DockerでMySQL+永続コンテナを構築する](http://qiita.com/naomichi-y/items/3b7dc706d19fa390e9d5)
* [VagrantにCentOS 7.0をインストールする](http://qiita.com/naomichi-y/items/9d776a7f2a9038ba57c2)

## 前提となる環境

* Host
  * OS: Mac OS X
  * VirtualBox 4.2.26
  * Vagrant 4.3.26
* [Guest](http://qiita.com/naomichi-y/items/9d776a7f2a9038ba57c2)
  * OS: CentOS 7.1
  * Docker 1.5.0-dev

* [Container](http://qiita.com/naomichi-y/items/3b7dc706d19fa390e9d5)
  * OS: CentOS 7.1
  * MySQL Container (5.6.23)
  * Data Container

## 目的

* Docker上で使い捨てのRailsコンテナを立ち上げる
* アプリケーションはNFS (ホスト共有ディレクトリ) 領域に配置
  * データは永続コンテナに配置しても良いのだが、ホスト側でソース以外のファイルを編集する可能性を考慮して、ここではNFSを採用した
* DBはMySQL (MySQLコンテナ) を使用
  * データは永続コンテナに配置
* ホストからゲストOSのIPを指定してRailsに接続できるようにする
  * http://10.0.0.10:3000/
* SSHサーバをインストールして、ホストOSからSSH接続を許可する
  * ポートは3022を使用
  * SSH接続には公開鍵認証を用いる (ここでは接続ユーザを"webapp"とする)

## 実行手順

### ビルドファイルの作成

ゲストOS上でRailsコンテナを構築するためのDockefileを作成する。

```
$ mkdir -p ~/containers/rails
$ cd ~/containers/rails
```

```code:~/containers/rails/Dockerfile
FROM centos:latest
MAINTAINER Naomichi Yamakita <n.yamakita@gmail.com>

## システムの更新
RUN yum -y update
RUN yum remove -y vim-minimal

# 一般的な開発ライブラリの構築
RUN yum install -y passwd wget hostname tar make gcc zlib-devel git sudo net-tools ntp vim-enhanced gcc-c++

# MySQL関連のライブラリ
RUN yum install -y libffi-devel.x86_64 readline-devel mysql mysql-devel

# SSH関連のライブラリ
RUN yum install -y openssl-devel openssh-server

## システムの設定
RUN cp -p /usr/share/zoneinfo/Japan /etc/localtime

RUN echo "PATH=\$PATH:/usr/local/bin" >> /root/.bashrc
RUN echo "export PATH" >> /root/.bashrc

## SSHの設定
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -C '' -N ''
RUN sed -ri 's/#RSAAuthentication/RSAAuthentication/g' /etc/ssh/sshd_config
RUN sed -ri 's/#PubkeyAuthentication/PubkeyAuthentication/g' /etc/ssh/sshd_config
RUN sed -ri 's/#PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config
RUN sed -ri 's/#ClientAliveInterval 0/ClientAliveInterval 15/g' /etc/ssh/sshd_config
RUN sed -ri 's/#ClientAliveCountMax 3/ClientAliveCountMax 3/g' /etc/ssh/sshd_config

RUN echo 'root:root'|chpasswd

## "webapp"ユーザの追加
RUN sed -ri 's/Defaults    requiretty/# Defaults    requiretty/g' /etc/sudoers

RUN useradd -m -s /bin/bash webapp

RUN mkdir /home/webapp/.ssh
RUN chmod 700 /home/webapp/.ssh
RUN chown webapp:webapp /home/webapp/.ssh
ADD build/authorized_keys /home/webapp/.ssh/
RUN chmod 600 /home/webapp/.ssh/authorized_keys
RUN chown webapp:webapp /home/webapp/.ssh/authorized_keys

RUN echo 'webapp ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/webapp

RUN echo "LANG=en_US" >> /home/webapp/.bash_profile
RUN echo "export LANG" >> /home/webapp/.bash_profile

# 秘密鍵の登録
ADD build/id_rsa /home/webapp/.ssh/
RUN chown webapp:webapp /home/webapp/.ssh/id_rsa
RUN chmod 400 /home/webapp/.ssh/id_rsa

# Gitの設定
ADD build/.gitconfig /home/webapp/
RUN chown webapp:webapp /home/webapp/.gitconfig

## Vimの設定
RUN mkdir /home/webapp/repos
RUN cd /home/webapp/repos && \
  git clone https://github.com/naomichi-y/vim.git
RUN chown -Rf webapp:webapp /home/webapp/repos

RUN ln -s /home/webapp/repos/vim/source/.vim /home/webapp/.vim
RUN chown -Rf webapp:webapp /home/webapp/.vim

RUN ln -s /home/webapp/repos/vim/source/.vimrc /home/webapp/.vimrc
RUN chown -Rf webapp:webapp /home/webapp/.vimrc

## Rubyのインストール
RUN cd /usr/local/src && \
  wget http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.1.tar.gz && \
  tar zxvf ruby-2.2.1.tar.gz && \
  cd ruby-2.2.1 && \
  ./configure --disable-install-doc && \
  make && \
  make install
RUN echo 'gem: --no-document' > /usr/local/etc/gemrc
RUN yum install -y patch
RUN gem update --system

## Bundlerのインストール
RUN gem install bundler

## SSH、Railsの起動
EXPOSE 22 3000

ADD build/start_server /usr/bin/
RUN chmod +x /usr/bin/start_server

CMD ["/usr/bin/start_server"]
```
* GitやVimの設定を変更しているが、これらは各々の環境に合わせて変更すれば良い。
* 便宜上、SSHには公開鍵認証を用いているが、開発環境であればパスワード認証でも良いと思う。

Vagrantfileで参照しているファイルは次の通り。

```code:~/containers/rails/build/.gitconfig
[user]
    name = naomichi-y
    email = n.yamakita@gmail.com
[mergetool]
    keepBackup = true
[core]
    editor = /usr/bin/vim
    quotepath = false
[http]
    sslVerify = false
```

```code:~/containers/rails/build/authorized_keys
# SSHの公開鍵ファイル。ホストOSから接続するために必要。
***
```

```code:~/containers/rails/build/id_rsa
# SSHの秘密鍵ファイル。コンテナからGitにファイルをコミットする際に使用
***
```

```code:~/containers/rails/build/start_server
#!/bin/bash

## start rails
cd /var/www
bundle exec rails server -b 0.0.0.0 -d

## start sshd
/usr/sbin/sshd -D
***
```

### ビルド

続いてDockerfileをビルドする。環境にもよるが、数十分の時間を要する。

```
$ docker build -t rails .
```

ビルドが完了したらコンテナを立ち上げる。

```
# -h コンテナのホスト名
# -v: ゲストOS (ホストOS) のNFS領域をコンテナへマウント
# --link: MySQLコンテナに接続できるようにする

$ docker run \
-h rails-local \
-p 3022:22 \
-p 3000:3000 \
--name rails \
-d \
-v /home/vagrant/Projects:/var/www \
--volumes-from=storage \
--link mysql:mysql \
rails
```

Dockerのプロセス一覧にrailsの名前が表示されているか確認。

```
[vagrant@localhost rails]$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                                          NAMES
9bc54058a045        rails:latest        "/usr/bin/start_serv   6 seconds ago       Up 4 seconds        0.0.0.0:3000->3000/tcp, 0.0.0.0:3022->22/tcp   rails
6c43ca8325be        mysql:latest        "/usr/local/bin/star   2 days ago          Up 36 hours         0.0.0.0:3306->3306/tcp                         mysql
```

続いてホストOSからRailsコンテナにSSH接続できることを確認する。

```
$ ssh -i ~/.ssh/id_rsa -p 3022 webapp@10.0.0.10
The authenticity of host '[10.0.0.10]:3022 ([10.0.0.10]:3022)' can't be established.
RSA key fingerprint is ***
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[10.0.0.10]:3022' (RSA) to the list of known hosts.
Last login: Thu Apr  9 23:59:33 2015 from 10.0.2.2
$
```

### プロジェクトの作成

`/var/www`は共有ディレクトリのため、この下にアプリケーションを作成する。

```
$ cd /var/www
$ rails new hello -d mysql
$ sudo mkdir /opt/rails
$ sudo chown webapp:webapp /opt/rails
$ bundle install --path=/opt/rails/vendor/bundle
...
Bundled gems are installed into /opt/rails/vendor/bundle.
```

ここではライブラリのインストール先をデータコンテナに設定した。理由は2点ある。

* アプリケーションディレクトリ (NFS領域) にパッケージインストールしようとすると何故かエラーが出て失敗した (URLを失念したが、他のサイトでも同現象が報告されていた)。
* コンテナという特性上、Gemはシステム領域にインストールでも良いのだが、開発中はライブラリの入れ替えが多く、その度にビルドするのが面倒。

最後にRailsを起動する。

```
bundle exec rails server -b 0.0.0.0
```

http://10.0.0.10:3000/ にアクセスできることを確認する。

### 自動起動の設定

`vagrant up`時にRailsを起動したいのであれば、[MySQLコンテナ](http://qiita.com/naomichi-y/items/3b7dc706d19fa390e9d5#%E8%87%AA%E5%8B%95%E8%B5%B7%E5%8B%95%E3%81%AE%E8%A8%AD%E5%AE%9A) 同様にプロビジョニングファイルの設定を追加する。

```code:provision/always.sh
#!/usr/bin/bash

echo "start containers"
docker start mysql
docker start rails
```

`vagrand reload`でrailsが起動していることを確認する。

```
$ vagrant reload
...
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.
==> default: Running provisioner: shell...
    default: Running: /var/folders/nm/m391v5jn1wsc1hpltn2gq3r40000gn/T/vagrant-shell20150405-2988-1du2a2q.sh
==> default: start containers
==> default: mysql
==> default: rails
...

$ vagrant ssh

# プロセスが動作しているか確認
$ ps ax|grep rails
ps ax|grep rai[vagrant@localhost ~]$ ps ax|grep rails
 5756 pts/0    S+     0:00 vim rails/Dockerfile
22328 pts/2    S+     0:00 grep --color=auto rails```
```