docker-composeで複数のRailsローカル開発環境を作成する

背景

今は一つのRailsローカル開発環境を使って開発を行なっています。ところが、別のRailsアプリケーションの開発を行うことになりました。なので、もう一つのRailsローカル開発環境を作成する必要が出てしまいました…そのときの作成メモを記載します。

ローカル開発環境の構成

既存の開発環境は以下の2つの要素でできています

  • docker-compose
  • docker-sync

それぞれ、なぜ利用するかなど確認してきましょう。

コンテナ間通信

RailsアプリケーションはRailsが動作するアプリケーションコンテナとMySQLが動作するDBコンテナが協調して動作することで成り立ちます。

複数のコンテナを通信させる場合、2つの方法があります。一つは--linkオプションを使う方法、もう一つはdockerネットワークを利用する方法です。

–linkオプションを利用する方法

詳しくはこちらに記載があります。このサイトによると、--linkオプションはレガシー機能で、将来的に削除される可能性があるということです。

dockerネットワークを利用する方法

dockerネットワークを利用する方法もこちらに記載されています。ネットワークを作ることで、コンテナ同士がコンテナ名で通信が行えるようになります。

dockerネットワークの作成を個別で行なってもよいですが、もっと便利な方法があります。docker-composeを利用することです。

docker-compose

docker-composeについてもさくらのページに説明があります。

docker-composeはdocker-compose.ymlというファイルに構成を記載します。YAMLの最初にバージョン番号を記載するのですが、今のバージョンはいくつなんだろうと思って調べてみると、以下のページが見つかりました。

https://docs.docker.com/compose/compose-file/compose-versioning/

マイナーバージョンもあったんですね…知りませんでした。既存で使っているdocker-composeのversionは3です。

docker-sync

ローカル開発環境を構成するもう一つの要素はdocker-syncです。

docker-syncを使う理由

docker-syncを使う理由としては、すでに詳しい記事がいくつかあります

docker-syncでホスト-コンテナ間を爆速で同期する

上記の記事の中に、docker-sync以外の方法も記載されていました

Docker for Mac の Mutagen-based caching で Volume のパフォーマンスが劇的に改善した

現状ですと、docker-sync以外にvolumeのパフォーマンスを改善する方法がないようです。それがdocker-syncを使う理由だと思います。

docker-syncの仕組み

仕組みについても先ほどの記事に記載がありました。

docker-syncの仕組みとしては、 docker の -v で直接ホスト側のディレクトリをマウントするのではなく、rsyncやunisonの仕組みでホスト側のファイルをコンテナ側に転送しよう、というものです。

なるほど、ファイル転送専用のコンテナを準備して同期を取るということですね。

設定に関しては、docker-sync.ymlで行います。

既存のローカル開発環境の設定

既存のアプリケーションの設定ファイルを確認します

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
version: '3'

services:
db:
image: mysql:5.6
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
volumes:
- mysql:/var/lib/mysql
- ./docker/mysql/conf.d:/etc/mysql/conf.d
- ./docker/mysql/init:/docker-entrypoint-initdb.d

web:
build:
context: .
dockerfile: ./docker/rails/Dockerfile
command: ['rails', 's', '-p', '3000', '-b', '0.0.0.0']
ports:
- "3000:3000"
volumes:
- rails-sync-volume:/var/www/html:nocopy
- bundle:/usr/local/bundle
tmpfs:
- /var/www/html/tmp/pids
links:
- db
tty: true
stdin_open: true

volumes:
bundle:
driver: local
mysql:
driver: local
rails-sync-volume:
external: true

docker-sync.yml

1
2
3
4
5
6
7
8
9
10
version: '2'

syncs:
rails-sync-volume:
src: './'
sync_strategy: 'unison'
sync_excludes:
- '.docker-sync'
- '.git'
- '.gitignore'

新しいローカル開発環境の作成

既存設定ファイルのコピー

