DockerでRails6+PostgreSQLの開発環境を構築する


バージョン

  • Ruby 2.7.5
  • Rails 6.1.5 (※APIモードではなく通常モード)
  • PostgreSQL 14.2

rails newで除外するもの

自分にとって不要なものを外す

  • turbolinks
  • test (RSpecを後で使う予定なので、minitestは不要)
  • actioncable

gemのインストール先

公式のRubyイメージではbundle installのインストール先が/usr/local/bundleになっている。
それを前提としてbundle installはオプションをつけずに実行する。
また、docker-comopse buildの時間を短縮するため、/usr/local/bundleをボリュームとして保持する。

ボリューム

以下についてはすべてボリュームに保存する事にして
Railsプロジェクト直下には置かないことにする。

  • PostgreSQLのdataディレクトリ
  • vender/bundle
  • node_modules

1. 作業用ディレクトリの作成

railsプロジェクトのルートとなるディレクトリを作成。

$ mkdir rails-app
$ cd rails-app

2. GemfileとGemfile.lockを作成する

$ touch Gemfile
$ touch Gemfile.lock

Gemfileには使用したいRailsのバージョンだけを記述。

Gemfile
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails", "6.1.5"

3. Dockerfileを作成する

Dockerfile
FROM ruby:2.7.5

RUN apt-get update -qq && apt-get install -y build-essential postgresql-client

WORKDIR /myapp

# install nodejs(LTS)
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs

# npm自体のバージョンを最新にする
RUN npm install -g npm

# install yarn
RUN npm install -g yarn

# gem
COPY Gemfile /myapp/
COPY Gemfile.lock /myapp/
RUN gem install bundler
RUN bundle install

# コンテナー起動時に毎回実行されるスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

# 3000番ポートをリンクしたサービスのみに公開
EXPOSE 3000

4. entrypoint.shを作成する

entrypoint.sh
#!/bin/bash
set -e

# server.pidが残っているとrailsが起動できないので削除する
rm -f /myapp/tmp/pids/server.pid

# コンテナーのプロセスを実行する(Dockerfile 内の CMD に設定されているもの)
exec "$@"

5. docker-compose.ymlを作成

docker-compose.yml
version: "3.9"
services:
  db:
    image: postgres:14.2
    container_name: rails-app_db
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: devuser
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C"
    networks:
      - mynetwork

  web:
    image: rails-app_web
    build:
      context: .
      dockerfile: Dockerfile
    container_name: rails-app_web
    command: bash -c "bundle install && yarn install --check-files && rm -f tmp/pids/server.pid && bundle exec pumactl start"
    environment:
      TZ: Asia/Tokyo
      RAILS_ENV: development
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
      - node_modules:/myapp/node_modules
    ports:
      - "3000:3000"
    depends_on:
      - db
    networks:
      - mynetwork

networks:
  mynetwork:
    name: rails-app

volumes:
  pgdata:
    name: rails-app_pgdata
  bundle:
    name: rails-app_bundle
  node_modules:
    name: rails-app_node_modules
  

Gitでファイルを管理する

あとでやり直せるように、gitで管理しておく。

$ git init
$ git add -A
$ git commit -m "initial commit"

6. Railsプロジェクトを作成する

rails newの時に、bundle installやyarn installをするとエラーになるので後で行う事にする(--skip-bundle --skip-webpack-install)。
後は、turbolinks、actioncable、testを除外するオプションを指定して実行。

$ docker-compose run web rails new . --force --no-deps --database=postgresql \
--skip-action-cable --skip-turbolinks --skip-test \
--skip-bundle --skip-webpack-install

成功すると、カレントディレクトリにrailsプロジェクトのファイルが生成されている。
この時に、Gemfileも上書きされる。
ファイルのパーミッションはrootになっているので、現在操作しているユーザーに変更しておく。

$ sudo chown -R ${USER}:${USER} .

Gemfileをシンプルにする

コメントが多くてごちゃごちゃしているので自分はいつもコメントを消してバージョン指定も最小限にする。
pgのバージョンを指定しているのは、1.3に上げるとなにかの警告が表示されたため。
本来はここからrspec-railsやkaminariなどを追加していくのだが、とりあえず最小限の状態にしておく。

Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.7.5'

gem 'rails', '~> 6.1.5'
gem 'pg', '~> 1.2.3'
gem 'puma'
gem 'sass-rails'
gem 'webpacker'
gem 'jbuilder'
gem 'bcrypt'
gem 'bootsnap', require: false
gem 'tzinfo-data'

group :development do
  gem 'web-console'
  gem 'listen'
  gem 'spring'
end

ここまでの作業をコミット

$ git add -A
$ git commit -m "railsプロジェクトを作成"

7. Dockerイメージをビルド

$ docker-compose build

8. DB接続設定を修正

config/database.ymlをdocker-compose.ymlの内容に合わせて修正する。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  port: 5432
  host: db
  username: devuser
  password: devuser

development:
  <<: *default
  database: myapp_dev

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: <%= ENV["DATABASE_USERNAME"] %>
  password: <%= ENV["DATABASE_PASSWORD"] %>
  host: <%= ENV["DATABASE_HOST"] %>

9. bundle installを行う

$ docker-compose run web bundle install

10. webpacker:installを行う

$ docker-compose run web bin/rails webpacker:install

11. データベースを作成

$ docker-compose run web bin/rails db:create

うまく行くと、このような表示になる。

[+] Running 3/1
 ⠿ Network rails-app          Created                                                                                                                      0.1s
 ⠿ Volume "rails-app_pgdata"  Created                                                                                                                      0.0s
 ⠿ Container rails-app_db     Created                                                                                                                      0.0s
[+] Running 1/1
 ⠿ Container rails-app_db  Started                                                                                                                         0.4s
Running via Spring preloader in process 20
Created database 'myapp_dev'
Created database 'myapp_test'

12. コンテナを起動

$ docker-compose up

成功すると以下のようなログが流れる。

rails-app_web  | => Booting Puma
rails-app_web  | => Rails 6.1.5 application starting in development
rails-app_web  | => Run `bin/rails server --help` for more startup options
rails-app_web  | Puma starting in single mode...
rails-app_web  | * Puma version: 5.6.4 (ruby 2.7.5-p203) ("Birdie's Version")
rails-app_web  | *  Min threads: 5
rails-app_web  | *  Max threads: 5
rails-app_web  | *  Environment: development
rails-app_web  | *          PID: 1
rails-app_web  | * Listening on http://0.0.0.0:3000
rails-app_web  | Use Ctrl-C to stop

ブラウザで http://localhost:3000/ にアクセスしてRailsのトップページが表示されたら成功。