Ruby
Rails
MySQL
docker
docker-compose

1時間以内に作れる!Dockerで作る最強の開発環境の作成~Mac~(Ruby on Rails編)

1時間以内に作れる!Dockerで作る最強の開発環境の作成~Mac~(Ruby on Rails編)

Ateam Hikkoshi Samurai Inc. Advent Calendar 201711日目です。
本日はエイチーム引越し侍の新卒4年目、Webエンジニアの@zwirkyが担当します。

Dockerについて

Dockerについての説明は割愛します。
(なぜなら1時間以内で開発開発を作らないといけないためw)

知りたいかたは、こちらをご覧ください。
Dockerとは??

また、昔自分が書いた記事でDockerを簡単に触ってみる入門編も書いているので、そちらも合わせてみてみてください。
Dockerを導入する(CentOS版)

実際に作ってみる

① Docker Community Edition for Macのインストール(10分)

Macで簡単にDockerを使えるようにするために、Docker Community Edition for Macというものを提供してくれています。
Docker Community Edition for Macの中には、Docker環境を構築や運用するためのアプリケーションやツールが詰まっており、
pkgでインストールすればすぐにDockerを触る事ができます。

Docker Community Edition for Mac

多分、そこまで苦労せずにインストールができると思います。

今回いれるDocker Community Edition for Macのインストール時に選択するツールは下記のようになります。

ツール 説明
Docker Client Dockerを操作するコマンドツール
Docker Machine Docker仮想マシンを簡単に構築するためのツール
Docker Compose 複数のDocker(コンテナ)を操作するためのツール
Docker Kitematic DockerをGUIで操作するためのツール
Docker Quickstart Terminal Dockerコマンドをすぐに利用できるターミナル

インストールが完了したら、下記のコマンドを打ってみてください。
Dockerが使えるようになっているはずです。

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete 
Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
Status: Downloaded newer image for hello-world:latest

・・中略・・

For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/

② Dockerイメージのダウンロード(10分)

今回は、開発環境なのでちょっとシンプルに下記の構成でいこうと思います。

  • Ruby(2.4.2)
  • MySQL(5.7.20)
  • Nginx(1.12.2)

とりあえず、2017/12/01時点での最新版です!

$ docker pull ruby:2.4.2
$ docker pull mysql:5.7.20
$ docker pull nginx:1.12.2

上記を行うことで、Docker ImageをDocker Hubから取得して保存してくれます。
落としたImageはこちらで確認。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               5.7.20              dd0afb9bc4a9        3 days ago          408MB
ruby                2.4.2               5dce8a4be4f6        11 days ago         687MB
nginx               1.12.2              db5c5ed76327        5 weeks ago         108MB

③ プロジェクトの準備(1分)

作業用ディレクトリを作成

$ mkdir ~/work_dir/containers

work_dirは適当な名前でOKです。

今回の目指すフォルダ構成は下記になります。

.
├── Gemfile
├── Gemfile.lock
├── containers
│   ├── mysql
│   │   ├── Dockerfile
│   │   ├── my.cnf
│   │   └── password.yml
│   ├── nginx
│   │   ├── Dockerfile
│   │   ├── default.conf
│   │   └── nginx.conf
│   └── ruby
│       └── Dockerfile
└── docker-compose.yml

④ Ruby(Railsを利用するための)コンテナの設定(5分)

Railsを触るための準備をしましょう。

GemfileとGemfile.lockの作成

$ vim ~/work_dir/Gemfile
Gemfile
source 'https://rubygems.org'

# 最新版のRailsを使用
gem 'rails', '5.1.0'
$ touch ~/work_dir/Gemfile.lock

rubyコンテナ用のディレクトリ作成

$ mkdir ~/work_dir/containers/ruby

Dockerfileの作成

$ vim ~/work_dir/containers/ruby/Dockerfile
Dockerfile
FROM ruby:2.4.2
RUN apt-get update -qq && apt-get install -y apt-utils \
    build-essential libpq-dev nodejs mysql-client
RUN mkdir /app
WORKDIR /app
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN bundle install -j4 
ADD . /app

EXPOSE 3000    

※ work_dirとapp_nameは変更してください

コマンドのそれぞれの意味を知りたい人はこちらのDockerfileのリファレンスからどうぞ

⑤ MySQLコンテナの設定(5分)

MySQLコンテナ用のディレクトリ作成

$ mkdir ~/work_dir/containers/mysql

設定ファイルの作成

$ vim ~/work_dir/containers/mysql/my.cnf
my.cnf
[mysqld]

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

symbolic-links=0

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

character-set-server = utf8

[client]
default-character-set = utf8

[mysqldump]
default-character-set = utf8

[mysql]
default-character-set = utf8

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

Dockerfileの作成

