🚀

【Rails7】Dockerを使ってherokuにRailsアプリをデプロイする

2022/10/09に公開約8,200字

こんにちは!todakaです。
初めての投稿で緊張しますが、よろしくお願いします。🎉
今回はDockerでRailsアプリを構築し、Herokuにデプロイするまでの手順を記事に残したいと思います。

今回やりたいこと

  • Dockerを使ってRailsアプリを立ち上げる。
  • Dockerを使ってherokuにRailsアプリをデプロイする。
    • herokuのコンテナレジストリを使ってDockerデプロイをする。

環境

今回使用する環境は下記の通りです。

Docker
Ruby: 3.1.2
Rails 7.0.4

ローカルでRailsアプリを作成する

1. Railsアプリの作成

まずはRailsアプリをを作成します。
今回はDaisyUIを使いたいので、importmapではなく、jsbundling-railsとcssbundling-railsを使います。

$ mkdir sample-app
$ cd sample-app
$ rails new . -T -d mysql -j esbuild --css tailwind

https://zenn.dev/yoiyoicho/articles/410a7e3fd892b5

2. Docker関連の設定

ひとまずローカルで使うためのDockerの設定をします。Docker Composeも使いますので、そのへんも一緒に作っていきます。公式のリファレンスは貼りますが、お世話になっているコミュニティの課題のものがベースになっています。

本番環境のための修正は後ほどします。

touch {Dockerfile,docker-compose.yml,endpoint.sh}

Dockerfile

Dockerfile
FROM ruby:3.1.2
ARG ROOT="/sample_app"
ENV LANG=C.UTF-8 TZ=Asia/Tokyo

WORKDIR ${ROOT}

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update; \
    curl -sL https://deb.nodesource.com/setup_16.x | bash -; \
    curl -Ss https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -; \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list; \
    apt-get update -qq && \
    apt-get install -y --no-install-recommends \
		  vim=2:8.2.2434-3+deb11u1 \
          mariadb-client=1:10.5.15-0+deb11u1 \
          tzdata \
          nodejs \
          yarn \
            && apt-get clean \
            && rm -rf /var/lib/apt/lists/*
            
COPY Gemfile ${ROOT}
COPY Gemfile.lock ${ROOT}
RUN gem install bundler:2.3.22;\
    bundle install --jobs 4

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

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

docker-compose.yml

docker-compose.yml
version: "3.9"

services:
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/sample_app:cached
      - bundle:/usr/local/bundle
    ports:
      - 3000:3000
    depends_on:
      - db
    stdin_open: true
    tty: true
  db:
    image: mysql:5.7.33
    environment:
      MYSQL_ROOT_PASSWORD: "mysql"
    ports:
      - 3306:3306
    volumes:
      - mysql_data:/var/lib/mysql
volumes:
  bundle:
  mysql_data:

entrypoint.sh

entrypoint.sh
#!/bin/bash
set -e
rm -f /sample_app/tmp/pids/server.pid
exec "$@"

https://docs.docker.jp/engine/reference/builder.html
https://docs.docker.com/samples/rails/
https://qiita.com/MasatoraAtarashi/items/3f0317cd648ff63fa92c
Dockerを起動し、おなじみのRailsの画面が出てくればOKです🎉

$ docker-compose build
$ docker-compose run web rails db:create
$ docker-compose up -d

Image from Gyazo

3. サンプルページの作成とDaisyUIの適用

ローカルでlocalhost:3000にアクセスするとおなじみの画面が出てきますが、この画面は本番環境では表示されないため、サンプルページを作る必要があります。
ここではサンプルページを作成し、DaisyUIが適用されるようにします。

DaisyUIを導入する

yarnを使ってDaisyUIを導入し、関連する設定をします。

$ yarn add daisyui
$ yarn tailwind init -p

tailwind.config.jsに追記します。

tailwind.config.js
module.exports = {
  content: [
    './app/views/**/*.html.erb',
    './app/helpers/**/*.rb',
    './app/assets/stylesheets/**/*.css',
    './app/javascript/**/*.js'
  ],
  plugins: [require("daisyui")], // 追記
}

https://daisyui.com/docs/install/

サンプルページを作る

サンプルページを作ります。

$ rails g controller sample index

routes.rbを設定します。

config/routes.rb
Rails.application.routes.draw do
  root 'sample#index' # 追記
end

ビューファイルを適当に作成し、DaisyUIのボタンを配置します。

app/views/sample/index.html.erb
<h1>Welcome to Sample App</h1>
<button class="btn btn-primary">Join us!</button>

ローカル環境できちんと動作するか確認します。
ボタンにDaisyUIが適用されていればOKです。

$ docker-compose down
$ docker-compose build
$ docker-compose up -d

Image from Gyazo
もしDaisyUIが適用されていなければ、bin/devを実行します。

$ bin/dev

herokuへのデプロイの準備

次にherokuへのデプロイの準備をしていきます。

