はじめに
現在在籍しているHappiness Chainというプログラミングスクールの課題の一環として、docker-composeを使ってrailsで作られたwebアプリをdocker化する方法について記載しておきます。
なお、あくまでdocker化に焦点を当てることとし、railsアプリの作成方法については記載しません。
Railsプロジェクトの取得
docker化するRailsプロジェクトのコードをgitから取得します。
git clone <repositoryURL>
Dockerfileの作成
まず、Dockerfileを作成します。Dockerfileはコンテナの中身を記載するファイルで、ビルド時に読み込まれます。
FROM ruby:3.2.2 RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ postgresql-client \ yarn WORKDIR /rails-docker COPY Gemfile Gemfile.lock /rails-docker/ RUN bundle install
Dockerfileの書き方
簡単に中身の解説をします。
FROMで使用するイメージを取得します。
RUNでアプリに必要なライブラリやツールをインストールします。
本アプリを動かすディレクトリをWORKDIRで指定します。ここで指定したディレクトリがコンテナ内に存在しない場合は新規作成してくれます。
Railsアプリで使用するGemfileとGemfile.lockは、今回はすでに作成されているので、それをそのままCOPYでコンテナにコピーします。
最後にbundle install
を実行します。これで適切にgemをインストールします。
なお、このコマンドの記載順には意味があります。再ビルド時にはキャッシュをうまく使って時間短縮しており、変更があった箇所だけ再実行されるからです。
例えば、Gemfile、Gemfile.lockを更新したとします。
この場合、改めてbuild-essentialなどをインストールする必要はありませんが、必ずbundle install
を行いたいため、上記のような順番で書いておきます。
docker-compose.ymlの作成
次に、docker-compose.ymlを作成します。 docker-compose.ymlはdocker composeの設定ファイルです。コンテナをどのように使っていくかについて記載します。
docker composeのメリット
docker composeについて説明する前に、docker-composeを使わない通常のコンテナの起動について見ておきます。
例えば以下のように行います。
docker run -d \ --network app --network-alias mysql \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=secret \ -e MYSQL_DATABASE=todos \ mysql:8.0
これは起動時に使用するネットワーク、ボリューム、環境変数、データベースをオプションで指定しているのですが、とても長いコマンドになっていて、打ち込むのも他の開発者に伝えるのも大変ですよね。
docker composeを使えば、このたくさんのオプションはdocker-compose.ymlという設定ファイルに記載しておき、起動時はdocker-compose up
だけで良くなります。
起動も楽ですし、他の開発者の方にもdocker-compose.ymlを共有するだけで良くなります。
他にも、docker composeを使うと複数のコンテナを立てやすくなるというメリットもあります。
docker-compose.ymlの書き方
docker composeのメリットがわかったところで、docker-compose.ymlを見ていきましょう。
例えば、railsとpostgresを別々のコンテナに格納する場合、docker-compose.ymlには以下のように設定します。
servicesの下にあるweb, dbがそれぞれrails, postgresのコンテナを指します。
# 現在は大抵バージョン3を指定する version: '3' # ホストにボリューム領域を作成 volumes: db-data: services: web: build: . # アプリ起動時に実行するコマンドを指定 # ここではrailsサーバの起動を実行している command: bundle exec rails s -p 3000 -b '0.0.0.0' # アプリのコードはホストだけに設置としたいため、ホストのファイルをコンテナにマウント volumes: - .:/rails-docker # database.yml(後述)内で使用する環境変数を指定 environment: - 'DATABASE_PASSWORD=postgres' # ホストとコンテナのポートを指定 # railsの場合はデフォルトが3000 ports: - "3000:3000" # 先にデータベースを作成するよう指定 depends_on: - db db: # 使用するデータベースの種類とバージョンを指定 image: postgres:12 # コンテナが削除されてもデータが消えないように、ホストのファイルをコンテナにマウント volumes: - 'db-data:/var/lib/postgresql/data' # データベースの環境変数を指定 environment: - 'POSTGRES_USER=postgres' - 'POSTGRES_PASSWORD=postgres'
なお、このコンテナをクラウドで公開する場合は、データベースの環境変数はここに書いてはいけません。
別途環境変数を指定するファイルを作成してそこに記載し、そのファイルはGitで共有しないなど対策をしてください。方法については、例えばこちらを参照してください。
config/database.ymlの作成
次にdatabase.ymlの作成をします。
database.ymlはデータベースの設定値について記載したファイルです。
postgresの場合は以下のように書きます。
default: &default adapter: postgresql encoding: unicode # host名がdocker-compose.ymlのサービス名になる host: db username: postgres # postgresのデフォルトのポートは5432 port: 5432 # このファイルをGitに上げたりするので、パスワードは直接書かない # 環境変数はホスト側(docker-compose.yml)から読み取る password: <%= ENV.fetch("DATABASE_PASSWORD") %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
使用するデータベースの種類によっても異なるため、詳細は割愛します。
ビルドしてデータベースの作成
設定ファイルの作成が終わったので、ビルドしてコンテナ内でデータベースを作成します。
# バックグラウンドで起動するので「-d」オプションを追加 # ビルドが2回目以降の場合はさらに「--build」をつけること $ docker-compose up -d # コンテナの中に入る $ docker-compose exec web bash # データベースを作る $ rails db:create # データベースにテーブル定義を作る $ rails db:migrate # コンテナから出る $ exit # 再度起動 $ docker-compose up
正常にデータベースが作成できていれば、エラーは出ません。
起動して確認
ブラウザでlocalhost:3000
にアクセスできるかを確認します。
また、ボリュームのマウントが上手くいっているかも確認してください。
- アプリでデータ登録の処理を実行する
- Ctrl + Cでアプリを停止
$ docker-compose up
で再度起動localhost:3000
にアクセスし、1で登録したデータが残っているか確認する。
ここで残っていなければ、ボリュームのマウンドがうまくいっていないので、docker-compose.ymlの当該箇所を確認してください。