Dockerを使って古いRails+MySQLを塩漬けした話

7年前に書いたRuby 1.8 + Rails 1.2.6 + MySQL 5.0のアプリがあり、ほとんど使ってないけど、たま～に使うので、扱いに困っていました。

そこで、今動いているミドルウェアのバージョンをそのままにDockerでコンテナ化して、どんな環境にも移動できるようにしました。これでどこでも昔のバージョンのまま動き続けることができる、いわるゆ**塩漬け**です！

それを紹介します。

## Dockerの実行環境

* CentOS Linux release 7.1.1503
* Docker version 1.10.3, build 3999ccb-unsupported

## 塩漬け対象アプリの構成

* ミドル
  * Ruby1.8.7
  * Ruby on Rails 1.2.6
  * MySQL 5.0.77
* アプリ
  * bitbucketにあるレポジトリを/usr/local/myappにcloneして動作させる
* データ
  * MySQLにあるデータベースの中のテーブル一式

## DBのコンテナ化

### Dockerfileの準備

MySQLの公式には5.0のイメージはなかったため、[lsdriscollさん](https://hub.docker.com/r/lsdriscoll/mysql-server-5.0/)を参考にしつつ[公式のCentOS 5.11](https://hub.docker.com/_/centos/)のイメージをベースに自分で作ることにしました。

ファイル構成

```
 └ myapp-db
     ├ Dockerfile
     ├ initial.sql
     └ my.cnf
```

Dockerfileの内容

```
FROM centos:5.11
MAINTAINER fetaro@xxx.com
RUN yum -y install mysql-server-5.0.95-5.el5_9
COPY my.cnf /etc/my.cnf
COPY initial.sql /initial.sql
RUN  mysql_install_db --datadir=/var/lib/mysql --user=mysql
USER root
CMD ["mysqld_safe", "--init-file=/initial.sql", "--user=mysql"]
```

initial.sqlの内容

```
GRANT ALL PRIVILEGES ON *.* to root@'localhost' IDENTIFIED BY 'xxxx' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON myapp_production.* to myapp@'%' IDENTIFIED BY 'xxx';
GRANT ALL PRIVILEGES ON myapp_production.* to myapp@'localhost' IDENTIFIED BY 'xxx';
FLUSH PRIVILEGES;
CREATE DATABASE IF NOT EXISTS myapp_production DEFAULT CHARACTER SET utf8;
（以降テーブルの作成など）
```

my.cnfの内容

```
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
old_passwords=0

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
port=3306
```

### イメージのビルド

Dockerfileのあるディレクトリで

```
docker build -t fetaro/myapp-db .
```

-t はイメージの名前指定。「DockerHubのユーザ名/」を頭につけるのが作法っぽいです。

確認

```
docker images

REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
fetaro/myapp-db             latest              2af6e1f44b8c        32 minutes ago      381.3 MB
docker.io/centos              5.11                b424fba01172        4 months ago        284.1 MB
```

ベースになっているcentosと自分で作ったmyapp-dbが見えます。

### コンテナの生成&起動

```
docker run --name myapp-db  -d  fetaro/myapp-db
```

確認

```
# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
767b41356fa6        fetaro/myapp-db    "mysqld_safe --init-f"   33 minutes ago      Up 33 minutes                                myapp-db
```

このMySQLはポート指定していないため、外部からはアクセスできません。
しかし、Dockerのリンク機能を使って、次に作るWebアプリコンテナとリンクを結び、Docker内部で通信するようにするため問題ありません。

## Webアプリのコンテナ化

### Dockerfileの準備

ruby 1.8.7が動くベースイメージを[Docker Hub](https://hub.docker.com/)から探し、[docker.io/nvulane/ruby1.8.7](https://hub.docker.com/r/nvulane/ruby1.8.7/)を採用することにしました。

ファイル構成

```
 └ myapp-web
     └ Dockerfile
```

Dockerfileの内容

```
FROM docker.io/nvulane/ruby1.8.7
MAINTAINER fetaro@xxxx.com
WORKDIR /usr/local/
RUN apt-get install -y
RUN gem install rake  -v 0.8.7 --no-ri --no-rdoc
RUN gem install rails -v 1.2.6 --no-ri --no-rdoc

# アプリをbitbucketから取得して/usr/local/myappに展開(一行で書くのが作法)
RUN wget --no-check-certificate https://fetaro:xxxxxx@bitbucket.org/fetaro/myapp/get/master.zip \
  && unzip master.zip -d tmp \
  && mv tmp/* myapp \
  && rm -f master.zip

# 起動する時にプロジェクトホームにいる必要があるので移動
WORKDIR /usr/local/myapp/
CMD ["ruby", "script/server", "-e", "production"]

EXPOSE 3000
```

ポイントとして、Dockerは１コマンドごとにファイルシステムの差分を管理していくので、まとめて作業する場合はRUNを何行も書くのではなく１行で書くのが作法とのこと。そのためgitからアプリ取得して展開するところは1行で書いています。

### イメージのビルド

Dockerfileのあるディレクトリで

```
docker build -t fetaro/myapp-web .
```

-tはイメージに名前を付けている。

確認

```
docker images

REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
fetaro/myapp-db             latest              2af6e1f44b8c        37 minutes ago      381.3 MB
fetaro/myapp-web            latest              abc6e670ee65        About an hour ago   488.9 MB
docker.io/centos              5.11                b424fba01172        4 months ago        284.1 MB
docker.io/nvulane/ruby1.8.7   latest              b9b3d6f40baf        5 months ago        451.8 MB
```

新たにruby1.8.7のイメージとmyapp-webのイメージができていることがわかる。

### コンテナの作成＆起動

```
docker run --name myapp-web -d -p 3000:3000 -t --link myapp-db:myapp-db fetaro/myapp-web
```

ポイントは--linkにてmyapp-dbコンテナとリンクしているところ。これによりmyapp-webコンテナの`/etc/hosts`に myapp-dbのエントリが追加され、アプリからは`myapp-db`というホスト名で接続できます。

確認

```
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
6c40992e1373        fetaro/myapp-web   "ruby script/server -"   36 minutes ago      Up 36 minutes       0.0.0.0:3000->3000/tcp   myapp-web
767b41356fa6        fetaro/myapp-db    "mysqld_safe --init-f"   38 minutes ago      Up 38 minutes                                myapp-db
```

myapp-webとmyapp-dbが起動していることが分かります。

これで完成！ポート3000にアクセスすればアプリが使えます。



## さいごに

この構成では、データの更新はmyapp-dbコンテナの中を直接更新する作りになっているため、コンテナを壊すと更新したデータは消えます。今回は塩漬けアプリでほとんど更新が無いためこの方式を採用していますが、データを外出ししたい場合はdockerのボリュームやデータコンテナを使うほうがよいでしょう。
また、docker compose等を使って二つのコンテナをまとめて管理したほうがよいらしいですが、次回以降のテーマとします。
あと、実行ユーザがかなり適当でrootでwebを動かしているので、これは変えたほうが良いさそうですが、めんどうなのでこのままで。

Docker初心者なので、いろいろ間違っているかもしれません。ツッコミ等があればどしどし下さい m(_ _)m


## 参考にしたドキュメント

[Docker公式ホームページ](https://docs.docker.com/)
[Docker ドキュメント日本語化プロジェクト](http://docs.docker.jp/)
[オライリージャパン出版「Docker」](https://www.amazon.co.jp/Docker-Adrian-Mouat/dp/4873117763)