2018/9 DcokerでRails環境構築

前回、Dcokerの基本的な使い方をPostgreSQLを例に紹介しました。 今回は、より実践的なRails環境構築する方法を紹介します。

## プロセスポリシー ここでDockerのポリシーについて説明します。 Vagrantでは1つのVM内に、PostgreSQLとRailsを同居させて紹介しました。 しかし、Dockerでは1コンテナ・1プロセスポリシーがありPostgreSQLとRailsは別のコンテナ、つまり別のDockerfileで構築します。 このポリシーは各ソフトウェアを同居させると、同じ依存ライブラリ使うけどバージョン違うので問題が発生する。というケースを避けるためでもあるようです。

準備

Dockerfile置き場作成

前回はmy_project直下にDockerfileを配置しました。 しかし今回はPostgreSQLとRails用の2つのDockerfileを準備するので、まずDockerfile置き場を作ります。 (作らなくても動きますが、作っといたほうがわかりやすいです。)

> cd my_project
> mkdir docker_file

PostgreSQL Dockerfile作成

前回と同じ内容です。my_project/docker_file配下にDockerfile_postgresという名前のファイルで配置します。

FROM postgres:9.5

# 基本
ARG base_timezone="Asia/Tokyo"
ARG work_dir="/usr/local/share"
# PostgreSQL
ARG dbuser="postgres"
ARG dbpass="postgres"
ARG dbname="sample"

# 基本 ###################################
# locale設定
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

# timezone設定
ENV TZ="${base_timezone}"

# postgres ###################################
ENV POSTGRES_USER="${dbuser}"
ENV POSTGRES_PASSWORD="${dbpass}"
RUN echo "create database ${dbname}_development;" >> /docker-entrypoint-initdb.d/createdb.sql
RUN echo "create database ${dbname}_test;" >> /docker-entrypoint-initdb.d/createdb.sql

Rails Dockerfile作成

公式のRuby2.4イメージがベースです。 ただRailsを動かすにはNode.jsが必要です。 このRuby公式イメージにNode.jsをRUNコマンド等を使ってインストールするのもよいですが普通に手間です。

そこでDockerにはマルチステージビルドという機能を使います。 これはベースイメージに局所的に別のベースイメージを繋げて利用できます。 今回はRubyイメージに、公式Node.js v8イメージのNodeとYarnコマンドをCOPY --from=nodeで連結しました。 これでNode.jsをインストールせずとも、Node.jsを利用できます。

my_project/docker_file配下にDockerfile_railsという名前のファイルで配置します。

FROM node:8 AS node
FROM ruby:2.4

# 基本
ARG base_timezone="Asia/Tokyo"
ARG work_dir="/usr/local/share"
ARG DEBIAN_FRONTEND=noninteractive
# Node.js
ARG yarn_version="1.9.4"
# Rails
ARG rails_version="5.1.4"

# 基本 ###################################
RUN apt-get update
RUN apt-get -y install apt-utils --no-install-recommends

# locale設定
RUN apt-get -y install locales
RUN locale-gen ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LC_CTYPE ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP.utf8

# timezone設定
ENV TZ="${base_timezone}"

# Rails ###################################
# Node.js multi-stage build
COPY --from=node /opt/yarn-v${yarn_version} /opt/yarn/
COPY --from=node /usr/local/bin/node /usr/local/bin/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg

# Postgresで接続
RUN apt-get install -y postgresql-client --no-install-recommends
RUN rm -rf /var/lib/apt/lists/*

# Railsインストール
RUN gem install rails --version="~>${rails_version}"

# ポート解放
EXPOSE 3000

yarnのバージョンは新しくなっているのかもしれません。 https://hub.docker.com/_/node/ からgithubのDockerfile(8/stretch/Dockerfile)のYARN_VERSIONを確認してください。

Docker Compose作成

Dockerfileが複数個ある場合、それぞれに対してdocker startして起動するのは不便です。 そこでDocker Composeという機能を利用して、起動・終了を一括で行えるようにします。 こちらはDockerfileとは異なりmy_project直下にdocker-compose.ymlという名前のファイルで配置します。

version: "3"

services:

  pg:
    container_name: sample_pg
    build: 
      context: ./docker_file
      dockerfile: Dockerfile_postgres
    ports: 
      - 15432:5432

  rails:
    container_name: sample_rails
    build: 
      context: ./docker_file
      dockerfile: Dockerfile_rails
    ports: 
      - 3000:3000
    depends_on:
      - pg
    links:
      - pg:postgres
    volumes:
      - "./src:/www"
    stdin_open: true

Postgre用のDockerfile_postgresを指定、ポートを15432で開放。 Railsも同様に指定し

起動順序を指定したり、コンテナ間接続ができるのは便利ですね。

Docker Compose使い方

ビルド

PostgreSQLとRails用コンテナ作成のために一度にビルドします。

> cd my_project
> docker-compose build

操作

# 起動
> docker-compose up -d

# RailsにSSH接続(container_nameのsample_railsではなくrails)
> docker-compose exec rails bash

# コンテナ内
$ cd /www

# Rails起動
$ rails s

# コンテナ内からログアウト
$ exit

# 終了
> docker-compose stop

本当は、Rails起動する前にbundle installしたりwebpack-dev-server起動する手順がありますが、 今回はあくまでVagrantでRails環境を構築する方法の紹介なので省きます。

構築した環境の配布

上記のように、基盤構築担当者が各Dockerfileとdocker-compose.ymlを準備します。 そして、チームメンバにDockerfileとdocker-compose.ymlを配布し

してもらえば、あっというまに開発環境が整えられます。

最後に

DockerはVagrantに比べて記述量が少ないだけでなく

と準備の手間や保守性にも優れていることがおわかりいただけたと思います。