まずは新しいアプリケーションのルートディレクトリに、docker-compose.ymldocker-sync.ymlをコピーします。

1
2
$ cp app_A/docker-compose.yml app_B/docker-compose.yml
$ cp app_A/docker-sync.yml app_B/docker-sync.yml

docker-sync.ymlの編集

app_Bの方のdocker-sync.ymlを修正します。このままだと名前が被ってしまうので、名前を修正します。

1
2
3
4
5
6
7
8
9
10
version: '2'

syncs:
app_B-sync-volume:
src: './'
sync_strategy: 'unison'
sync_excludes:
- '.docker-sync'
- '.git'
- '.gitignore'

docker-syncの起動

編集したので起動してみます。

1
2
3
4
5
6
$ docker-sync start
ok Starting unison for sync app_B-sync-volume
ok Synced /Users/user/github/app_B/
success Unison server started
ok Synced /Users/user/github/app_B/
success Starting Docker-Sync in the background

コンテナを確認します。

1
2
3
$ docker ps
f98368a0a9e5 eugenmayer/unison:2.51.2.2 "/entrypoint.sh supe…" 28 hours ago Up About a minute 127.0.0.1:32771->5000/tcp app_B-sync-volume
129681851c64 eugenmayer/unison:2.51.2.2 "/entrypoint.sh supe…" 5 weeks ago Up 29 hours 127.0.0.1:32770->5000/tcp rails-sync-volume

無事起動できています。

docker-composeを試しに起動してみる

次はdocker-composeです。コピーした設定のままで一旦起動してみます。

1
2
3
4
$ docker-compose up
(省略)
Bind for 0.0.0.0:3306 failed: port is already allocated
(省略)

3306ポートは既存の開発環境が利用しているということで、エラーになってしまいました。
ポートの調整が必要ですね。

dockerのポート番号の調整を行う

ホスト側に公開するポートを3307に変更します

1
2
3
4
5
6
db:
image: mysql:5.6
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3307:3306'

これで再度試します。

1
2
3
4
$ docker-compose up
(省略)
Bind for 0.0.0.0:3000 failed: port is already allocated
(省略)

ある意味予想通りですが、Railsのポートも重複しているので、3001に変更します

1
2
3
4
5
6
7
web:
build:
context: .
dockerfile: ./docker/rails/Dockerfile
command: ['rails', 's', '-p', '3000', '-b', '0.0.0.0']
ports:
- "3001:3000"

これでもう一度試します。

1
2
3
4
5
$ docker-compose up
(省略)
caecf6ab0866_app_B_web_1 | * Environment: development
caecf6ab0866_app_B_web_1 | * Listening on tcp://0.0.0.0:3000
caecf6ab0866_app_B_web_1 | Use Ctrl-C to stop

無事起動しました!

Rails側の調整

MySQLのポート番号を修正しているので、config/database.ymlport: 3307を追記してコンテナを再起動します。

動作確認

http://localhost:3001 にアクセスします。すると、エラーが表示されました…

Can't connect to MySQL server on 'db' (111)

dbへの接続ができていないようです…

コンテナ間通信時のポート指定

原因調査のためドキュメントを調べていると、以下のページが見つかりました。

https://matsuand.github.io/docs.docker.jp.onthefly/compose/networking/

ネットワークにより接続されているサービス間の通信は CONTAINER_PORT を利用します。

ということは、docker-compose.ymlでのポート指定が3307:3306なので、Railsアプリケーションのコンテナからは3306でアクセスすればよいということですね。config/database.ymlの修正は必要がなかったということです。

config/database.ymlport: 3307を削除したら、無事動作確認できました。

まとめ

今回新しくRailsアプリケーション開発環境を作成しました。既存の設定ファイルをコピーして少し編集しただけですが、docker-sync, docker-composeの理解が進んだと思います。

次回は新しいhexoのアプリケーション設定を行いたいと思います。