Help us understand the problem. What is going on with this article?

【Docker】Rails圧倒的環境構築&Herokuへ簡単デプロイ

Docker Advent Calendar 2019 の18日目。
どうもてぃです。
僕の好きな数字が 18 で、advent calendarを見たらちょうど空いてたので参戦いたしました。
しょーもない理由です。どうぞ、お手柔らかにおねがいします。

楽に環境構築したい。。。

弊社では基本バックRails・フロントReactでやっているのですが、毎度環境構築するのにみんな正直愛想を尽かしている次第です。
本番のことはとりあえず置いておいて、ローカル開発環境くらいは一瞬で作ってしまって、さっさとプロジェクトにジョインしたい。
そういった考えの元から、オレオレDockerfile/docker-compose.ymlでRails & PostgreSQL環境を一発で作ってしまおうという結論にいたりました。

人間楽をしたい生き物ですから、 退屈なことは自動化で瞬殺しましょう

やりたいこと

  • Rails new
  • bundle install
  • DB作成
  • サーバー起動
  • ブラウザ起動

以上を簡単なシェルスクリプトを流して実行します。

超絶簡単です。
猿でもできる環境構築。

実行環境

以下検証当初バージョン

  • elementary OS loki 0.4.1 (Ubuntu 16.04.5)
  • Docker version 17.12.0-ce, build c97c6d6
  • docker-compose version 1.20.1, build 5d8c71b

※可能であればdocker-composeのバージョンは1.20以上にしておいてください。

docker & docker-compose最新版適応

  • docker-compose version 1.25.1-rc1, build d92e9bee
  • Docker version 19.03.5, build 633a0ea838

この記事を書いてる際にdockerとdocker-composeのバージョンを最新にしたところ問題なく動きました。
殆どmacユーザーだとは思うのですが、念の為バージョンアップの方法を書いておきます。
以下必要のない人はgit cloneまで飛ばしてください。

※すんません、macについては未検証ですm(_ _)m

docker upgrade

# for mac
$ brew cask upgrade docker



# for linux(ubuntu)
$ sudo apt purge docker-ce

# インストール時にやっていれば飛ばしておk
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 同上
$ sudo add-apt-repository \
> "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
> xenial \
> stable"

$ sudo apt update; apt install docker-ce

$ docker -v
Docker version 19.03.5, build 633a0ea838

:tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada:

docker-compose upgrade

mac/linuxどちらも以下の手順でいけるはず。
こちらにアクセスし、自分の欲しいバージョンを見つけ、curl時にバージョンを指定してください。
今回は一番上にあった、 1.25.1-rc1 を使用します。

# docker-composeの場所確認
$ which docker-compose
/usr/local/bin/docker-compose

# docker-compose削除
$ sudo rm /usr/local/bin/docker-compose

# docker-compose 1.25.1-rc1をダウンロード
$ sudo curl -L https://github.com/docker/compose/releases/download/1.25.1-rc1/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

# docker-composeコマンドをsudoなしで利用できるように
$ sudo chmod +x /usr/local/bin/docker-compose

$ docker-compose -v
docker-compose version 1.25.1-rc1, build d92e9bee

:tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada:

git clone

ゼロから説明するのは今回の記事の趣旨に反するので、とりあえずGitHubにリポジトリを用意しました。
README.md 通りに実行すれば、サーバー起動まで上手くいくはずです(メモリが足りないとかなければ)

↓リンク
https://github.com/motty93/docker-rails-postgresql

(すんません、うまくいかなかったらissueあげてもらえると即対応します。)

手順

README.mdに手順書いてあるんですが、念の為こちらにも書いておきます。

$ git clone https://github.com/motty93/docker-rails-postgresql

$ cd docker-rails-postgresql/

$ sudo chmod 755 init.sh

$ ./init.sh

割と時間がかかるので、スクリプトを実行したら終わるまで大人しくtwitterやようつべを見てのんびりしておきましょう。

自動化シェル

とはいいつつも、ただ実行するコマンドを羅列しただけです。
最終的にはdocker-compose up -dでサーバーをデーモン起動し、ブラウザを立ち上げます。

#!/bin/bash

echo "rails new"
docker-compose run web rails _5.2.4_ new . --skip --database=postgresql \
  --skip-git --skip-bundle --skip-turbolinks --skip-coffee --skip-test

