Rails
docker

rails開発環境をdockerで作ったメモ

More than 3 years have passed since last update.

やったこと

railsの開発環境をDockerで立ち上げてみた。

プロジェクトを作る

$ rails new -J --skip-bundle -T -d mysql rails_app

mysqlの起動

mysqlのコンテナを立ち上げておく。
使うのはdocker公式イメージ。
docker-composeとか使うのはとりあえず後。

$ docker run -d -p 3306:3306 --name mysqld -e MYSQL_ROOT_PASSWORD=ルートパスワード mysql

data containerを使うのも後。

db接続の設定

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: コンテナ起動時に設定したパスワード
  host: mysqld

hostはmysqlコンテナ立ち上げ時に--nameで指定した名前にしておく。

Dockerfile

railsプロジェクトのトップにDockerfileを置く。

Dockerfile
FROM 2.1.5:onbuild

CMD ["bin/rails", "s"]

これだけ。使いたいversion名にする。CMDにはサーバ起動の命令を書いておく。

bundle install

build時にGemfile.lockが必須となるので、bundle install

build

$ docker build -t rails_app .

dbの作成

$ docker run --rm --link mysqld:mysqld rails_app bin/rake db:create

db:createだけすれば良いので、--rmで終了後にコンテナを自動で削除する。

--linkで、rails_appコンテナ内からホスト名mysqldでmysqlコンテナにアクセスできるように設定。

起動

$ docker run -d --name rails_app --link mysqld:mysqld -p 8080:3000 rails_app

これで、http://192.168.59.103:8080/ にアクセスするととりあえずwelcomeの画面は開ける。IPは、boot2docker ipで出力される値。

ホスト上のソースファイルをマウント

ただし、これだとホスト上でファイルを編集しても、docker imageをリビルドしない限りコンテナ上のアプリに反映されない。これでは開発はままならないので、ホスト上のrailsディレクトリをコンテナにマウントする。

$ docker run -v "$PWD":/usr/src/app --link mysqld:mysqld -p 8080:3000 rails_app

-vオプションで、アプリのコードがあるカレントをコンテナ上のアプリのディレクトリにマウント。

/usr/src/appは、ベースに使っているイメージ2.1.5:onbuildのDockerfileに記載されている、コードのデプロイ先。

scaffold

とりあえずscaffoldで適当なモデルを作り、ホスト上のコードに変更を加える。migrationも合わせてやっちゃう。

$ bin/rails g scaffold item name:string price:integer description:text
$ docker run --rm -v "$PWD":/usr/src/app --link mysqld:mysqld rails_app bin/rake db:migrate

http://192.168.59.103:8080/items にアクセスすると、Item一覧のページが見れるはず。リビルドなしでホスト上の変更が反映できたことがわかる。

データの永続化

アプリは起動したが、mysqlコンテナが消えるとデータも消えてしまうので、data container patternに従ってmysqlコンテナとデータコンテナを分ける。

$ docker create --name mysql_data -v /var/lib/mysql busybox
$ docker run -d -p 3306:3306 --name mysqld --volumes-from mysql_data -e MYSQL_ROOT_PASSWORD=password mysql
$ docker run --rm -v "$PWD":/usr/src/app --link mysqld:mysqld rails_app bin/rake db:create
mysql> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| mysql                 |
| performance_schema    |
| rails_app_development |
| rails_app_test        |
+-----------------------+
5 rows in set (0.00 sec)

ここで再びmysqlコンテナを再度立ち上げてみる。

$ docker stop mysqld
$ docker rm mysqld
$ docker run -d -p 3306:3306 --name mysqld --volumes-from mysql_data -e MYSQL_ROOT_PASSWORD=password mysql
mysql> show databases;
+-----------------------+
| Database              |
+-----------------------+
| information_schema    |
| mysql                 |
| performance_schema    |
| rails_app_development |
| rails_app_test        |
+-----------------------+
5 rows in set (0.00 sec)

コンテナを再度立ち上げているが、data自体は永続化されたままである。

docker-composeの出番です

ここまで来るといろいろとオプションとか面倒なので、docker-composeを使いたくなる。そこで、railsプロジェクトのトップに以下のファイルを置く。

docker-compose.yml
mysqldata:
  image: busybox
  volumes:
   - /var/lib/mysql
mysqld:
  image: mysql
  volumes_from:
   - mysqldata
  ports:
   - 3306:3306
  environment:
    MYSQL_ROOT_PASSWORD: password
app:
  build: ./
  ports:
   - 8080:3000
  links:
   - mysqld:mysqld
  volumes:
   - $PWD:/usr/src/app

docker-compose up -dで諸々全てが立ち上がる。データコンテナを作り直しているので、
docker-compose runを使ってdbをセットアップ。このコマンドは、

Runs a one-off command on a service.

とマニュアルに書いてあるので、docker-compose.ymlで定義した各service(ymlの第一階層に定義したmysqldとかappなどをserviceと呼ぶ)に対して特定コマンドを実行したいときに使うのだろう。

$ docker-compose run app bin/rake db:create
$ docker-compose run app bin/rake db:migrate

以降、docker-compose upをしても、volumes-fromで指定されたボリュームは保存されるので、mysqlのデータは永続化される。

ymlにMYSQLのパスワードを書いてしまっているのがいけてないなとは思う。が、docker-compose help upを見る限り、起動時に指定できそうな感じはしなかった。

まとめ

dockerを使って、rails+mysqlの開発環境を作ってみた。サンプルプロジェクトは、こちら。
https://github.com/hokuma/docker_rails_sample

これで、

$ git clone xxx
$ docker-compose up -d

だけでとりあえず開発環境は立ち上げられる。