やったこと
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接続の設定
default: &default
adapter: mysql2
encoding: utf8
pool: 5
username: root
password: コンテナ起動時に設定したパスワード
host: mysqld
hostはmysqlコンテナ立ち上げ時に--name
で指定した名前にしておく。
Dockerfile
railsプロジェクトのトップに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プロジェクトのトップに以下のファイルを置く。
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
だけでとりあえず開発環境は立ち上げられる。