DockerでRails環境を構築する
最近副業でRailsを始めたので勉強がてらRailsやろうとなったので、Dockerで環境構築してみました。
構成
下記構成で作成します。
- Ruby
- Nginx
- MySQL
ディレクトリ構造はこんな感じです。
Railsの動作環境の作成
Rails用のDockerfileの作成
まずはDockerfile
を作成します。
src
ディレクトリを作成し、中にDockerfile
を作成。
内容は下記の様にします。
# マルチステージビルドでNode入れる
FROM node:14-alpine as node
FROM ruby:2.7
# nodeとyarnコピー
COPY --from=node /opt/yarn-* /opt/yarn
# シンボリックリンクはる
RUN ln -fs /opt/yarn/bin/yarn /usr/local/bin/yarn
RUN apt-get update && \
apt-get install -y git vim less build-essential graphviz cron bash g++ nodejs && \
apt-get clean
#Railsアプリのルートディレクトリ作成
ENV RAILS_ROOT /var/www/src
RUN mkdir -p $RAILS_ROOT
WORKDIR $RAILS_ROOT
RUN mkdir -p $RAILS_ROOT/tmp/sockets && mkdir -p $RAILS_ROOT/tmp/pids
RUN node -v && yarn -v
# ホストのGemfileのコピー
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install --jobs 20 --retry 5
解説はコメントにある通りですが、ベースイメージにruby:2.7
を使用します。
なにが使えるかや、どんなイメージが有るかはDockerHubを見ます。
Railsは使用するのにNode.jsが必要です。 そのため、マルチステージビルドというのを利用します。
簡単に言うと、フォルダ内部のファイル移動と似たようなイメージです。
FROM node:14-alpine as node
でnodeの環境ビルドされるので、そこからnodeを使うためのものを全部移動しましょう的なことです。
あとは、Railsで使うもの入れてます。
/tmp/sockets
はUnixソケットでnginxと通信したいので配置用のフォルダです。
RUN node -v && yarn -v
は仮にnodeやyarnがなかったときにビルドの途中で落としたいのでいれてます。
Gemfileの作成
src
内にGemfile
とGemfile.lock
を作成します。仮に既存のプロジェクトの場合はここに配置します。
Gemfile
は下記の様にしておきます。Gemfile.lock
は空で大丈夫です。
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.7.3'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.1.0'
docker-compseを作成しnginxとMySQLと連携する
作業ディレクトリ(src
の1つ上)内にdocker-compose.yml
を作成します。
内容はこんな感じです。
version: '3'
networks:
rails:
volumes:
db-volume:
bundle-data:
tmp-data:
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
ports:
- ${APP_PORT:-80}:80
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./nginx/logs:/var/log/nginx
- tmp-data:/var/www/src/tmp
depends_on:
- rails
networks:
- rails
rails_db:
image: mysql:8.0
container_name: rails_db
command: --default-authentication-plugin=mysql_native_password
ports:
- ${DB_PORT:-3360}:3306
volumes:
- db-volume:/var/lib/mysql
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
networks:
- rails
rails:
container_name: rails
build:
context: ./src
dockerfile: Dockerfile
depends_on:
- rails_db
volumes:
- .:/var/www
- bundle-data:/usr/local/bundle
#ソケット通信用ファイルをnginxコンテナと共有
- tmp-data:/var/www/src/tmp
command: puma -b unix:/var/www/src/tmp/sockets/puma.sock
environment:
TZ: 'Asia/Tokyo'
DB_HOST: rails_db
DB_DATABASE: ${DB_DATABASE}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
networks:
- rails
まずはnginxから nginxのイメージをそのまま利用します。 設定ファイルをバインドマウントしてます。UnixソケットはRailsコンテナのが必要なので、名前付きボリュームで共有しています。 その他エラー時に対応したいのでlogもバインドしてます。 設定ファイルは後述します。
次にMySQLです。
MySQLのイメージをそのまま利用します。
command
で認証方式を変更しています。
あとは環境変数の設定しています。
次にRailsです。
build
に先程作成したDockerfileを指定します。
tmp-data
にはpuma
のソケット場所をしています。
そして、command
でUnixソケットで接続するように指定します。
railsのpuma.rb
を指定してもいいのですが、記載不要で対応したいのでcommand
で行います。
環境変数
環境変数を設定していきます。
${DB_PASSWORD}
のようになってる箇所ですね。
作業ディレクトリ内に.env
を作成します。
DBの接続情報を記載します。DB_HOST
はrailsにわたすようにMySQLのコンテナ名を記載します。
DB_PORT=3360
DB_DATABASE=rails
DB_USERNAME=homestead
DB_PASSWORD=secret
DB_HOST=rails_db
nginx設定
作業ディレクトリにnginx
ディレクトを作成します。
default.conf
を作成します。
default.conf
の内容は下記です。
upstream rails_app {
# ソケット通信したいのでpuma.sockを指定
server unix:/var/www/src/tmp/sockets/puma.sock;
}
server {
listen 80;
# ドメインもしくはIPを指定
server_name localhost;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# ドキュメントルートの指定
root /var/www/src/public;
client_max_body_size 100m;
error_page 404 /404.html;
error_page 505 502 503 504 /500.html;
try_files $uri/index.html $uri @rails;
keepalive_timeout 5;
location ~ /\. {
deny all;
}
location ~* ^.+\.(rb|log)$ {
deny all;
}
# リバースプロキシ関連の設定
location @rails {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://rails_app;
}
}
ソケット通信の設定とログの出力先を設定しています。
RailsでMySQLの接続情報
src/config/database.yml
からDBの接続情報を変更します。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
database: <%= ENV.fetch('DB_DATABASE', 'rails') %>
username: <%= ENV.fetch('DB_USERNAME', 'homestead') %>
password: <%= ENV.fetch('DB_PASSWORD', 'secret') %>
host: <%= ENV.fetch('DB_HOST', 'rails_db') %>
起動する
あとは起動しましょう! Railsの新規プロジェクトの場合は下記の様にプロジェクトを作成しましょう。 オプションは自分がイラないもの省いているのと、データベースをMySQLで作成してます。
docker-compose run --rm rails rails new . --force --database=mysql --skip-test --skip-turbolinks
プロジェクトができたら、docker-compose up -d --build
でコンテナを全部立ち上げます。
http:localhost
でアクセスできたらOK!
502が出たらnginxのエラーログを見てみましょう!