はじめに
ここまで以下の記事のとおり、Rails6 + PostgreSQL、Vue3の開発環境をDockerでそれぞれ構築してきました。
今回は、それぞれ構築したこの開発環境をDocker Composeを使って、まとめて管理できるようにしていきたいと思います。
目次
1. ディレクトリの構成
2. 完成したファイル
3. front/Dockerfileの修正
4. dockercompose.ymlの修正
5. 動作確認
6. さいごに
1. ディレクトリの構成
準備したファイルは以下のとおり、各ディレクトリに配置しています。
.
├── api
│ ├── Gemfile
│ ├── Gemfile.lock
│ ├── Dockerfile
│ └── entrypoint.sh
├── front
│ └── Dockerfile
└── dockercompose.yml
2. 完成したファイル
今回は最初に完成形のファイルをお示しした上で、前回までの記事で作成したファイルをどのように考え、どのように修正したかという点について、述べていきたいと思います。
source 'https://rubygems.org'
gem 'rails', '~> 6.1'
# 何も書きません
FROM ruby:3.0
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update -qq \
&& apt-get install -y nodejs yarn postgresql-client
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
#!/bin/bash
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
FROM node:16.16
RUN apt-get update -qq && yarn global add @vue/cli
WORKDIR /app
COPY . /app
CMD ["yarn", "serve"]
version: "3.9"
services:
db:
image: postgres
volumes:
- postgresql_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
api:
build: ./api
volumes:
- ./api:/app
ports:
- "3000:3000"
depends_on:
- db
front:
build: ./front
volumes:
- ./front:/app
ports:
- "8080:8080"
volumes:
postgresql_data:
3. front/Dockerfileの修正
前回の記事で作成していたDockerfileでは、最後のコマンドを
CMD ["/bin/bash"]
としていましたが、次のように修正しました。
CMD ["yarn", "serve"]
DockerfileのCMD
はコンテナ起動時に実行するコマンドです。
前回の記事では、コンテナ内でコマンドを実行してVueのインストールなどを試していたので、bashを起動させるようにしていましたが、実際に開発を進める時は、コンテナを起動させるとVueプロジェクトのサーバーに立ち上がってほしいので、上記のように修正しました。
4. dockercompose.ymlの修正
今回、先に作成していたRails6 + PostgreSQLの環境にVue3を追加するにあたって、主に修正したのはdockercompose.ymlとなります。
もともと作成していたdockercompose.ymlは次のとおりです。
version: "3.9"
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- db
dbコンテナのvolumes
以前の設定では、DBのデータはホスト側の./tmp/dbにマウントしていましたが、volumes
を使ってDocker側で管理することにしました。
Docker側で管理することのメリットは公式で以下のとおり説明されています。
- ボリュームはバインドマウントよりも、バックアップや移行が容易です。
- ボリュームは Docker CLI コマンドや Docker API を利用して管理することができます。
- ボリュームは Linux と Windows 上のコンテナーにおいて動作します。
- ボリュームは複数コンテナー間にて安全に共有できます。
- ボリュームドライバーを用いると、リモートホスト上、あるいはクラウドプロバイダー上のボリュームに保存できるようになります。保存の際にはボリューム内データを暗号化することができ、その他にも種々の機能を利用することができます。
- ボリュームを新たに生成すると、その内容はコンテナーがあらかじめ用意していた内容になります。
- Docker Desktop 上のボリュームは、Mac や Windows ホストからのバインドマウントに比べて、より高い性能を実現します。
次のとおりvolumes
を作成、作成したvolumes
へのマウントを行っています。
# volumesを作成
volumes:
postgresql_data:
# volumesへのマウント
volumes:
- postgresql_data:/var/lib/postgresql/data
apiコンテナのcommandを削除
dockercompose.ymlから次の箇所を削除しました。
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
dockercompose.ymlのcommand
はdocker compose
でコンテナを起動したとき、DockerfileのCMD
を上書きして実行されます。
そのため、同じことを書いているのであれば、Dockerfileの
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
と、dockercompose.ymlの
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
はいずれか一方でいいのではないかと考えました。
開発時のコンテナの起動はdocker compose
使うつもりだったので、当初は「dockercompose.ymlに書いてあったら十分だな。Dockerfileを修正しよう。」と考えていましたが、公式で以下の記述を見つけたため、dockercompose.ymlを修正することにしました。
Dockerfile は、少なくとも1つの CMD か ENTRYPOINT 命令を書くべきです。
この点については自分なりに調べてこの結論を出しましたが、Docker Composeを使うときもこの公式の記述は適用すべきなのかは自信が持てずにいます。
「dockercompose.ymlに書くべきだ」や「両方に書くべきだ」という意見がありましたら、ぜひコメントをお願いします。
frontコンテナの追加
本来はここがメインになるはずでしたが、いざやってみると、
-
build
でDockerfileのパスを指定 -
volumes
でマウント先の設定 -
ports
でコンテナの8080ポートをホストの8080ポートに公開
ということを淡々と設定したのみであっさりと完了しました。
5. 動作確認
まずはDockerのイメージを作成→Railsアプリを作成→Gemfileが更新されたのでイメージの再作成をします。
$ docker compose build
$ docker compose run --rm --no-deps api rails new . -f -T --api --database=postgresql
$ docker compose build
次にdatabase.ymlの設定をして、DBを作成します。
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password: password
pool: 5
development:
<<: *default
database: api_development
test:
<<: *default
database: api_test
$ docker compose run --rm api rails db:create
これでRailsアプリの作成は完了したので、次にVueプロジェクトを作成します。
$ docker compose run --rm front vue create .
Vue CLI v5.0.8
? Generate project in current directory? (Y/n) Y
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 3] babel, eslint)
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn
さて、準備ができたの、コンテナを起動させます。
$ docker compose up
localhost:3000、localhost:8080にアクセスすると、それぞれのウェルカムページが出迎えてくれます。
無事、DockerでRails6 + Vue3 + PostgreSQLの開発環境を構築することができました!
おまけ
Rails、Vueのウェルカムページが出迎えてくれたので、大丈夫な気がしつつも、本当にこれで開発を進めていける環境が構築できたのか少し不安な気持ちもありました。
なので、以前、某教材で作成したRails + Vueのリアルタイムチャットアプリにこの開発環境を導入してみることにしました。
アプリ内に、今回作成したDocker関連のファイルを配置して、コンテナを起動させてみます。
…特に問題なく動作する。大丈夫そうだ。
6. さいごに
これで長かった環境構築も一段落しました。
ここから先は実際に開発を進める中で必要に応じて、変更を加えていきたいと思います。
一方で、まだDockerを使ってやってみたいなと思うことは残っています。
今、関心があるのは、ベースイメージにslimを使って自分で必要なライブラリをインストールし、イメージサイズを抑えるということです。
こんな風に実際に手を動かす中で関心のあることは増えていくのですが、すべてに手を出していたら時間がいくらあっても足りません。
やっぱり、目的意識を持つことが、学習効率をとっても、時間効率をとっても重要だなとしみじみと感じているところです。