RailsのDocker環境作成

Rails チュートリアルを勉強したかったので、Docker 公式を参考に Docker 環境を作成しました。
その際に少しやり方を変えたのと、いくつかエラーに遭遇したので、そのメモを書いておきます。

前提 #

  • Docker 導入済み
  • docker-compose コマンドが使用できる

なお、この記事の手順では Rails 5系の環境となる点に注意です。

Docker 環境 #

作成手順 #

※2021/02/07追記 少し公式の手順が変わっていたので見直しを行いました。

公式では、すべてのファイルをルートに置いていますが、自分は以下のようなディレクトリ構造にしたかったので変えました。

自分の場合のディレクトリ構造

(プロジェクトルート)
 |- docker
 | |- ruby
 |   |- Dockerfile
 |-※Railsのソース
 |- docker-compose.yml
 |- entrypoint.sh
 |- Gemfile
 |- Gemfile.lock
 |- README.md

1.Dockerfile を作成

FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /src
WORKDIR /src
COPY Gemfile /src/Gemfile
COPY Gemfile.lock /src/Gemfile.lock
RUN bundle install
COPY . /src

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

2.Gemfile を作成

source 'https://rubygems.org'
gem 'rails', '~>5'

3.Gemfile.lock を作成(中身は空で OK)

4.entrypoint.sh を作成

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /src/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

5.docker-compose.yml を作成

version: '3.9'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password
  web:
    build:
      context: ./
      dockerfile: ./docker/ruby/Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/src
    ports:
      - "3000:3000"
    depends_on:
      - db

※Windows の場合は、下記の注意点も参照。

6.ビルドして、Rails プロジェクトを作成

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

7.もう一度、コンテナをビルド(rails new で Gemfile の内容が変わったため)

$ docker-compose build

8.データベースの接続設定を記述(src/config/database.yml)
データベース名は任意の名前で OK

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

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test

Docker の起動 #

1.コンテナの起動

$ docker-compose up -d

2.初期 DB の作成

$ docker-compose exec web rails db:create

以下のように表示されれば無事データベースが作成されています。

Created database 'myapp_develop'
Created database 'myapp_test'

3.ブラウザでアクセス

localhost:3000

以下のような画面が表示されればOKです。
Railsトップ画面

遭遇したエラー #

ビルドコンテキスト外のファイルを COPY しようとしてエラー #

参考:docker-composeでADDやCOPYをする際に注意すること

docker-compose.yml の以下の部分を

 web:
    build:
      context: ./
      dockerfile: ./docker/ruby/Dockerfile

最初はこうしていました。

 web:
    build: ./docker/ruby

すると、Dockerfile の中で、Gemfile を COPY するところでエラーになりました。

原因としては、ビルドコンテキスト外のファイルで COPY や ADD ができないとのことでした。
つまりビルドコンテキストに./docker/rubyを指定しているので、この配下にあるファイルしか指定できないようです。
なので、buildの個所をcontextdockerfileにわけて記述することで対応しました。

なお、補足として、Dockerfile の COPY などで指定するホスト側のパスは、ビルドコンテキストを基準としたパスになります。

COPY Gemfile /src/Gemfile ←ビルドコンテキスト(./)からのパス

コンテナ起動時に exited with code 1 になる #

参考: docker-compose upするとコンテナが一瞬でexited with code 1する話

docker-compose up で起動するとコンテナがうまく起動しませんでした。
原因としては、コンテナ起動時に実行しているentrypoint.shの改行コードがCRLF(Windows標準)になっていたことでした。
ここは改行コードをLF(Linux標準)に変更して対応しました。

Windows のみで発生するエラー #

postgres コンテナの起動に失敗する #

参考:Docker for WindowsとLaradocでpostgresのコンテナが起動できない場合の対処

コンテナ起動に失敗し、ログを見るとFATAL: data directory "/var/lib/postgresql/data" has wrong ownershipと表示されて
いました。
どうも volume マウントに失敗していたようです。

docker-compose.yml でマウントのパスを/var/lib/postgresql/dataから/var/lib/postgresql/に修正すると、なぜか起動するようになりました。

  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/ ←パス末尾のdataをなくす

Rails アプリが File exists @ dir_s_mkdir - /src/tmp/cache/assets/sprockets/v3.0/2D でエラー落ちする #

参考:Windows+Docker+Railsでsprocketsのエラーが出る時

一度はちゃんと動作していた Rails アプリがこのエラーになり、動作しなくなったことがありました。
どうも Windows の場合は、ファイルの大文字小文字を区別しないことにより、ファイル名称がバッティングしてしまい起こるそうです。

参考記事の通りに対応することで解決しました。

config/initializers/assets.rb に以下を追加

Rails.application.config.assets.configure do |env|
  env.cache = Sprockets::Cache::FileStore.new(
    ENV.fetch("SPROCKETS_CACHE", "#{env.root}/tmp/cache/assets"),
    Rails.application.config.assets.cache_limit,
    env.logger
  )
end

docker-compose.yml を以下のように修正

version: '3.9'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql
    environment:
      POSTGRES_PASSWORD: password
  web:
    build:
      context: ./
      dockerfile: ./docker/ruby/Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    environment:
      - SPROCKETS_CACHE=/cach
    volumes:
      - .:/src
      - cache:/cache
    ports:
      - "3000:3000"
    depends_on:
      - db

volumes:
  cache:

Docke r公式で案内があったのはありがたかったのですが、ディレクトリ構造を変更したこともあり、いくつかエラーに遭遇しました。
とりあえず無事起動できてよかったです。

Rails チュートリアルは一応一通り終わったので、AWS の勉強に戻ろうかと思います。資格取らねば…。

参考リンクまとめ #