はじめに
以前Railsの本番環境をunicornで立てる実装をしました。
ただ、サーバーをVPSから自宅サーバーに移行する際、サーバーをすべてdockerで立てようとした時にnginx周りとかで色々と詰まったことがあったので記事に記録を残しました。
ディレクトリ構成
- root
- app
- bin
- ...(rails関連のファイル)
- public
- .env
- Dockerfile
- docker-compose.yml
- nginx
- Dockerfile
- nginx.conf
Docker関連
FROM ruby:3.1.2-alpine as builder
RUN apk update && \
apk add --no-cache \
build-base \
postgresql-dev
RUN gem install bundler
COPY Gemfile Gemfile.lock ./
ENV RAILS_ENV=production
RUN RAILS_ENV=${RAILS_ENV} bundle install
FROM ruby:3.1.2-alpine as app
RUN apk update && \
apk add --no-cache \
tzdata \
postgresql-client
WORKDIR /app
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . .
CMD ["sh", "entrypoint.sh"]
マルチステージビルド(https://docs.docker.jp/develop/develop-images/multistage-build.html )を使うことで作られるdocker imageのサイズを小さくする工夫をしてあります。
参考: https://qiita.com/sasamuku/items/6aea2b4dffb43de161e3
services:
rails:
build:
context: .
dockerfile: Dockerfile
image: rails-app
container_name: rails-app-rails
depends_on:
- db
env_file:
- .env
environment:
- RAILS_ENV=production
volumes:
- public:/app/public
db:
image: postgres:15-alpine
restart: always
container_name: rails-app-postgres
volumes:
- database:/var/lib/postgresql/data
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: rails_app_production
nginx:
container_name: rails-app-nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- 54010:80
depends_on:
- rails
volumes:
- public:/app/public
volumes:
database:
public:
- Railsのpublicディレクトリをvolumeとしてnginxと共有し、nginx上で公開できるようにしています。公開するポートについては、dockerのコンテナ内ネットワークを使ってrailsサーバーのポートへnginxがプロキシするようにしています。
-
env_file
に.env
を指定することで、.env
の内容がコンテナ内の環境変数に入るようにしています。 - nginxについては
nginx/Dockerfile
を元にビルドをするようにしています
FROM nginx:alpine
RUN rm -f /etc/nginx/conf.d/*
ADD nginx.conf /etc/nginx/conf.d/nginx.conf
CMD /usr/sbin/nginx -g 'daemon off;'
nginxのDockerfileです。設定ファイル(.conf)をコピーしてnginxサーバーを起動しています。
Rails関係
POSTGRES_USER=...
POSTGRES_PASSWORD=...
.env
にはPOSTGRES_USER
とPOSTGRES_PASSWORD
を指定します。
production:
<<: *default
database: rails_app_production
username: <%= ENV["POSTGRES_USER"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
host: db
Railsのデータベースの設定を記述します。hostはdockerコンテナ内ネットワークを使用してpostgresサーバーと接続できるようにします。
bin/rails db:migrate
bin/rails assets:precompile
bin/rails server -b 0.0.0.0 -p 3000
サーバー起動時に実行されるコマンドを設定します。起動時にdb:migrate
を実行することで起動時にデータベースのスキーマを反映させることができます。assets:precompile
は多分Dockerfile
の中で行なっても大丈夫だと思う(要検証)。
Nginx関係
server {
listen 80;
server_name www.example.com;
root /app/public;
location @app {
proxy_pass http://rails:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
try_files $uri/index.html $uri @app;
error_page 500 502 503 504 /500.html;
}
Railsのpublicディレクトリを直接公開するよう設定をし、それ以外のURLに対してはRailsサーバーにリクエストを送るようにしています。
おわりに
今回はRails + Nginxサーバーをdockerを用いて公開するよう設定をしました。次回はRailsサーバーとフロントエンドのNextサーバーを組み合わせてdockerで本番環境を構築していこうと思います。
参考資料