1. heroku CLIのインストール

heroku CLIがインストールされていない場合はインストールします。

$ brew tap heroku/brew && brew install heroku

https://devcenter.heroku.com/ja/articles/heroku-cli

2. heroku CLIでログイン

$ heroku login

3. herokuでアプリを新規作成

アプリ名を指定しなければ、一意のアプリ名を指定されます。

$ heroku create

4. DB用のアドオンを追加

今回はMySQLを使います。アドオンはClearDBを追加します。

$ heroku addons:create cleardb:ignite

これにより、CLEARDB_DATABASE_URLという環境変数が追加されます。

$ heroku config
CLEARDB_DATABASE_URL: mysql://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]?reconnect=true

この環境変数の値を、DATABASE_URLという環境変数に登録します。gemはmysql2を使っているかと思いますので、mysql2://から始める値に書き換えます。

$ heroku config:add DATABASE_URL='mysql2://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]?reconnect=true'

解説記事によってはconfig/database.ymlを書き換えたり、herokuに様々な環境変数を登録する手法が紹介されていますが、Rails4.1以降では環境変数DATABASE_URLを登録するだけで、接続情報を読み取ってくれるようです。
https://zenn.dev/kino_puehddby/articles/21a3cf0aacee7c

5. 本番のための諸々の設定

本番環境で必要なこと

開発環境では、アプリコードの変更を随時コンテナに取り込む必要があります。docker-compose.ymlによってホストデータがコンテナにマウントされているので、コンテナは随時新しいコードを参照することができます。(上記のDockerfileで問題なく動作します)

docker-compose.yml
services:
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/sample_app:cached
      - bundle:/usr/local/bundle
# 省略

ただ、本番環境ではホスト(ローカル)の情報をコンテナにマウントできないので、本番環境ではアプリコードをコンテナにコピーする必要があります。

Dockerfile
COPY Gemfile ${ROOT}
COPY Gemfile.lock ${ROOT}
COPY . ${ROOT} # これを追記

方針など

今回はHeroku Container Registryを使い、Dockerデプロイします。
https://devcenter.heroku.com/ja/articles/container-registry-and-runtime

当初はDockerfileを開発用と本番用で共用にしたかったのですが、私のDockerに対する理解不足もあり、今回は別々のDockerfileを設定しました。いずれチャレンジしたいと思います( ;∀;)
ほんとはこの記事のようにしたかったのです・・・
https://core-tech.jp/blog/tech_log/4414/

手順

DockerfileにCOPY . ${ROOT}を追記します。

Dockerfile
FROM ruby:3.1.2
ARG ROOT="/sample_app"
ENV LANG=C.UTF-8 TZ=Asia/Tokyo

WORKDIR ${ROOT}

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update; \
    curl -sL https://deb.nodesource.com/setup_16.x | bash -; \
    curl -Ss https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -; \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list; \
    apt-get update -qq && \
    apt-get install -y --no-install-recommends \
		  vim=2:8.2.2434-3+deb11u1 \
          mariadb-client=1:10.5.15-0+deb11u1 \
          tzdata \
          nodejs \
          yarn \
            && apt-get clean \
            && rm -rf /var/lib/apt/lists/*

COPY Gemfile ${ROOT}
COPY Gemfile.lock ${ROOT}
COPY . ${ROOT} # 追記
RUN gem install bundler:2.3.22;\
    bundle install --jobs 4

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

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

Dockerfileを本番用にしましたので、開発用のDockerfileを別に設定しました。内容は最初に設定したのものと同じです。

Dockerfile.development
# 割愛

docker-compose.ymlに開発時に使用するDockerfileを指定します。

docker-compose.yml
version: "3.9"

services:
  web:
    build: 
      context: . # 追記
      dockerfile: Dockerfile.development # 追記

6. その他修正

本番環境でBlocked Errorを回避するため、以下を追記します。今回はエラーが発生したのち、あとから追記しました。
Image from Gyazo

config/environments/development.rb
Rails.application.configure do
  # 省略
  config.hosts << 'ホスト名' # 追記
  # 省略
end

https://qiita.com/kodai_0122/items/67c6d390f18698950440

herokuへのデプロイと動作確認

1. heroku container registryにデプロイする

コンテナレジストリにログインする

$ heroku container:login

イメージをプッシュ&リリースする。

$ heroku container:push web
$ heroku container:release web

https://devcenter.heroku.com/ja/articles/container-registry-and-runtime

2. 動作確認

$ heroku open

終わりに

Dockerfileについては試行錯誤しましたが正しく動作せず、結果的にチャレンジできずじまいです。
ひとまずデプロイできたので安心しましたが、イメージがまだまだ大きいので改善の余地はあるかと思います。
Docker難しいぃ!・・・・・けどなんだかんだ面白いですね。
修正したらこの記事にも反映させますのでご了承ください。

ご意見や誤り箇所があればコメントいただけると嬉しいです!

Discussion

ログインするとコメントできます