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
###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
##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版
$ heroku open
\(^o^)/\(^o^)/\(^o^)/\(^o^)/\(^o^)/\(^o^)/
herokuへpostgresqlのアドオンをいれる
heroku container:login
した後にpostgresqlのアドオンを入れましょう。
ただコンテナデプロイするだけじゃダメなんですよね。
$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku open
これで簡単にデプロイができちゃいました。
パーフェクトHerokuContainer
###これでもダメだった場合
上記手順を踏んでも、Application Error
が起きる場合tmp/pids/server.pid
が残っている可能性が非常に高いです。
削除して、デプロイの手順をもう一度踏んでください。
以下手順。
$ rm tmp/pids/server.pid
$ heroku container:push web
$ heroku container:release web
$ heroku open
##Congratulation!!!
##記事を書くに当たり猛烈に躓いた点
###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はずしてもダメでしたもん。
上記解決のため今回はDockerfile
でgem 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