HerokuでRailsの本番環境を作成する

f:id:y-ohgi:20181027023516p:plain

概要

Heroku x Ruby on Rails x PostgreSQL の構成でサービスを運用する機会があったのでそのメモ

Components

  • Ruby 2.5.1
  • Rails 5.2.1
  • Postgres 10.4
  • DockerCE 18.06

localの構築

railsの用意

Railsrubyもローカルに仕込みたくなかったのでDockerfileで片付けた。

$ cat <<EOL | docker build -t rails -
FROM ruby:2.5-alpine

ENV LANG C.UTF-8

WORKDIR /app

RUN set -x\
  && apk add --no-cache --update \
    libxml2-dev \
    libxslt-dev \
    libstdc++ \
    tzdata \
    nodejs \
    nodejs-npm \
    build-base \
    linux-headers \
    ca-certificates \
    postgresql-dev \
    mysql-client \
    mysql-dev \
    git \
    curl-dev \
  && gem install bundler rails\
  && npm install -g yarn

EXPOSE 3000
EOL
$ docker run -v `pwd`:/app rails new . --database=postgresql

or

$ docker run -it -v `pwd`:/app yohgi/railscmd rails new . --database=postgresql

yohgi/railscmd - Docker Hub

docker-composeの用意

docker-composeでざっくり動くものを構築する

まずは Dockerfile の記述

FROM ruby:2.5-alpine

ENV LANG C.UTF-8

WORKDIR /app
COPY . .

RUN apk add --no-cache --update \
    libxml2-dev \
    libxslt-dev \
    libstdc++ \
    tzdata \
    nodejs \
    nodejs-npm \
    build-base \
    linux-headers \
    ca-certificates \
    postgresql-dev \
    protobuf-dev \
    less \
  && gem install bundler \
  && bundle install \
  && npm install -g yarn \
  && yarn install
#XXX: 本番でこのイメージを用いる場合はユーザーを作成する。
#       ローカルで色々考えたくないのでrootで起動

EXPOSE 3000

次に docker-compose.yaml の記述

version: "3"

services:
  web:
    build: .
    restart: always
    tty: true
    stdin_open: true
    depends_on:
      - db
    ports:
      - 3000:3000
    volumes:
      - './:/app:cached'
    environment:
      - RAILS_ENV=development
      - DATABASE_HOST=db
      - DATABASE_USER=postgres
      - DATABASE_PASS=
    command: ash -c "rm -f /app/tmp/pids/server.pid; bundle exec rails s -p 3000 -b '0.0.0.0'"

  db:
    image: postgres:10.4-alpine
    volumes:
       - ./postgres:/var/lib/postgres
    ports:
       - 15432:5432
 

最後に config/database.yml を編集。
それぞれ、 developmenttest 環境はdocker-composeへ、 production 環境はHerokuへ対応もする。

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['DATABASE_USER'] %>
  ? password

development:
  <<: *default
  database: myapp_development
  host: <%= ENV['DATABASE_URL'] || '127.0.0.1' %>

test:
  <<: *default
  database: myapp_test
  host: <%= ENV['DATABASE_URL'] || '127.0.0.1' %>

production:
  reconnect: false
  url: <%= ENV['DATABASE_URL'] %>

起動確認。
repl(pry)を使いたいのでattachするために docker-compose run する。

docker-compose run --rm web bundle exec rails db:create db:migrate
docker-compose run --service-ports web

Herokuの操作

アドオンの導入

各アドオンはクレカ登録が必要

Databaseの導入

$ heroku addons:create heroku-postgresql

ちなみにMySQLをHerokuへで使う場合は以下

$ heroku addons:create cleardb:ignite

ログ監視のためにPapertrailを導入

$ heroku addons:create papertrail

アプリケーションの性能監視のためにNewRelicを導入

$ heroku addons:create newrelic:wayne

Herokuの設定変更

環境変数タイムゾーンを登録

$ heroku config:add TZ=Asia/Tokyo

Procfileの作成

ルートディレクトリへ以下のように Procfile ファイルを追加編集
release を用いることで db:migrate を実行してからデプロイする事が可能。

release: bundle exec rails db:migrate
web: bundle exec rails server -p $PORT -e $RAILS_ENV

独自ドメインの設定

$7以上のプランに入ってないと設定不可だった気がする。

HerokuでのApexドメインについて

ApexドメインはHerokuでは扱いづらい ことに注意。
HerokuはCNAMEを登録して独自ドメインを登録するため、CNAMEを使用できないApexドメインが使用できない。
使用するためにはANAMEが使用可能なドメイン管理サイトで行う必要がある。
例えばお名前ドットコムで取得したドメインをPointDNSへ委譲するなど。

今回はサブドメインを使用する。
e.g. www.example.com

独自ドメインの設定

  1. 設定するドメインをHerokuへ登録
    • Herokuコンソール > Settings > Domains and certificates > Add domain
  2. 表示された DNS Target をメモる
  3. ドメイン管理サイトで登録したドメインのCNAMEへ DNS Target を登録する。
  4. 1日ぐらい経つとLet's Enctyptの証明書が発行される

HSTSの設定

http > httpsのリダイレクト設定。
Railsのコンフィグを書き換えるだけで有効にできる。

config/environments/production.rb

+  config.force_ssl = true

設定したドメインでのみアクセスを受け付ける(受け付けない)

魔実装する。
例えば application_controller.rbproduction 環境だけ特定ドメインだけ受け付けるなど...
魔実装の途中で「herokuのドメインを防ぐ理由ってなんだっけ?」ってなってやめた。

CD(継続的デプロイメント)の設定

  1. GitHubの認証を行う
    • Herokuコンソール > Deploy > Deployment method > GitHub
  2. リポジトリの選択
  3. ブランチの選択

以降選択したブランチに変更がかかるたびに自動的にデプロイが行われる。
release ブランチを切り、リリースのたびに master から release へPRを作成してマージするようなフローが理想的?

まとめ

以上、Herokuについてでした。
やっぱPaaSは楽すぎてクラウド屋さん的には面白みに欠けるなーと。