はじめに
Dockerの勉強も兼ねてrailsのアプリをコンテナに作ろうとしたが環境構築にアホみたいに時間がかかった。
Dockerもrailsも(もはや初歩的なコマンドすら)不慣れなプログラマを救いたいので、手順を書きます。
あとDockerはこれからrailsエンジニアになる人が合わせて使えるようになっておけばスキルとして加点になるので(新しめの技術なので供給量的にも)、勉強のきっかけになればと。
この手順すらめんどくさいと思った方へ(2019-02-04追記)
何もない状態からrailsサーバーとMySQLのコンテナを立ててくれるシェル
※真面目に作りを意識しながらやった方が今後応用が効くようになるのでできるだけ読んで欲しいです...
環境(!!Rails5系で作成してます!!)
- Mac OS
- Ruby2.5.3
- Rails5.2.2
- MySQL5.7
-> Rails6系では、webpackが入った都合上、yarnのインストールが必要になります。
- こちらのブログが私の記事を参考にしてくださっているので、6系については、そちらに移譲します(2020-02-19追記)
- 私の方でも6系のテンプレートを作成しました(2020-02-19追記)
- zennにrails6の構築記事を書き直しました(2020-11-21追記)
前提(2019-02-04追記)
そもそもDockerコンテナを使うメリットの一つに周辺環境との依存を避けることができることが挙げられる。だが、ローカル(ホスト側)の任意の場所に、アプリを作っていくフォルダ/ファイルを作り、それらをDockerのコンテナ内で利用したり、逆にコンテナ内のフォルダ/ファイルをローカルで扱いたいケースがある。このような場合など、ローカル(ホスト側)の一部のフォルダ/ファイルをコンテナ内のフォルダ/ファイルと同期することをボリュームマウントするという。
【画像・参考】さわって理解する Docker 入門 より
以上を踏まえて、ローカル(ホスト側)のアプリの作業フォルダをsampleApp
(各自で命名してください)とし、コンテナ側をapp_name
としている。app_name
はDockerfile
やdocker-compose.yml
で使っているが、app_name
から変更しなくてよい。(コピペでOK)
ファイル構成(ホスト側つまりローカルが最終的にこういう構成になります)
sampleApp ---- Dockerfile
|-- Gemfile
|-- Gemfile.lock
|-- README.md
|-- Rakefile
|-- app
|-- bin
|-- config ---- application.rb
| |-- boot.rb
| |-- cable.yml
| |-- credentials.yml.enc
| |-- database.yml
| |-- environment.rb
| |-- environments
| |-- initializers
| |-- locales
| |-- master.key
| |-- puma.rb
| |-- routes.rb
| |-- spring.rb
| |-- storage.yml
|
|-- config.ru
|-- db
|-- docker-compose.yml
|-- lib
|-- log
|-- package.json
|-- public
|-- storage
|-- test
|-- tmp
|-- vendor
【1】プロジェクトの作業ディレクトリを作成、移動
mkdir
でディレクトリを作成してcd
で移動
$ mkdir sampleApp
$ cd sampleApp
【2】作業ディレクトリでDockerfileを作成、中身の編集
主はvimで編集をしているが、touch Dockerfile
して、エディタで編集してもOK。
Dockerfileは、Docker上で動作するコンテナの構成情報を記述するためのファイル
(この後【8】で実行してもらう、)docker-build
コマンドによって、Dockerfileに記述されたインフラの構成情報をもとにしてコンテナのもととなるイメージを作成する。
Dockerfileの注意点として、COPY
かADD
をするときにホスト側(左側)は必ず(Dockerfileを置いてあるディレクトリからの)相対パスなので注意(初心者向けに明示的な書き方をした。)
## touch Dockerfile してから vi Dockerfileでもいいけど、カレントディレクトリ内に同じファイル名がなければ、作成&編集ができる
$ vi Dockerfile
# コピペでOK, app_nameもそのままでOK
# 19.01.20現在最新安定版のイメージを取得
FROM ruby:2.5.3
# 必要なパッケージのインストール(基本的に必要になってくるものだと思うので削らないこと)
RUN apt-get update -qq && \
apt-get install -y build-essential \
libpq-dev \
nodejs
# 作業ディレクトリの作成、設定
RUN mkdir /app_name
##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照
ENV APP_ROOT /app_name
WORKDIR $APP_ROOT
# ホスト側(ローカル)のGemfileを追加する(ローカルのGemfileは【3】で作成)
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock
# Gemfileのbundle install
RUN bundle install
ADD . $APP_ROOT
【3】Gemfileを作成、編集
touch Gemfile
で作成して、エディタで編集してもOK
GemfileはBunder用の設定ファイルでこれを元にgemの依存関係を示した、Gemfile.lockを作成する(【4】で空のGemfile.lockを作る)
# vimでGemfileの名前でファイル新規作成
$ vi Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.2'
【4】空のGemfile.lockを作成
$ touch Gemfile.lock
【5】docker-compose.ymlを作成、編集
ymlファイルを以下の例をコピペして作成、MYSQL_ROOT_PASSWORD
とMYSQL_DATABASE
で、任意のパスワード(【7】で同じものを設定する)とデータベース名を設定
$ vi docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: root
ports:
- "3306:3306"
web:
build: .
command: rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/app_name
ports:
- "3000:3000"
links:
- db
【6】rails newを実行する
$ docker-compose run web rails new . --force --database=mysql --skip-bundle
【7】database.ymlを修正する
場所はここ -> /sampleApp/config/database.yml
## カレントディレクトリ(/sampleApp)配下を見てみると色々できていて、configも作成されている
$ ls -l
total 56
-rw-r--r-- 1 author staff 519 1 20 20:07 Dockerfile
-rw-r--r-- 1 author staff 2216 1 20 20:15 Gemfile
-rw-r--r-- 1 author staff 0 1 20 20:08 Gemfile.lock
-rw-r--r-- 1 author staff 374 1 20 20:15 README.md
-rw-r--r-- 1 author staff 227 1 20 20:15 Rakefile
drwxr-xr-x 10 author staff 320 1 20 20:15 app
drwxr-xr-x 8 author staff 256 1 20 20:15 bin
drwxr-xr-x 16 author staff 512 1 20 20:15 config
-rw-r--r-- 1 author staff 130 1 20 20:15 config.ru
drwxr-xr-x 3 author staff 96 1 20 20:15 db
-rw-r--r-- 1 author staff 261 1 20 20:09 docker-compose.yml
drwxr-xr-x 4 author staff 128 1 20 20:15 lib
drwxr-xr-x 3 author staff 96 1 20 20:15 log
-rw-r--r-- 1 author staff 67 1 20 20:15 package.json
drwxr-xr-x 9 author staff 288 1 20 20:15 public
drwxr-xr-x 3 author staff 96 1 20 20:15 storage
drwxr-xr-x 11 author staff 352 1 20 20:15 test
drwxr-xr-x 5 author staff 160 1 20 20:15 tmp
drwxr-xr-x 3 author staff 96 1 20 20:15 vendor
## カレントディレクトリ(/sampleApp)にて
$ cd config
$ vi database.yml
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password # docker-compose.ymlのMYSQL_ROOT_PASSWORD
host: db # docker-compose.ymlのservice名
【8】Docker起動
/sampleApp/config/
がカレントディレクトリなので、cd ..
で一つ上の階層(/sampleApp
)に移動すること
Why?
↓
この後実行するdocker-compose
コマンドはdocker-compose.yml
ファイルを探して実行が進むので、そのディレクトリ(今回なら、/sampleApp
)上で実行しなければならないから
$ docker-compose build # コンテナをビルド
# -dオプションをつけてバックグラウンド実行するとこの後新しいシェルを立ち上げる必要がなくなる
$ docker-compose up # コンテナの一斉起動
【9】DB作成
新しいterminalを開いて、/sampleApp
で実行
$ docker-compose run web rails db:create
【10】ブラウザでlocalhost:3000にアクセスしてサーバーの起動を確認
おまけ
サーバーを止める
$ docker-compose down
Ctrl+C
で止めると、コンテナが残って次回起動時にエラーが出る
もしやっちゃったら、tmp/pids/server.pid
を削除、再起動
再起動はdocker-compose up
でできる
Dockerfileやdocker-compose.ymlの変更を反映、railsサーバーを再起動
$ docker-compose up --build
bundle installなどのコマンドを実行したい
#docker-compose run {サービス名} {任意のコマンド}
$ docker-compose run web bundle install
ローカルからMySQLコンテナに接続
$ mysql -u root -p -h localhost -P 3306 --protocol=tcp
追記(2019-01-24):ホスト側でDockerfileおよびdocker-compose.ymlとソースを分けたい方へ
ファイル構造(ホスト側)
sampleApp ---- Dockerfile
|-- docker-compose.yml
|
|-- src -- |-- app
|-- bin
|-- config
|-- db
|-- lib
|-- log
|-- public
|-- storage
|-- test
|-- tmp
|-- vendor
|-- config.ru
|-- Gemfile
|-- Gemfile.lock
|-- README.md
|-- Rakefile
Dockerfile
# 19.01.20現在最新安定版
FROM ruby:2.5.3
# railsコンソール中で日本語入力するための設定 <- NEW
ENV LANG C.UTF-8
# RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
# /var/lib/apt/lists配下のキャッシュを削除し容量を小さくする <- NEW
RUN apt-get update -qq && \
apt-get install -y build-essential \
libpq-dev \
nodejs \
&& rm -rf /var/lib/apt/lists/*
# 作業ディレクトリの設定
RUN mkdir /app_name
ENV APP_ROOT /app_name
WORKDIR $APP_ROOT
# gemfileを追加する
ADD ./src/Gemfile $APP_ROOT/Gemfile
ADD ./src/Gemfile.lock $APP_ROOT/Gemfile.lock
# gemfileのinstall
RUN bundle install
ADD ./src/ $APP_ROOT
docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
volumes:
- ./src/db/mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: root
ports:
- "3306:3306"
web:
build: .
command: rails s -p 3000 -b '0.0.0.0'
volumes:
- ./src:/app_name
ports:
- "3000:3000"
links:
- db
何もない状態からrailsサーバーとMySQLのコンテナを立ててくれるシェル(2019-02-04追記)
1. 任意の場所にアプリを作って行きたいフォルダ(作業ディレクトリ)を作成し、作ったフォルダ配下に移動
$ mkdir sampleApp
$ cd sampleApp
2. 以下のdocker-rails.shシェルをコピー、sampleAppフォルダ配下に置く
3. sampleAppフォルダ配下でシェルのファイルを実行
$ bash docker-rails.sh
#!/bin/bash
echo "docker pull ruby:2.5.3"
docker pull ruby:2.5.3
echo "docker pull mysql:5.7"
docker pull mysql:5.7
echo "docker images"
docker images
# make Dockerfile
cat <<'EOF' > Dockerfile
FROM ruby:2.5.3
ENV LANG C.UTF-8
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs && rm -rf /var/lib/apt/lists/*
RUN gem install bundler
WORKDIR /tmp
COPY src/Gemfile Gemfile
COPY src/Gemfile.lock Gemfile.lock
RUN bundle install
ENV APP_HOME /app_name
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
COPY . $APP_HOME
EOF
# make 'src' directory and cd 'src' directory
mkdir src && cd src
# make Gemfile
cat <<'EOF' > Gemfile
source 'https://rubygems.org'
gem 'rails'
EOF
# make Gemfile.lock()
touch Gemfile.lock
# cd ../
cd ../
# make docker-compose.yml
cat <<'EOF' > docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
volumes:
- ./src/db/mysql_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=root
ports:
- "3306:3306"
web:
build: .
command: rails s -p 3000 -b '0.0.0.0'
volumes:
- ./src:/app_name
ports:
- "3000:3000"
links:
- db
tty: true
stdin_open: true
EOF
echo "docker-compose run web rails new . --force --database=mysql --skip-bundle"
docker-compose run web rails new . --force --database=mysql --skip-bundle
# cd 'src'
cd src
# fix Gemfile
echo "fix Gemfile(uncoment mini_racer)"
cat Gemfile | sed "s/# gem 'mini_racer'/gem 'mini_racer'/" > __tmpfile__
cat __tmpfile__ > Gemfile
rm __tmpfile__
# cd ../
cd ../
docker-compose build
# cd src/
cd src/
# fix config/database.yml
echo "fix config/database.yml"
cat config/database.yml | sed 's/password:$/password: root/' | sed 's/host: localhost/host: db/' > __tmpfile__
cat __tmpfile__ > config/database.yml
rm __tmpfile__
# cd ../
cd ../
echo "docker-compose run web rake db:create"
docker-compose run web rake db:create
echo "docker-compose up"
docker-compose up