Docker for MacでRails/MySQLの開発環境を作る

環境

プロジェクトを定義する

プロジェクトディレクトリを作成し、以下のファイルを全て同じ階層に置きます。

.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── docker-compose.yml
└── .env

以下は各ファイルの内容です。 空のGemfile.lockも作っておきましょう。

Dockerfile

# Rubyの公式コンテナ(Docker イメージ、実行環境、命令の標準セットを含む)を使う
FROM ruby:2.5.0

# RubyイメージはDebianイメージをベースにしているため、apt-getを使い依存関係をインストールする
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# /lib/railbook を作業用ディレクトリに設定する
# 以下のRUN,CMD,ENTRYPOINT,COPY,ADDコマンドはこのディレクトリ配下で実行される
RUN mkdir /railbook # --- 訂正前 --- RUN mkdir /lib/railbook
WORKDIR /railbook # --- 訂正前 --- WORKDIR /lib/railbook

# Gemfile をコピーして bundle install する
COPY Gemfile /railbook/Gemfile # --- 訂正前 --- ADD Gemfile /lib/railbook/Gemfile
COPY Gemfile.lock /railbook/Gemfile.lock # --- 訂正前 --- ADD Gemfile.lock /lib/railbook/Gemfile.lock
RUN bundle install

COPY . /railbook # --- 訂正前 --- ADD . /lib/railbook

Gemfile

source 'https://rubygems.org'

gem 'rails', '5.1.5'

docker-compose.yml

version: '3'
services:
  db:
    image: mysql:5.7
    ports:
      - "3306:3306"
    env_file: .env # 環境設定はパスワードなども含むため、.envにして同階層に配置し、外部ファイルから読み込む
    volumes:
      - ./db/mysql:/var/lib/mysql:cached

  web:
    build: .
    depends_on:
      - db
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    volumes:
      - .:/railbook:cached # --- 訂正前 --- - ./lib/railbook:/lib/railbook:cached

.env

MYSQL_USER=任意のユーザー名
MYSQL_ROOT_PASSWORD=任意のパスワード

プロジェクトを構築する

まず新規アプリを作成します。

$ docker-compose run web rails new . --force --database=mysql
Creating network "railsintro_default" with the default driver
Creating railsintro_db_1 ... done
Building web
3e731ddb7fc9: Pull complete
47cafa6a79d0: Pull complete
79fcf5a213c7: Pull complete
68e99216b7ad: Pull complete
4822563608bb: Pull complete
9d614f26bec1: Pull complete
1c758cfc0888: Pull complete
8a4fbc3666ca: Pull complete
Digest: sha256:ed5fc221d5d03d89e1f8c1f7780b98bc708e68b4d8dba73594d017e999156619
Status: Downloaded newer image for ruby:2.5.0
 ---> bae0455cb2b9
Step 2/8 : RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
 ---> Running in e553e712bc3f
Reading package lists...
Building dependency tree...
Reading state information...
libpq-dev is already the newest version (9.6.6-0+deb9u1).
The following additional packages will be installed:
  dpkg-dev fakeroot libalgorithm-diff-perl libalgorithm-diff-xs-perl
  libalgorithm-merge-perl libfakeroot libuv1
Suggested packages:
  debian-keyring
The following NEW packages will be installed:
  build-essential dpkg-dev fakeroot libalgorithm-diff-perl
  libalgorithm-diff-xs-perl libalgorithm-merge-perl libfakeroot libuv1 nodejs
0 upgraded, 9 newly installed, 0 to remove and 20 not upgraded.
Need to get 5328 kB of archives.
After this operation, 17.0 MB of additional disk space will be used.
Get:1 http://deb.debian.org/debian stretch/main amd64 dpkg-dev all 1.18.24 [1592 kB]
Get:2 http://deb.debian.org/debian stretch/main amd64 build-essential amd64 12.3 [7346 B]

〜中略〜

WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
/lib/railbook/Gemfile not found

以上で土台となるスケルトン(骨組み)が作成できました。そしてイメージを再構築する必要があるので、buildコマンドを叩きます。

$ docker-compose build
db uses an image, skipping
Building web
Step 1/8 : FROM ruby:2.5.0
 ---> bae0455cb2b9
Step 2/8 : RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
 ---> Using cache
 ---> 26f1748c3d95
