Rails7 のステージング環境(Docker)を楽々に作成してSSL化する
目的
WEBサーバー(nginx,apacheなど)やアプリケーションサーバー(unicorn,pumaなど)、その他のSSL対応手続きに必要な、面倒なセットアップを大幅にカットあるいは簡略化することで、ローカル環境で実装したRailsとDockerのアプリケーションのステージング環境作成を容易にすること。
前提条件
- ローカル環境でアプリケーションが正常に動いている (http://localhost:3000)
- ステージングサーバーの契約済み
- ステージングサーバーのインフラ設定(ネットワーク、セキュリティなど含む)が完了している
- ステージングサーバー内にdockerとdocker-composeがインストールされている
- 独自ドメインを取得済み
- DNS設定にて、ドメインとパプリックIPを紐付け済み
別に一緒でなくて全然構いませんが、筆者の環境は以下のようになっていますので、参考までに。
- ドメイン取得 => ムームードメインで購入
- ステージングサーバー => EC2でインスタンス作成
- ドメインとパプリックIPを紐付け => Route53で設定済み
バージョン情報
- 手元の作業PC: Apple M1 Pro
- Rails: 7.0.2
- Ruby: 3.1.1
- PostgreSQL: 14.3
- Docker: 20.10.17
- Docker-compose.yml: 2.10.1
ゴール
ブラウザに 独自ドメインでアクセスできること。
今回は、例として、https://www.mysite.work で アクセスできるようにします。
なお、本番環境の設定手順もすぐに別の記事で解説するのでお待ちを。
ディレクトリ構成
プロジェクトルート
├── data (postgresqlのデータマウント用)
├── docker-compose.staging.yml (ステージング用だとわかる命名だと良き)
├── https-portal
└── web
├── .env
├── Dockerfile.prod (自分は本番と共通にしています)
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── app
├── bin
├── config
├── config.ru
├── db
├── entrypoint.sh
├── lib
├── log
├── public
├── storage
├── test
├── tmp
└── vendor
「Rails7.0.2 + PostgreSQL14.3 開発環境(docker)を構築する」の構成をベースにしています。
手順1: 各ファイルの作成・編集
.envを作成
秘匿したい情報はこのファイルに記載
DB_STG_DATABASE="xxxxxxxxxx"
DB_STG_HOST="db" # 今回は、docker-composeで立ち上げるdbサービスを利用
DB_STG_USER="xxxxxxxxxx"
DB_STG_PASSWORD="xxxxxxxxxx"
docker-commpose.staging.yml作成
version: '3'
services:
db:
image: postgres:14.3
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
# - ./db/initdb.d:/docker-entrypoint-initdb.d
environment:
POSTGRES_USER: ${DB_STG_USER}
POSTGRES_PASSWORD: ${DB_STG_PASSWORD}
restart: always
networks:
dragon-network:
ipv4_address: 192.168.1.2
web:
build:
context: web
dockerfile: Dockerfile.prod
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0' -e production"
restart: always
volumes:
- ./web:/app
environment:
DB_PROD_DATABASE: ${DB_STG_DATABASE}
DB_PROD_HOST: ${DB_STG_HOST}
DB_PROD_USER: ${DB_STG_USER}
DB_PROD_PASSWORD: ${DB_STG_PASSWORD}
EDITOR: vim
RAILS_ENV: production
depends_on:
- db
networks:
dragon-network:
ipv4_address: 192.168.1.3
https-portal:
image: steveltn/https-portal:1
ports:
- '80:80'
- '443:443'
restart: always
environment:
DOMAINS: 'admin:bluesky@mysite.work => www.mysite.work, admin:bluesky@www.mysite.work -> http://web:3000'
STAGE: "staging"
WORKER_PROCESSES: 2
CLIENT_MAX_BODY_SIZE: 10M
volumes:
- ./https-portal:/var/lib/https-portal
networks:
dragon-network:
ipv4_address: 192.168.1.4
networks:
dragon-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
https-portal の詳細に関しては以下をご覧ください
- 今回のポイント1
- Basic認証をhttps-portalで設定
- ユーザー名: admin
- パスワード: bluesky
- Basic認証をhttps-portalで設定
- 今回のポイント2
- mysite.workにアクセスするとwww.mysite.workにリダイレクトするように設定
- 注意点1つ
- サービス名webのポート3000番をdockerネットワークの外部にまで公開しない。
ports: 3000:3000
などでポートフォワーディングしてしまうとブラウザから、[staging_public_ip]:3000でアクセスできてしまいます。
- サービス名webのポート3000番をdockerネットワークの外部にまで公開しない。
environments/production.rbの強制SSLをオフにしておく
プロジェクトルート/web/config/environments/production.rb
...
config.force_ssl = false
...
https-portalサービスにて、SSL証明書を発行するときに、httpの通信が発生するため、docker-compose.staging.ymlにて80番ポートが開いていなかったり、force_sslをtrueにしてしまっていると、SSL証明書の発行に失敗してしまう。
Dockerfile.prodを作成
# gemインストールのみに使用
FROM ruby:3.1.1-alpine as builder
ENV ROOT="/app"
ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo
WORKDIR ${ROOT}
COPY Gemfile Gemfile.lock ${ROOT}
RUN apk add \
alpine-sdk \
build-base \
# sqlite-dev \
# mysql-client \
# mysql-dev \
postgresql-dev \
postgresql-client \
tzdata \
git
# M1のRails(Docker環境)起動時にnokogiriがLoadErrorとなる問題の解決方法
RUN apk add --no-cache gcompat
RUN apk add --no-cache --virtual .build-deps \
build-base \
ruby-dev
RUN gem install bundler && bundle install
RUN bundle update webdrivers selenium-webdriver
RUN bundle exec rails assets:precompile RAILS_ENV=production
# マルチステージビルド
FROM ruby:3.1.1-alpine AS runner
ENV ROOT="/app"
ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo
WORKDIR ${ROOT}
RUN apk update && \
apk add \
postgresql-dev \
tzdata \
bash \
gcompat \
vim
RUN apk add --no-cache nodejs
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . ${ROOT}
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
- ポイント
- docker-composeでビルドしたときに、アセットのプリコンパイルを行うようにしている
- これをしないと、jsとcssがステージングに反映されない
- docker-composeでビルドしたときに、アセットのプリコンパイルを行うようにしている
- 注意点
- EXPOSE 3000などで、外部に公開しない
web/config/database.ymlを編集
production:
<<: *default
database: <%= ENV["DB_PROD_DATABASE"] %>
host: <%= ENV["DB_PROD_HOST"] %>
username: <%= ENV["DB_PROD_USER"] %>
password: <%= ENV["DB_PROD_PASSWORD"] %>
(uglifierを使っている人) terserに置き換え
2年前にRails5.2で動かしていた頃は、自分は、uglifierというgemを使って、javascriptのコードを軽量化していたが、Rails7.0で同じように使用すると、precompile時にエラーを吐いていた。ES6構文まではuglifierが使えるけど、ES2020とかになるとterserに置き換えないといけないらしい。以下のようにしてterserに置き換えることで解決した。
- gem 'uglifier'
+ gem 'terser'
- config.assets.js_compressor = :uglifier
+ config.assets.js_compressor = :terser
手順2: アプリケーションをステージングサーバーに転送
それぞれのやり方で転送してください。自分は、fileZillaを愛用しております。
手順3: ステージングで起動
ビルド
$ docker-compose -f docker-compose.staging.yml build
DB作成とマイグレーションファイルの実行
$ docker-compose -f docker-compose.staging.yml run --rm web bundle exec rails db:migrate:reset RAILS_ENV=production
起動
$ docker-compose -f docker-compose.staging.yml up -d
すると、オレオレ証明書がhttps-portalにより、自動で作成される。
ログで確認する。
docker-compose -f docker-compose.staging.yml logs -f
証明書が発行されたら、ブラウザにて以下2点を確認する。オレオレ証明書なので、ブラウザから警告が出ると思いますが、気にしないで、問題ないです。
- https://www.mysite.workにアクセスして、Webページが表示される
- https://mysite.workにアクセスして、https://www.mysite.workにリダイレクトされる
確認できたら、手順4に入る。
手順4: environments/production.rbの強制SSLをオンにしておく
プロジェクトルート/web/config/environments/production.rb
...
config.force_ssl = true
...
設定を変えたら、立ち上げ直す
$ docker-compose -f docker-compose.staging.yml down
$ docker-compose -f docker-compose.staging.yml up -d --build
終わりに
今回はRailsとDockerで作成したローカル環境を容易にステージングに作成する方法を紹介いたしました。
2年前までは自分は、サーバーにgit cloneして手動でライブラリをインストールして、設定編集したりして、極めて面倒な作業だったので、今では非常にhttps-portalに利便性を感じています。
https-portalは、wordpressで使っている記事はよく見るものの、Railsで使っている記事は、自分が探した限りでは、ただの1件もなかったので、非常に価値のある記事が、公開できたのではないかと思っています。
本番環境作成手順に関してもすぐに別の記事で紹介するので、お楽しみに。
docker + Railsのステージング環境作成にぜひ役に立てば幸いです。
Discussion