複数のRails on Dockerアプリで一つのDBを共有する
個人開発のRailsアプリが大きくなってきて、APIや管理画面などをプロジェクト単位で割りたいと思い、共通のDB、共通のネットワークに再構成した際の備忘録になります。
今更ながらZennは初投稿、笑
完成例
この記事でのサンプル概要
- 2つのRails on Docker(app-api, app-admin)のプロジェクトがある
- app-apiプロジェクトにRailsの
api
コンテナ、Postgres(やMySQLなど)のdb
コンテナがある。このdb
をapp-adminでも使う - app-adminプロジェクトはRailsの
admin
コンテナのみ
この記事でやること
- 共通ネットワーク(
app_common_network
)を作成 - app-api, app-adminの共通ネットワークにする
- 共通のDB(app-apiの
db
コンテナ)を使う
完成図
この記事での前提(実装前)
各docker-compose.yml
app-api側
version: '3'
services:
api:
build: .
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
RAILS_ENV: development
volumes:
- bundle_install:/usr/local/bundle
- .:/app-api
ports:
- '3000:3000'
links:
- db
db:
image: postgres
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- '5432:5432'
volumes:
- ./db/postgres:/var/lib/postgresql/data
volumes:
bundle_install:
driver: local
app-admin側
version: '3'
services:
admin:
build: .
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app-admin
ports:
- '3000:3000'
現状のコンテナ構成図
1. 共通のネットワークを作成
まずは、共通のネットワーク(app_common_network
)を作成します
> docker network create app_common_network
dockerコマンドでネットワークを確認すると、以下のようにapp_common_network
が追加されているのが確認できるかと思います。
> docker network ls
NETWORK ID NAME DRIVER SCOPE
097xxxxxxxxx bridge bridge local
fa4xxxxxxxxx app-api_default bridge local
69bxxxxxxxxx app-admin_default bridge local
fa0xxxxxxxxx app_common_network bridge local
805xxxxxxxxx host host local
db6xxxxxxxxx none null local
2. 共通のネットワークを使う
作成したapp_common_network
を使うように変更します。
最上位のnetworks
キーで独自ネットワークを定義します。
networks:
app_common_network:
external: true
それぞれのサービスにnetworks
キーを使ってapp_common_network
を指定します。
services:
hoge:
build: .
# ...(省略)...
networks:
- app_common_network
上記を踏まえ、各docker-compose.ymlを以下のように修正します。
app-api側
version: '3'
services:
api:
build: .
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
RAILS_ENV: development
volumes:
- bundle_install:/usr/local/bundle
- .:/app-api
ports:
- '3000:3000'
links:
- db
+ networks:
+ - app_common_network
db:
image: postgres
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: password
ports:
- '5432:5432'
volumes:
- ./db/postgres:/var/lib/postgresql/data
+ networks:
+ - app_common_network
+networks:
+ app_common_network:
+ external: true
volumes:
bundle_install:
driver: local
app-admin側
- - '3000:3000'
+ - '23000:3000'
db
を共有する場合、app-api, app-adminの両方を立ち上げる必要があります。現状ポート番号3000を両方使っているため、admin側を23000に変更します(ちなみに13000番はLinden Labで使われている?ので23000番にしてます)。
それを踏まえ、以下のように修正します。
version: '3'
services:
admin:
build: .
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app-admin
ports:
- - '3000:3000'
+ - '23000:3000'
+ networks:
+ - app_common_network
+networks:
+ app_common_network:
+ external: true
修正したら、app-api, app-adminのコンテナを両方ビルドし直しましょう
> cd app-apiのパス
> docker compose build --no-cache # 念のためキャッシュなしでビルド
> cd app-adminのパス
> docker compose build --no-cache
3. 共通のDBを使う
db
コンテナがないapp-adminのconfig/database.yml
を追加します。
app-apiと同じDBを使うので、app-api/config/database.yml
の設定がすでにあれば同じ設定で問題ないかと思います。
+default: &default
+ adapter: postgresql
+ encoding: unicode
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ username: root
+ password: password
+ host: db
+
+development:
+ <<: *default
+ database: app_development
+
+test:
+ <<: *default
+ database: app_test
+
+production:
+ <<: *default
+ adapter: postgresql
+ database: <%= ENV['DB_NAME'] %>
+ username: <%= ENV['DB_USERNAME'] %>
+ password: <%= ENV['DB_PASSWORD'] %>
+ host: <%= ENV['DB_HOSTNAME'] %>
+
4. コンテナ起動
これで共通のネットワーク設定は完了しているので、コンテナを起動します。
ネットワーク設定を変更したため、起動中にネットワークエラーが発生する場合があります。その際は--force-recreate
を試してみてください(僕も発生したことがあるのですが再現できず、、まだまだDockerやネットワーク周りの知識不足です)。
> cd app-apiのパス
> docker compose up
> docker compose up --force-recreate # エラーが発生してコンテナ起動できない場合
# app-apiのコンテナは起動したまま別でシェル起動して..
> cd app-adminのパス
> docker compose up
終わり
これでapp-api, app-adminの両方で共通のDBが使えるようになったかと思います!
もし文章中に間違った表現や、再現できないなどがあれば、ご指摘・お知らせいただけると幸いです。
Discussion