Step 3/8 : RUN mkdir /lib/railbook
 ---> Using cache
 ---> c7beaa0e6aa0
Step 4/8 : WORKDIR /lib/railbook
 ---> Using cache
 ---> 5484205f8d5c
Step 5/8 : ADD Gemfile /lib/railbook/Gemfile
 ---> Using cache
 ---> 910e85a15616
Step 6/8 : ADD Gemfile.lock /lib/railbook/Gemfile.lock
 ---> Using cache
 ---> 4ba7b0021eea
Step 7/8 : RUN bundle install
 ---> Using cache
 ---> 948e06ccc33c
Step 8/8 : ADD . /lib/railbook
 ---> c1881c2864b8
Successfully built c1881c2864b8
Successfully tagged railsintro_web:latest

データベースに接続…と思ったら

config/database.ymlを書き換え…config/database.ymlがない! どこで間違えたのか調べます。 Dockerfileとかで指定した /lib/railbook がなんか怪しい気がしますね。

一旦、コンテナとイメージを削除してbuildからやり直してみます。

$ docker container rm CONTAINER ID

$ docker image rm IMAGE ID

とりあえずDockerfileとdocker-compose.ymlを公式と同じ書き方にしてbuildしてみると、ルートにappなどのディレクトリが自動でたくさん作成され、config/database.ymlも作成されました。 build中にターミナルで表示されるメッセージも後半部分が違っています。

そこでエラーメッセージをよく確認すると、最初にdocker-compose runしたときの最後のエラーメッセージに原因が書いてありました。

/lib/railbook/Gemfile not found

つまりdocker-compose.ymlのwebのvolumesの指定がおかしかったのです。 volumesのホスト側はGemfileと同じ階層を指定しなければいけなかったようです。

    volumes:
      - ./lib/railbook:/lib/railbook:cached

この箇所を以下のように修正します。

    volumes:
      - .:/railbook:cached

ついでにDockerfileのADDコマンドをCOPYコマンドに変えておきます。 Dockerfile のベストプラクティス — Docker-docs-ja 1.9.0b ドキュメント

修正箇所は最初に記載したコードに記しておきました。

そして再び、 docker-compose run web rails new . --force --database=mysql を叩きます。 今度はうまくいきました。

改めてデータベースに接続

config/database.ymlの username とpassword をdocker-compose.ymlのdbサービスで設定したものに書き換えます。


ここから追記 2018-4-27

database.ymlには username とpassword の他に、hostをdocker-composeで定義したDBのサービス名にしないといけません。dbとwebでコンテナをわけているので、hostをdbにしないと「/var/run/mysqld/mysqld.sock' (2 "No such file or directory")」のようなソケットエラーが出ます。

database.yml(抜粋)

〜中略〜

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: 任意のユーザー名
  password: 任意のパスワード
  host: db

development:
  <<: *default
  database: films_development

〜中略〜

追記終わり


起動します。

$ docker-compose up

起動を確認できたら、一旦 Ctrl-C で停止します。 最後にデータベースを作成します。

$ docker-compose run web rake db:create

バックグラウンドで再起動します。

$ docker-compose up -d

ページが表示されるか確認する

ブラウザで http://localhost:3000 に接続して、Railsのウェルカムページ「Yay! You’re on Rails!」の画面が表示されればOKです。

感想

慣れてないと色々調べるのに時間はかかるが、一度設定ファイル作れば起動は楽になります。なんだかんだ不明点を調べるのに1日かかりましたが。 今度は今話題のKubernetesも試してみようと思います。

主な参考資料

クイックスタート・ガイド:Docker Compose と Rails — Docker-docs-ja 17.06.Beta ドキュメント

Quickstart: Compose and Rails | Docker Documentation
英語版のほうがversionなど新しかったので、基本的な書き方はこちらに沿って行いました。

[Rails] DockerでRails + MySQLの開発環境をつくる手順 - Qiita

Rails with docker-composeで'/tmp/mysql.sock'がねえよと怒られたとき - Qiita

RailsプロジェクトのDocker導入手順 | 酒と涙とRubyとRailsと

Docker & Rails: Running a Rails Development Environment in Docker | Codeship | via @codeship

Cookpad Inc. · GitHub