Ruby on Railsアプリが動くApache Passenger Postgresql環境をdockerでつくる


# Dockerの基本

何となくは知っていて、難しいことはちょっとという人は、以下などで実際に手を動かしてみるといいと思う（自分もよくわかってない）。

[Docker 〜WordPress環境を作ってみる　ハンズオン編〜](http://www.slideshare.net/cyberblackvoom?utm_campaign=profiletracking&utm_medium=sssite&utm_source=ssslideview)

# Dockerを動かす環境

WindowsやMacの場合、VM環境を用意するのが一番簡単。
以下は、VirtualBoxにCentOS7環境を用意する簡単な手順。

## VirtualBoxのインストール

[VirtualBoxダウンロード](https://www.virtualbox.org/wiki/Downloads)から、VirtualBoxをダウンロードしてインストール

## CentOS7イメージをダウンロード

[CentOS7イメージダウンロード](http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1503-01.iso)から、isoイメージをダウンロード

## VirtualBoxでCentOS7イメージから仮想マシンを起動

1. VirtualBox => 新規 => 作成
※名前をCentOS7とかにするとタイプが自動で選択される

2. VirtualBox => 起動 => CentOS7のisoイメージを指定
3. !マークがついている部分をデフォルトで設定
4. 「ネットワークとホスト名」をONにする
5. VirtualBox => 設定 => ネットワーク => ポートフォワーディング

	| 名前 | ホストポート | ゲストポート |
	| --- | --- | --- |
	| ssh | 2222 | 22 |
	| http | 8000 | 80 |

6. sshでアクセス
`ssh -l root -p 2222 localhost`

# Dockerをインストール

CentOS7の仮想マシン上で、以下を実行

```bash
yum -y install docker
systemctl enable docker.service
systemctl start docker.service
```

# Dockerfileをつくる

## OS

CentOS7になると、そのままではsystemctlがうまくDockerfileから設定できないので、簡単なCentOS6を入れる。

```Dockerfile
From centos:centos6
MAINTAINER [YOURNAME]

# create user

RUN yum -y install passwd
RUN useradd [USERNAME]
RUN passwd -f -u [USERNAME]

```

## PostgreSQL


* `RUN sed -i -e "s/#bytea_output = 'hex'/bytea_output = 'escape'/g" /var/lib/pgsql/9.3/data/postgresql.conf`部分は[string contains null byteへの対応](http://tkm9.hateblo.jp/entry/2015/02/17/210353)なので、不要なら消す。
* `RUN sed -i -e "s/local   all             all                                     peer/local   all             all                                     md5/g" /var/lib/pgsql/9.3/data/pg_hba.conf`は先に実行すると、createdb.shが動かなかったので（原因未調査）、しかたなく最後にしている。


```Dockerfile
# postgres

RUN rpm -i http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-redhat93-9.3-1.noarch.rpm
RUN yum -y install postgresql93-server  postgresql93-devel postgresql93-docs postgresql93-libs; yum clean all

RUN chkconfig postgresql-9.3 on
RUN service postgresql-9.3 initdb
RUN echo "host    all             all             0.0.0.0/0               md5" >> /var/lib/pgsql/9.3/data/pg_hba.conf
RUN sed -i -e "s/#bytea_output = 'hex'/bytea_output = 'escape'/g" /var/lib/pgsql/9.3/data/postgresql.conf
RUN service postgresql-9.3 start
ADD createdb.sh /createdb.sh
RUN chmod +x /createdb.sh
RUN /createdb.sh
RUN sed -i -e "s/local   all             all                                     peer/local   all             all                                     md5/g" /var/lib/pgsql/9.3/data/pg_hba.conf
RUN service postgresql-9.3 start

EXPOSE 5432
```

* create.sh
* `[USERNAME]`と`[PASSWORD]`は書き換え
* こういった細かい一連の処理はシェルにしてADD & RUNするのがよいらしい

```create.sh
#!/bin/bash

__mod_user() {
usermod -G wheel postgres
}

__create_db() {
su --login postgres --command "/usr/pgsql-9.3/bin/postgres -D /var/lib/pgsql/9.3/data -p 5432" &
sleep 10
ps aux

su --login - postgres --command "psql -c \"CREATE USER [USERNAME] with CREATEROLE superuser PASSWORD '[PASSWORD]';\""
su --login - postgres --command "psql -c \"CREATE DATABASE [USERNAME] OWNER [USERNAME];\""
su --login - postgres --command "psql -c \"\du;\""
}

# Call functions
__mod_user
__create_db
```

## Apache

```Dockerfile
# httpd

RUN yum -y update && yum clean all
RUN yum -y install httpd && yum clean all

RUN chkconfig httpd on
RUN service httpd start

EXPOSE 80
```

## rbenv & ruby

* [ruby](https://gist.github.com/deepak/5925003)を参考にしている

```Dockerfile
# install rbenv

RUN yum -y install git make tar
# https://github.com/sstephenson/ruby-build/wiki#suggested-build-environment
RUN yum -y install gcc openssl-devel libyaml-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel

RUN git clone https://github.com/sstephenson/rbenv.git /usr/local/rbenv
RUN echo '# rbenv setup' > /etc/profile.d/rbenv.sh
RUN echo 'export RBENV_ROOT=/usr/local/rbenv' >> /etc/profile.d/rbenv.sh
RUN echo 'export PATH="$RBENV_ROOT/bin:$PATH"' >> /etc/profile.d/rbenv.sh
RUN echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh
RUN chmod +x /etc/profile.d/rbenv.sh

# install ruby-build

RUN mkdir /usr/local/rbenv/plugins
RUN git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build
ENV RBENV_ROOT /usr/local/rbenv
ENV PATH "$RBENV_ROOT/bin:$RBENV_ROOT/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# does not work. PATH is set to
# $RBENV_ROOT/shims:$RBENV_ROOT/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# install ruby

RUN rbenv --version
RUN rbenv install 2.2.0
RUN rbenv global 2.2.0
RUN ruby -v
RUN rbenv rehash
```

## Passenger

```Dockerfile
# passenger

RUN gem install passenger --no-ri --no-rdoc -V
RUN yum -y install libcurl-devel httpd-devel gcc-c++
RUN exit
RUN passenger-install-apache2-module
```

## httpd.confの設定

* あらかじめつくっておいたhttpd.confをAdd & RUNしてもいいかもしれない
* passenger_moduleのディレクトリはrubyのバージョンによって変わるので注意
* `[USERNAME]`、`[YOUR_RAILS_APP_NAME]`、`[ENVNAME]`は書き換え

```Dockerfile
# set httpd.conf

RUN sed -i -e 's/DocumentRoot "\/var\/www\/html"/DocumentRoot "\/home\/[USERNAME]\/[YOUR_RAILS_APP_NAME]\/public"/g' /etc/httpd/conf/httpd.conf
RUN echo '<Directory "/home/[USERNAME]/[YOUR_RAILS_APP_NAME]/public">' >> /etc/httpd/conf/httpd.conf
RUN echo 'Options -Indexes FollowSymLinks' >> /etc/httpd/conf/httpd.conf
RUN echo 'AllowOverride All' >> /etc/httpd/conf/httpd.conf
RUN echo '</Directory>' >> /etc/httpd/conf/httpd.conf

RUN cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
RUN sed -i -e "s/AddDefaultCharset UTF-8/# AddDefaultCharset UTF-8/g" /etc/httpd/conf/httpd.conf
RUN echo 'LoadModule passenger_module /usr/local/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/passenger-5.0.21/buildout/apache2/mod_passenger.so' >> /etc/httpd/conf/httpd.conf
RUN echo '<IfModule mod_passenger.c>' >> /etc/httpd/conf/httpd.conf
RUN echo '  PassengerRoot /usr/local/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/passenger-5.0.21' >> /etc/httpd/conf/httpd.conf
RUN echo '  PassengerDefaultRuby /usr/local/rbenv/shims/ruby' >> /etc/httpd/conf/httpd.conf
RUN echo '</IfModule>' >> /etc/httpd/conf/httpd.conf
RUN echo 'RailsEnv [ENVNAME]' >> /etc/httpd/conf/httpd.conf
```

## RAILSアプリをclone

* `[USERNAME]`、`[YOUR_RAILS_APP_NAME]`、`[ENVNAME]`は書き換え

```Dockerfile
# install [YOUR_RAILS_APP_NAME]

RUN yum -y install libxml2-devel libxslt-devel libpq-dev postgresql-devel sqlite-devel
RUN git clone [YOUR_RAILS_APP_GITHUB_URL] /home/[USERNAME]/[YOUR_RAILS_APP_NAME]
RUN chown -R [USERNAME] /home/[USERNAME]/[YOUR_RAILS_APP_NAME]
RUN chmod +x /home/[USERNAME]
RUN gem install bundler

ADD ./run.sh /home/[USERNAME]/run.sh
RUN chmod -v +x /home/[USERNAME]/run.sh
RUN chown pr /home/[USERNAME]/run.sh
```

```run.sh
#!/bin/bash

cd /home/[USERNAME]/[YOUR_RAILS_APP_NAME]
# http://ayumu-homes.hateblo.jp/entry/2015/02/08/174838
gem install nokogiri -- --use-system-libraries=true --with-xml2-include=/usr/include/libxml2/
bundle install --without test development
bundle update
bundle exec rake db:migrate RAILS_ENV=[ENVNAME]
bundle exec rake db:seed RAILS_ENV=[ENVNAME]
```

## postgresqlとapacheのサービス起動

```Dockerfile
#start service script
RUN echo -e "service postgresql-9.3 start\nservice httpd start\n/bin/bash" > /start_service.sh
RUN chmod o+x /start_service.sh

CMD ["/start_service.sh"]
```

# Dockerfileのビルド

```
docker build -t [YOURNAME]/[YOUR_APP_NAME] ~/[DOCKERFILE_DIRECTORY]
```

# Dockerコンテナの起動

* `docker exec -it [YOUR_APP_NAME] /home/[USERNAME]/run.sh`はDockerfileで動かすとうまくいかなかった（原因不明）ので、ここで実行している
* `[YOURNAME]`、`[YOUR_APP_NAME]`、`[DOCKERFILE_DIRECTORY]`、`[USERNAME]`は書き換え

```
docker build -t [YOURNAME]/[YOUR_APP_NAME] [DOCKERFILE_DIRECTORY]
docker run --privileged -d -p 80:80 --name [YOUR_APP_NAME] [YOURNAME]/[YOUR_APP_NAME] /sbin/init
docker exec -it [YOUR_APP_NAME] /home/[USERNAME]/run.sh
```

# アクセス

ブラウザーからアクセス

```
http://localhost:8000
```

# Dockerコンテナイメージのcommit & push

* 事前に[Docker Hub](https://hub.docker.com/)のアカウントを作成する
* `[YOUR_APP_NAME]`、`[DOCKER_HUB_ACCOUNT_NAME]`は書き換え

```
docker commit [YOUR_APP_NAME] [DOCKER_HUB_ACCOUNT_NAME]/[YOUR_APP_NAME]
docker login
docker push [DOCKER_HUB_ACCOUNT_NAME]/[YOUR_APP_NAME]

```


# Dcokerコンテナの停止と削除

```
docker stop [YOUR_APP_NAME]
docker rm `docker ps -a -q`
docker rmi $(docker images | awk '/^<none>/ { print $3 }')
```

# Dockerコンテナイメージのpull

* `[YOUR_APP_NAME]`、`[DOCKER_HUB_ACCOUNT_NAME]`は書き換え

```
docker pull -a [DOCKER_HUB_ACCOUNT_NAME]/[YOUR_APP_NAME]
docker run --privileged -d -p 80:80 --name [YOUR_APP_NAME] [YOURNAME]/[YOUR_APP_NAME] /sbin/init
```

# サンプル

https://github.com/itagakishintaro/ProgressReport