if [ "$(uname)" == 'Linux' ]; then
  echo "Linux chown all file"
  sudo chown -R $USER:$USER *
fi

echo "force files checkout"
git checkout README.md .gitignore

echo "fig build"
docker-compose build

if [ "$(uname)" == 'Linux' ]; then
  echo "Linux chown all file"
  sudo chown -R $USER:$USER *
fi

echo "bundle install"
docker-compose run web bundle install --path=vendor/bundle

echo "copy env setting"
cp ./docker/init/env_sample ./.env

echo "copy database.yml"
\cp -f ./docker/init/init_database.yml ./config/database.yml

echo "db create & migrate"
docker-compose run web rails db:create
docker-compose run web rails db:migrate

echo "fig up deamon"
docker-compose up -d

echo "browser open"
if [ "$(uname)" == 'Darwin' ]; then
  open "http://0.0.0.0:3000"
else
  xdg-open "http://0.0.0.0:3000"
fi

(windowsは想定してなかったので自動化できてませんすんません)

Dockerfile

FROM ruby:2.6.3
ENV LANG C.UTF-8
ENV APP_ROOT /myapp
ENV DEBCONF_NOWARNINGS yes

RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev \
    postgresql-client \
    nodejs \
    && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /tmp/* /var/tmp/*

RUN gem install -v 5.2.4 rails \
  && gem install bundler

WORKDIR /tmp

COPY Gemfile* /tmp/
RUN bundle install --clean \
    && mkdir ${APP_ROOT}

WORKDIR ${APP_ROOT}
ADD . ${APP_ROOT}/

CMD ["rails", "server", "-b", "0.0.0.0"]

至って平凡なDockerfileです。
Herokuへデプロイする際、Dockerfileの最後にサーバー起動コマンドがないとデプロイしてもアプリケーションエラーが発生してしまうため CMD ["rails", "server", "-b", "0.0.0.0"] を追記しています。
デプロイする予定の無い方は外していただいて問題ないです。

docker-compose.yml

version: '3'
services:
  postgres:
    image: postgres:10-alpine
    volumes:
      - postgresql-data:/var/lib/postgresql/data
      - ./docker/init/db:/docker-entrypoint-initdb.d
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
      - POSTGRES_PRODUCTION_DB
    ports:
      - '5432'
  web:
    build:
      context: .
      dockerfile: ./docker/rails/Dockerfile
    working_dir: /myapp
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -b 0.0.0.0 -p 3000"
    ports:
      - '3000:3000'
    volumes:
      - .:/myapp
      - /myapp/log
      - /myapp/.git
    environment:
      - POSTGRES_HOST
      - POSTGRES_PORT
      - POSTGRES_USER
      - POSTGRES_PASSWORD
    depends_on:
      - postgres
    tty: true
    stdin_open: true
volumes:
  postgresql-data:
    driver: local

postgresqlのvolumeに関して結構問題がありました(Linuxだとdockerの権限周りめんどい)が、上記の構成で上手く自動化まで持っていけました。
特に目立ったところのない平凡なdocker-compose.ymlですね。
今回、環境変数は.envを使用するため、environmentのように指定すれば勝手に使ってくれます。超便利〜。

初期設定関連ファイル

docker/initディレクトリ配下に入っています。

db/setup.sqlがpostgresqlの初期設定sql。
これがないと、実行ユーザーの権限がないやら、実行ユーザーのDBがないやら、postgresqlは遠慮なしに文句を行ってきます。
初期設定ユーザーの名前を変更したい場合、init.shを実行する前にsetup.sqlの中身を変更してください。

env_sampleは今回必要となる.envのサンプルファイル。
一応動くように環境変数を設定しています。
setup.sqlのユーザー・パスワードを変更した場合、こちらも変更しないとDBへ接続できないので注意してください。

init_database.ymlは環境変数に準じた設定をしています。
DB名を変更したい場合はrails new後、config/database.ymlを変更したらいいんじゃないすか。



以上、上記ファイル郡はinit.shが動いたときに適切な場面で適切な働きをしてくれます。
むしろ、最初以降は使い物にならないタダのゴミ使わないので、必要なければ初期スクリプト流した後削除してinitial commitしたらいいんじゃないすかね。

Heroku container deploy

Railsといえば、おなじみのHerokuさんです。
ここ半年は検証本番含め結構お世話になってます。
git push origin herokuってするのもいいんですが、せっかくDockerfile作ったんだから、コンテナデプロイしたくないですか?
てなわけで、公式を見てみましょう。

↓リンク
https://devcenter.heroku.com/articles/container-registry-and-runtime#getting-started

Getting startedのところだけを順に実行したらデプロイ完了です。

前準備

herokuへコンテナデプロイする際、アプリケーションルートにDockerfileがないとビルドしてくれません。
そのため、docker/rails/Dockerfileをアプリケーションルートへコピーします。

# docker/rails/Dockerfileをappルートへコピー
$ cp ./docker/rails/Dockerfile .

もう一点。
ローカルでコンテナが動いていると、heroku container:push後のアプリケーションクラッシュの一因になります。
念のため、コンテナを止めるか削除するかしておいてください。

僕は面倒くさがりなんでコンテナは毎回全削除してます。

$ docker rm -f `docker ps -a -q`

or

$ docker-compose down

念のため手順

$ heroku login

$ heroku container:login

$ heroku create

$ heroku container:push web

$ heroku container:release web

これだけ。
クソ簡単でしょ?
たのしいHeroku第1版 :book:

$ heroku open

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_139887_2e860399-ab7b-dfe1-3af8-063ab26fe9e0.jpeg

\(^o^)/\(^o^)/\(^o^)/\(^o^)/\(^o^)/\(^o^)/

herokuへpostgresqlのアドオンをいれる

heroku container:loginした後にpostgresqlのアドオンを入れましょう。
ただコンテナデプロイするだけじゃダメなんですよね。

$ heroku addons:create heroku-postgresql:hobby-dev

$ heroku open

これで簡単にデプロイができちゃいました。
パーフェクトHerokuContainer :book:

これでもダメだった場合

上記手順を踏んでも、Application Errorが起きる場合tmp/pids/server.pidが残っている可能性が非常に高いです。
削除して、デプロイの手順をもう一度踏んでください。

以下手順。

$ rm tmp/pids/server.pid

$ heroku container:push web

$ heroku container:release web

$ heroku open

Congratulation!!!

:tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada: :tada:

2019-12-17 17.41.05 からのスクリーンショット.png

記事を書くに当たり猛烈に躓いた点

LoadError: cannot load such file aciton_mailbox/engine

以前作成したDockerfileとdocker-compose.ymlを使用していたので全く問題なくいくとおもっていたのですが、なぜか上記でハマりました。
しかも検索しても全然出てこない。

色々調査していると、コンテナ内のrailsのバージョンが6.0.1になっており、自前で準備したGemfileのrailsと異なるバージョンになってしまっていました。

$ docker-compose run web rails -v #=> 5.2.4

$ docker run -it <image id> rails -v #=> 6.0.1

# は?

そりゃ、バージョン6系でもないのにaction_mailboxとか入れようとしてるからエラーになるわけですよね。
config/application.rbのrequireはずしてもダメでしたもん。

上記解決のため今回はDockerfilegem install railsする際にバージョン指定しています。
また、init.shのスクリプトでrails newする際にもバージョンを指定しています。
この二点はすげぇ大事です。とてつもなくね。

今回のポイント

  • Dockerfileでgem install railsをする際バージョン指定する
  • docker-compose run web rails new時もバージョン指定をする
  • PostgreSQLの実行ユーザーをdbコンテナができる際に作成されるようsqlファイルを作っておく
  • .env & database.ymlは予め作っておき、db:createが走る前に反映させる(自動化スクリプトで問題なくやってくれる)
  • 権限でつまづかないようにpostgresql volumesの設定に気をつける(Linuxのみ)
  • Gemfileは用意しておき、rails newの--skipオプションで上書きしないようにする

まとめ

今後同じリポジトリでrails 6.0.1にも対応する予定です(随時更新予定)
是非、環境構築につかれた方、簡単な検証環境をherokuに作りたい方、試してみてはいかがでしょうか!?

もっと改善できそうなところあればpull requestください。
よろしくお願いします。

参考

Heroku dev center Container Registry
dockerでPostgreSQLのコンテナ作成と初期化
"debconf: delaying package configuration, since apt-utils is not installed"を表示しないようにする
Action Mailbox の基礎
Heroku dev center Heroku PostgreSQL

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away