$ vim ~/work_dir/containers/mysql/Dockerfile
Dockerfile
FROM mysql:5.7.20
RUN apt-get update && apt-get install -y apt-utils locales && \
    rm -rf /var/lib/apt/lists/* && echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen && \
    locale-gen ja_JP.UTF-8
ENV LC_ALL ja_JP.UTF-8
ADD mysql/my.cnf /etc/my.cnf

※ work_dirは変更してください

⑥ Nginxコンテナの設定(5分)

Nginxコンテナ用のディレクトリ作成

$ mkdir ~/work_dir/containers/nginx

設定ファイルの作成

$ vim ~/work_dir/containers/nginx/nginx.conf
nginx.conf
user  nginx;
worker_processes  2;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
    multi_accept on;
    use epoll;
}
http {
    server_tokens off;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for $request_time"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip_static  on;
    gzip  on;
    gzip_types image/png image/gif image/jpeg text/javascript text/css;
    gzip_min_length 1000;
    gzip_proxied any;
    gzip_comp_level 9;
    gunzip on;
    include /etc/nginx/conf.d/*.conf;
}
$ vim ~/work_dir/nginx/default.conf
default.conf
server {
    listen       80;
    server_name  localhost;

    location / {
      proxy_pass http://localhost:3000;
    }
}

Dockerfileの作成

$ vim ~/work_dir/containers/nginx/Dockerfile
Dockerfile
FROM nginx:1.12.2
ENV LANG ja_JP.UTF-8
RUN apt-get update -qq && apt-get install -y apt-utils locales && \
    sed -i -e 's/# ja_JP.UTF-8/ja_JP.UTF-8/g' /etc/locale.gen && \
    locale-gen ja_JP.UTF-8

ENV LC_TIME C
ADD nginx.conf /etc/nginx/nginx.conf
ADD default.conf /etc/nginx/conf.d/default.conf

※ work_dirは変更してください

⑦ 各コンテナをつなぐための設定〜Docker Compose〜(5分)

設定ファイルの作成

$ vim ~/work_dir/containers/mysql/password.yml
password.yml
version: '2'
services:
  password:
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: hoge
      MYSQL_PASSWORD: password
      TZ: "Asia/Tokyo"

※ hogeとpasswordは変更してください

docker-compose.ymlの作成

$ vim docker-compose.yml
Dockerfile
version: '2'
services:
  datastore:
    image: busybox
    volumes:
      - /share
      - ./containers/mysql/volumes:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro
  server:
    build:
      context: .
      dockerfile: ./containers/nginx/Dockerfile
    ports:
      - '80:80'
    volumes_from:
      - datastore
    depends_on:
      - datastore
  web:
    build:
      context: .
      dockerfile: ./containers/ruby/Dockerfile
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - '3000:3000'
    volumes:
      - .:/app
      - /etc/localtime:/etc/localtime:ro
    volumes_from:
      - datastore
    depends_on:
      - db
    links:
      - db
      - db:database
      - db:mysql
    extends:
      file: ./containers/mysql/password.yml
      service: password
  db:
    build:
      context: .
      dockerfile: ./containers/mysql/Dockerfile
    ports:
      - '3306:3306'
    volumes_from:
      - datastore
    depends_on:
      - datastore
    extends:
      file: ./containers/mysql/password.yml
      service: password

※ work_dirは変更してください

⑧ 起動を確認(5分)

コンテナ内にアプリを作成する

$ docker-compose run web rails new . --force --database=mysql --skip-bundle

これを実行すると、フォルダ内にRailsのファイルが生成されます。

config/database.ymlの作成

$ vim config/database.yml
database.ymll
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: password
  host: db

実行しましょう!

$ docker-compose up

!!注意!!
もし、うまくいかない場合は、Docker内でファイルが更新できていないかもしれないです。
そのときは、

$ docker-compose build

これで、Gemfileやその他修正したものが反映されるはずです。

また、上記をやっても、DBが作成されていないので、下記のコマンドも打ってください。

$ docker-compose run web rails db:create

では、ブラウザを開くと、出てくると思います。
ブラウザでlocalhostを叩いてください!(完成です!!)

その他メモ

コンテナの削除

$ docker rm {CONTAINER ID}

イメージの削除

$ docker rmi {IMAGE ID}

Gemfileを変更したとき

$ docker-compose build
$ docker-compose up

イメージの状況確認

$ docker ps -a

Railsコマンドの例

$ docker-compose run web rails g controller hoge index

まとめ

ネット環境で時間のかかり方は人それぞれだと思いますが、おそらく1時間以内でできたのではないでしょうか??
Docker使えば、Macの中を汚さずに、仮想コンテナ上にミドルウェアを閉じ込めて使えるのでとてもA型の自分にとってはとてもありがたい話です。
また、imageが豊富なので、新しいバージョンを試すときも、imageをバージョン指定してとってくればすぐに利用することができます。
今回の記事の用にDockerを触ってみると、なんとなくDockerを知ってたひとも触ったことない人もDockerの全体像が見えてきたのではないでしょうか??
Dockerで開発をしていきましょう!

最後に

Ateam Hikkoshi Samurai Inc. Advent Calendar 2017 11日目いかがでしたでしょうか。
明日はエイチーム引越し侍の新卒1年目、期待の新星@ueki05が 入社1年目エンジニアがインターンシップで関わって感じたことに関する記事を書いてくれます。
お楽しみに。

追伸

株式会社エイチーム引越し侍では、一緒にサイト改善をしてくれるWebエンジニアを募集しています。エイチームグループのエンジニアとして働きたい!という方は是非、以下のリンクから応募してください。
皆様からのご応募、お待ちしております!!

エイチームグループ採用サイト(Web開発エンジニア職)