はじめに
DockerでRuby on rails + Mysqlの環境を作っていきます。
環境構築の仕方を知らないとDockerは書けないと思うので、Docker上で動かして環境構築しながらDockerfile及びdocker-composeの記述を追加していこうと思います。
rails s
で起動確認できるところまでやってみます。
Docker導入
Docker Desktop for Apple silicon
ダウンロードって書いてるところわかる?
↓これはまだintel Macしか無理っぽい
$ brew install --cask docker
バージョン確認はこのコマンド
$ docker -v
MySQL8.xインストール
$ brew install mysql
どうしてもMySQLのインストールに詰まっている方は、ver5.7
をインストールしましょう。
$ brew install mysql@5.7
$ brew link mysql@5.7 --force
導入はすばやく終了!
環境構築
作業フォルダを作ってそこにDockerfile
とdocker-compose.yml
を作成します。
(後にこのフォルダにrailsファイルを生成していく形になります。)
Dockerfile
にバージョンを記述してください。
ちょっと古い2.4.6
を使ってみます。
FROM ruby:2.4.6
バージョンはこちらを参考にしました。
https://hub.docker.com/_/ruby
今回はバージョンを自分で決められるのでrailsファイル作る前からバージョン書いてますが、もうすでにrailsファイルがある場合はgemfile見てそのバージョンを記述してくださいね。
次にdocker-compose.yml
を書きます。
version: '3.8'
services:
mysql: #ここはただの名前なのでdbとかdatabaseとかでもよい
image: mysql:latest
platform: linux/x86_64 #M1の場合これ必要
command: --default-authentication-plugin=mysql_native_password
ports:
- "3306:3306"
volumes:
- "./mysql-data:/var/lib/mysql"
environment:
MYSQL_ROOT_PASSWORD: root
app: #コンテナの名前です
build: .
volumes:
- ".:/app"
ports:
- "3000:3000"
tty: true
depends_on:
- mysql
何を書いているのか上から順に説明しますね。
version
docker-composeのバージョンについてはこちらを参考にしてください。
https://docs.docker.com/compose/compose-file/
mysql
バージョンはこちらを参照してください。
https://hub.docker.com/_/mysql
環境構築で挫折しがちなバージョン8以降でやっていきます。
最新版がいいときはmysql:latest
と書くこともできます。
※追記
これM1用で必要な部分
platform: linux/x86_64
mysql8以降を使う場合は必ずこれを記述してください。
command: --default-authentication-plugin=mysql_native_password
Mysql8から認証プラグインがcaching_sha2_password
になるのでmysql_native_password
に代えてあげる作業をしなければなりません。
ここがmysql8の環境構築でネックになる部分なのですが、Dockerではこの一行だけで解決してくれます。
なお、5.7
を使う場合はこの記述は必要ありません。
↑で貼ったリンク先にその辺のことも書かれていて、サンプルコードもあります。
portsは4306:3306
左側がローカルでDocker上のポートで紐づけています。
あとでsequel proに繋ぐやり方を書くのですが、左の4306
を使うことになります。
volumesは、docker環境で作成したデータベースのデータの保存先を決めています。
$ docker-compose up
したとき、指定しているmysql-data
という名前のフォルダがローカルに生成され、ここにdocker環境で作成したデータベースのデータが保存されます。
コンテナを消してしまったとしても前回作成したmysql-dataフォルダが残っていれば、再度コンテナを立ち上げたときに前回までのデータベースがそのまま生かされます。
MYSQL_ROOT_PASSWORD: root
は、mysqlのusernameとpasswordをroot
に指定しています。
あとでdatabase.yml
をそのように修正しますね。
app
build: .
は動かすDockerfileのディレクトリを指します。
今回はdocker-compose.ymlと同じディレクトリにあるので.
としてますが、
例えばdockerフォルダの中のDockerfile.devというファイル名の場合
は、
build:
context: ./docker
dockerfile: Dockerfile.dev
と書きます。ということは、
build: .
# これは
build:
context: .
dockerfile: Dockerfile
# これの略だったんですね。
volumesは".:/app"
左側の.
がローカルのディレクトの位置です。
docker-compose.ymlがあるディレクトリにこれからrailsファイルを生成するので.
になっています。
右側の/app
はDockerのコンテナ内のappフォルダ内を指しています。
これでローカルのディレクトリとDockerコンテナ内のディレクトリを紐付けました。
portsはmysqlのときと同じで"3000:3000"
はローカルのポート3000とDockerコンテナ内のポート3000を紐付けています。
tty: true
これは書いといてください!
depends_on: mysql
これは、appとmysqlは別々に起動している形になっているので、appがmysqlにアクセスできるようにしています。
Docker動かしてみる!
一度これで動かしてみたいと思います。
$ docker-compose up
# 中略
Recreating dockerrails_app_1 ... done
Attaching to dockerrails_app_1
こうなっていれば動いてます!
今動いてるdockerrails_app_1の中に入りたいですよね。
(dockerrails
これはローカルのフォルダ名ですので各自違うと思います。)
もう一つターミナルを開いて次のコマンドを打ちます。
$ docker exec -it dockerrails_app_1 /bin/bash
これで入れます。
docker-compose.yml
がルートディレクトリにあれば、
$ docker-compose exec app bash
これで入れます。
# exit
で出れるので試してみてください。
docker-compose.yml
はルートにないとめんどくさそうな気がするので毎回ルートに置いてます。
中に入れたらlsコマンド
でどんなフォルダがあるのか確認してみてください。
# ls
app bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
今作ったapp
というフォルダ内に展開していきたいので、cdコマンド
でappフォルダの中に入ります。
# cd app
これでapp#
に変わったと思います。
これDocker起動してdockerrails_app_1に入ったときに自動的にappフォルダ内に入りたいですよね。
**安心してください!**後でガッと実装しますので。
再度lsコマンド
で確認してみるとDockerfile
とdocker-compose.yml
がいるはずです。
いよいよrailsのファイル達を生成していくのですが、まずrailsをインストールするところから始まります。
app# gem install rails
インストールが完了したらrailsファイルを生成します。
mysqlの開発環境にするので、次のコマンドを流します。
app# rails new . -d mysql
これでファイルが生成されました。
まずはdatabase.yml
を修正します。
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
#下の二つを修正します。
password: root
host: mysql
host: mysql
のmysqlは、docker-composeで指定した名前です。
docker-compose.yml
でmysql:
と命名してdepends_on: mysql
でマウントしましたよね。
さてrails起動してみますかー。
app# rails s -b 0.0.0.0
怒られるんですよね。
nodejsをインストールしないとダメなんです。
次の二つのコマンドを流してください。
app# apt-get update
app# apt-get install nodejs
インストール中(Y/n)を聞かれるので迷わずY
!と答えてください。
後でDockerfileの書き方で触れるので頭の片隅においといてください。
色々と手動で環境構築しているのですが、最終的にすべて自動でしてくれるようにします!
今やっていることはDockerfileに書いていくことになりますのでなんとなくでいいので覚えててください。
このままでも起動はするのですが、mysqlコマンドが使えないのでmysql-client
をインストールしてあげます。
インストール中(Y/n)を聞かれるので迷わずY
!
app# apt-get install mysql-client
データベース作ってあげてrailsを起動してあげます。
app# rails db:create
app# rails s -b 0.0.0.0
無事起動できましたか??
Dockerfile書くぞ!
はい本題ですw
Dockerを動かしてから環境構築するときどんなインストールコマンドを使ってきましたか?
gem install rails
apt-get update
apt-get install -y nodejs
apt-get install -y mysql-client
これらのコマンドを使って環境構築しました。
-y
というのはインストール中に(Y/n)を聞かれた時にYと答えましたよね。そのyです。
これで止まることなく自動でYを選択してくれてどんどん進んでいきます。
これらのコマンドをDockerfileではこう書きます。
RUN gem install rails
RUN apt-get update && \
apt-get install -y nodejs mysql-client
\
バックスラッシュを使うことで改行して書くことができます。
次にbundle installも自動でするようにします。
WORKDIR /app
COPY Gemfile ./
COPY Gemfile.lock ./
RUN bundle install --jobs=4 --retry=3
WORKDIR
でパスを指定することによって、Docker内での作業ディレクトリを指定することができます。
これでDockerを起動してdocker-compose exec app bash
を叩いたとき直接appフォルダ内に入ってくれるようになります。
そして、ローカルのGemfile
とGemfile.lock
をDockerコンテナ内のルートディレクトリ(先程/app
に指定したので/app
内)にコピーします。
その後bundle install
を流しています。
パスは変数で指定した方が吉です。
↓で書いてみます。
こちらが今回作ったDockerfileです。
FROM ruby:2.4.6
ENV LANG=C.UTF-8
ENV WORK_DIR="/app" \
CONTAINER_ROOT="./"
RUN apt-get update && \
apt-get install -y nodejs mysql-client && \
gem install rails
WORKDIR $WORK_DIR
COPY Gemfile Gemfile.lock $CONTAINER_ROOT
RUN bundle install --jobs=4 --retry=3
version: '3.7'
services:
mysql:
image: mysql:8.0.16
command: --default-authentication-plugin=mysql_native_password
ports:
- "4306:3306"
volumes:
- "./mysql-data:/var/lib/mysql"
environment:
MYSQL_ROOT_PASSWORD: root
app:
build: .
volumes:
- ".:/app"
ports:
- "3000:3000"
tty: true
depends_on:
- mysql
Dockerfile
にENV LANG=C.UTF-8
を追加しています。
これはDockerコンテナ内で日本語をDockerさんに受け入れてもらうための記述です。
その下にcommand: "rails s -b 0.0.0.0"
を記述するとrails起動までしてくれますがrailsを停止したときにDockerまで停止させてしまう(Dockerは停止させない設定が必要)のでDockerを起動させてから別ターミナルでrailsを起動するようにしましょ。
Dockerfileを書き換えたので再構築しましょう。--build
オプションを使います。
$ docker-compose up --build
よくあるエラー
rails s -b 0.0.0.0
で下記のエラーが発生した場合、
A server is already running. Check /app/tmp/pids/server.pid.
ローカルの作業ディレクトリ/tmp/pids/server.pid
を削除すれば解決します。
Dockerコンテナ立ち上げ時、毎回削除するようにできますが今回の記事では対象外とします。
Sequel Proで接続

これで繋がります。
Passwordの部分はroot
ですね。
おわり
このくらいのボリュームなら緊急時でも何も見ずにプリッと書けますよね。(そんな緊急時があるのか?)
でもこれは基礎の「き」なのでコンテナのサイズが大きかったりします。。。
例えばベースイメージにAlpine Linux
を使ったりすると実は半分のサイズになったりします。

上がalpineで同じ環境内容で動かしたものになります。
下がこの記事で書いたDockerコンテナです。
alpineにするとまた環境構築のコマンドが違ってくるのでそちらに関して書こう・・・と思ったのですが、もうすでに詳しく書かれている記事があるのでやめときます。
有料ですが500円でDocker書けるようになるならコスパよすぎです。
はい、寝ますおやすも