DockerComposeでコンテナベースのRailsアプリを作成してHerokuにデプロイする


## はじめに

DockerComposeを使うとWebサーバーだけでなくPostgreSQLやRedisといった複数のDockerコンテナを組み合わせたアプリケーションを作成することができます。

DockerComposeで作成したアプリケーションを手元で動かすだけでなく、そのままHerokuにデプロイしてみました。

## 注意事項

- MacOS Catalinaで検証しています
- HerokuとDockerのアカウントをご用意ください
- 構築するRailsのバージョンは6.0.3、Rubyは2.7.1です
- DatabaseはPostgreSQLを使用します
- DockerのOSイメージはalpineを使用しています。

## DockerとDocker Composeのバージョン確認

手元の環境で、DockerとDocker Composeのバージョンを確認します。今回は以下のバージョンでのセットアップを想定します。

```
$ docker -v
Docker version 19.03.13, build 4484c46d9d
```

```
$docker-compose -v
docker-compose version 1.27.4, build 40524192
```

## DockerとHerokuへのログイン

Dockerイメージの取得や、Herokuへのデプロイができるように、あらかじめログインしておきます（[HerokuCLI](https://devcenter.heroku.com/articles/heroku-cli#download-and-install)をインストールしてください）。

```
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: *********
Password: *********
Login Succeeded
```

```
$ heroku login
Enter your Heroku credentials:
Email: ************
Password: ********
Two-factor code: ******
Logged in as **********
```

## 作業場所と必要なファイルの準備

作業ディレクトリを用意します。今回はmyappとしました。

```
$ mkdir myapp && cd $_
```

Gitでバージョン管理を行う場合は `git init` しておきましょう。（やらなくてもいいです）

```
$ git init
```

必要なファイルを空の状態で用意します。

```
$ touch Dockerfile docker-compose.yml Gemfile Gemfile.lock
```

用意したファイルの中身を記述していきます。
Dockerfileは以下のようにします。（`myapp`は任意のアプリケーション名で置換してください）

```Dockerfile
FROM ruby:2.7.1-alpine

ENV PACKAGES="build-base linux-headers libxml2-dev libxslt-dev curl-dev nodejs tzdata postgresql-dev postgresql yarn less" \
    HOME="/app"

WORKDIR $HOME

ADD Gemfile      $HOME/Gemfile
ADD Gemfile.lock $HOME/Gemfile.lock

RUN apk update && \
    apk upgrade && \
    apk add --no-cache $PACKAGES && \
    bundle install -j4

ADD . $HOME

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

続いて、docker-compose.ymlを編集します。

```docker-compose.yml
version: '3'
services:
  db:
    image: postgres:13.0
    environment:
      - POSTGRES_PASSWORD=password
    volumes:
      - db_data:/var/lib/postgresql/data # dbのデータを永続化します。無くても動きます。
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  db_data:
```

続いて、Gemfileを編集します。

```Gemfile
source 'https://rubygems.org'
gem 'rails', '6.0.3'
```

これで、Docker上でRailsアプリを動かす準備が整いました。

## Railsアプリケーションを作成する

Railsアプリを作成します。 `docker-compose run web xxx` は、 `web`というDockerコンテナで xxx コマンドを実行する、という意味です。

```
$ docker-compose run web rails new . --force --database=postgresql
```

## Docker上でRailsを起動する

PostgresのDockerコンテナと接続するために `config/database.yml` を編集します。

```yaml

default: &default
  adapter: postgresql
  encoding: unicode
  host: db           # 追記
  username: postgres # 追記
  password: password # 追記
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```

Dockerコンテナをビルドします。このアプリケーションに必要なDockerイメージ（Ruby, PostgereSQL）のダウンロードも行われます。

```shell
$ docker-compose build
```

データベースを作成します。

```shell
$ docker-compose run web rails db:create
```

アプリケーションを起動します。Webサーバーが起動します。

```shell
$ docker-compose up
```

ブラウザで、localhost:3000 に移動して確認しましょう。以下のページが表示されれば、ひとまずローカルでのアプリケーション起動は成功です！


![スクリーンショット 2020-11-11 17.53.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19401/4dbf651c-011b-6b23-d2fc-c2d34f666a3b.png)



## Herokuへデプロイする

作成したRailsアプリをHerokuにデプロイします。

ローカルでWebサーバーが動作している（pidsが存在する）と、herokuでWebサーバーが起動しない可能性があるので、一旦ローカルのサーバーを停止しておきます。また `server.pid` が存在する場合は消しておきます。

```
$ docker-compose down
$ rm tmp/pids/server.pid
```

Herokuのホスト名を許可しておきます。 （今回の場合Rails.envはdevelopmentになります）

```config/environments/development.rb
 config.hosts << ".herokuapp.com" # 追記
```

Herokuにアプリケーションを作成します。

```
$ heroku create
```

Heroku Container Registryにimageをアップロードするためにログインし、その後コンテナをpushします。

```
$heroku container:login
```

```
$ heroku container:push web
```

今回はDBにPostgreSQLを使用しているので、add-onを追加します。

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

pushしたアプリケーションをリリースします。

```
$ heroku container:release web
```

以上で完了です！ 以下のコマンドで公開されたアプリケーションが確認できます。

```
$ heroku open
```

## 成果物

最終的なコードをこちらに置きました。
https://github.com/akirakudo/heroku-docker-rails6

## 参考文献

- https://docs.docker.com/compose/rails/#define-the-project
- https://devcenter.heroku.com/articles/local-development-with-docker-compose
- https://devcenter.heroku.com/articles/container-registry-and-runtime