DockerでRails環境を構築する方法

こんにちは!

今回はDockerでRails環境を構築する方法についてまとめます。

はじめに

docs.docker.jp

  • クイックスタートガイドに基づいて解説

手順

  1. Dockerfile、Gemfile、Gemfile.lock、docker-compose.ymlの作成
  2. docker compose run web rails new . --force --database=postgresql
  3. Dockerfileの修正
  4. config/database.ymlの設定
  5. docker compose build
  6. docker compose run web rails db:create
  7. docker compose up -d

手順① Dockerfile、Gemfile、Gemfile.lockの作成

Dockerfile

FROM ruby:3.3.0
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp 
  • これはクイックスタートガイドのDockerfileの内容
    • 適宜バージョンアップなどをして調整する
  • ホスト側のカレントディレクトリにDockerfileを作成

FROM ruby:3.3.0

  • ベースにするイメージを指定
    • DockerHubを確認し、最新のruby:3.3.0を指定

RUN apt-get update --qq && apt-get install -y

  • コンテナ内で実行されるコマンドを指定

    apt-get update -qq

  • インストール可能なパッケージの一覧をアップデートする
  • --qqはログの表示を抑える

    apt-get install -y

  • インストールするパッケージを指定する
  • -yは確認ダイアログを全てYesで進める

    build-essential

  • 開発に必要なビルドツールなどのパッケージ
  • gccやmakeなどが含まれる

    libpq-dev 

  • PostgreSQLに接続するために必要なパッケージ

    nodejs

  • webpackなどを利用するため必要

RUN mkdir /myapp

WORKDIR /myapp

  • 基準となるディレクトリを絶対パスで指定
    • 以降の操作はこのディレクトリが基準になる

      Gemfile /myapp/Gemfile

  • Gemfileを/myapp/Gemfileに追加(コピー)する

    • ADDCOPYはほぼ同じ機能
    • ADDには圧縮ファイルを解凍する機能などが含まれており、COPYを使う方が推奨される
  • ADD 追加元 追加先で指定する

ADD Gemfile.lock /myapp/Gemfile.lock

  • 上と同じ

RUN bundle install

  • 先ほどコピーしたGemfileを使用してコンテナ内でGemをインストールする

ADD . /myapp

  • ホスト側のカレントディレクトリの内容を全て/myappに追加(コピー)する

Gemfile

source 'https://rubygems.org'
gem 'rails', '>= 7.1.3'
  • railsのバージョンを最新にした

Gemfile.lock

  • ホスト側のカレントディレクトリに空のGemfile.lockを用意する

docker-compose.yml

version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=secret
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

version

  • docker-composeのバージョンを指定

services

  • 使用するコンテナの内容を定義

db

  • dbコンテナの内容を定義

image

  • 使用するイメージを指定

volumes

  • バインドマウントを指定

environment

  • 環境変数PostgreSQLのパスワードを指定
    • POSTGRES_USER: 指定しなかった場合はデフォルトでpostgresとなる
    • POSTGRES_DB: 指定しなかった場合はデフォルトでpostgresとなる

web

  • webコンテナの内容を定義

build

  • 既存のイメージを使わない場合は、buildにDockerfileが置いているディレクトリのパスを指定

command

  • コンテナ内で実行するコマンドを指定

volumes

  • バインドマウントを指定

ports

depends_on

  • 依存関係を指定し、起動順序を調整する

手順② docker compose run web rails new . --force --database=postgresql

docker compose run web rails new . --force --database=postgresql

  • docker composeのwebコンテナでrails new . --force --database=postgresqlコマンドを実行
  • --force 上書きの指定
  • --database=postgresql 使用するデータベースの指定
    • 何も指定しないとsqliteとなる
  • この時点で、Dockerfileが本番環境の内容で上書きされる

手順③ Dockerfileの修正

  • 本番環境の内容で上書きされたDockerfileを、最初に作成したDockefileの内容に再度上書きする
    • 本番環境用のDockefileはDockerfile.prodなどの名前で保存しておくとよい

手順④ config/database.ymlの設定

  • config/database.ymlを編集し、データベースへの接続設定を行う

config/database.yml

default: &default
  adapter: postgresql
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db
  user: postgres
  password: secret

host

  • 接続するdbのコンテナ名を指定
    • docker-compose.ymlでdb:と指定していればdbを記載

user

  • postgreSQLのユーザー名を指定
    • docker-compose.ymlで指定していなければ、デフォルトのpostgres

password

  • postgreSQLのパスワードを指定
    • docker-compose.ymlで環境変数に指定したパスワードを記載

手順⑤ docker compose build

  • rails newのタイミングで、Gemfileも新しくなっているので、再度buildしてDockerイメージを作成する

手順⑥ docker compose run web rails db:create

docker compose run web rails db:create

  • docker composeのwebコンテナでrails db:createコマンドを実行
  • rails db:create config/database.ymlを元にデータベースを作成する

WSL2の場合のエラー

  • WSL2で上記コマンドを実行すると、以下のエラーが出る
could not translate host name "db" to address: Temporary failure in name resolution
Couldn't create 'myapp_development' database. Please check your configuration.
bin/rails aborted!
ActiveRecord::ConnectionNotEstablished: could not translate host name "db" to address: Temporary failure in name resolution (ActiveRecord::ConnectionNotEstablished)
  • WSL2でない実機のUbuntuなどでは問題なく動作するので、dbの指定箇所の間違いなどではなさそう
  • docker compose logsで確認すると以下のエラーが出ている
test-db-1  | chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
test-db-1  | The files belonging to this database system will be owned by user "postgres".
test-db-1  | This user must also own the server process.
test-db-1  |
test-db-1  | The database cluster will be initialized with locale "en_US.utf8".
test-db-1  | The default database encoding has accordingly been set to "UTF8".
test-db-1  | The default text search configuration will be set to "english".
test-db-1  |
test-db-1  | Data page checksums are disabled.
test-db-1  |
test-db-1  | initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permitted
  • パーミッション関係のようだが、いい解決策が見つからなかった
  • バインドマウントをせずに、名前付きボリュームにすると動作した
  • docker-compose.ymlの変更箇所抜粋
  db:
    volumes:
      - postgres_volume:/var/lib/postgresql/data
volumes:
  postgres_volume:

手順⑦ docker compose up -d

docker compose up -d

  • docker compose で立ち上げ
  • http://localhost:3000でアクセス

おわりに

今回はDockerでRails環境を構築する方法についてまとめました。今回のDockerの環境構築を通じて、大分Dockerを実際に使うことに慣れてきました。前回Dockerを学んだときはDockerの仕組みを理解することで精いっぱいでしたが、今回の構築作業を通してDockerが使える道具になったと思います。

62/100