Nginx+Next.js+Rails+PostgreSQLを使用した開発環境構築
概要
再度環境構築の話となりますが、タイトルにある通りNginx
のリバースプロキシを使用しNext.js
、Ruby on Rails
のDocker
を使用した開発環境の構築についての手順を紹介します。
前回同様データベースはPostgreSQL
を使用しようと思います。
構成
2022年6月22日時点での環境を示します。
- macOS Monterey 12.4
- Docker 20.10.14
- Docker Compose v2.5.1
- Nginx 1.21.6
- Node.js v18.4.0
- Next.js 12.1.6
- Ruby 3.1.2
- Ruby on Rail 7.0.3
- PostgreSQL 14.3
ディレクトリ構造
プロジェクトルート
├── docker-compose.yml
├── container
│ ├── backend
│ │ └── Dockerfile
│ │ └── entrypoint.sh
│ ├── db
│ ├── frontend
│ │ └── Dockerfile
│ └── nginx
│ └── default.conf
│ └── nginx.conf
├── backend
│ ├── Gemfile
│ └── Gemfile.lock
└── frontend
プロジェクトの作成
Next.js(フロントエンド側)のプロジェクト作成
- docker-compose.yml
version: "3"
services:
frontend:
container_name: frontend
build:
context: .
dockerfile: container/frontend/Dockerfile
volumes:
- ./frontend:/usr/src/app
command: yarn dev
ports:
- "3000:3000"
- container/frontend/Dockerfile
FROM node:18-alpine3.15
# 環境変数の設定
ENV APP_PATH /usr/src/app
WORKDIR $APP_PATH
Next.jsのプロジェクトを作成する
docker compose run --rm frontend npx create-next-app . --ts
Ruby on Rails(バックエンド側)のプロジェクト作成
- docker-compose.yml(修正)
version: "3"
services:
frontend:
container_name: frontend
build:
context: .
dockerfile: container/frontend/Dockerfile
volumes:
- ./frontend:/usr/src/app
command: yarn dev
ports:
- "3000:3000"
+ depends_on:
+ - backend
+ backend:
+ container_name: backend
+ build:
+ context: .
+ dockerfile: container/backend/Dockerfile
+ volumes:
+ - ./backend:/app
+ environment:
+ TZ: Asia/Tokyo
+ RAILS_ENV: development
+ ports:
+ - "3001:3000"
+ depends_on:
+ - db
+ db:
+ image: postgres:14.3-alpine
+ container_name: postgres
+ environment:
+ - TZ=Asia/Tokyo
+ - PGTZ=Asia/Tokyo
+ - POSTGRES_PASSWORD=password
+ volumes:
+ - ./container/db/data:/var/lib/postgresql/data
+ ports:
+ - "5432:5432"
- container/backend/Dockerfile
FROM ruby:3.1.2-alpine
ENV ROOT="/app"
ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo
WORKDIR ${ROOT}
COPY ./backend/Gemfile ./backend/Gemfile.lock ${ROOT}
RUN apk update && \
apk add \
alpine-sdk \
build-base \
sqlite-dev \
postgresql-dev \
tzdata \
git \
gcompat
RUN gem install bundler
RUN bundle install
COPY ./container/backend/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
CMD ["rails", "server", "-e"]
- container/backend/entrypoint.sh
#!/bin/sh
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
- backend/Gemfile
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.2"
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.0.3"
- backend/Gemfile.lock
空ファイル
Ruby on Railsのプロジェクトを作成する
docker compose run --rm backend bundle exec rails _7.0.3_ new . -d postgresql -f
コンテナをビルドする
docker compose build
データベース情報を設定する
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ username: postgres
+ password: password
+ host: db
データベースを作成する
docker compose run --rm backend rails db:create
コンテナを立ち上げる
docker compose up -d
http://localhost:3000/
へアクセスし、フロントエンド側の画面が表示されることを確認する
http://localhost:3001/
へアクセスし、バックエンド側の画面が表示されることを確認する
コンテナを落とす
docker compose down
Nginxの設定を追加
- docker-compose.yml(再修正)
version: "3"
services:
+ web:
+ image: nginx:1.21.6
+ container_name: web
+ environment:
+ TZ: Asia/Tokyo
+ volumes:
+ - ./container/nginx/default.conf:/etc/nginx/conf.d/default.conf
+ - ./container/nginx/log:/var/log/nginx
+ - ./backend/public:/backend/public
+ - ./backend/tmp:/backend/tmp
+ ports:
+ - "80:80"
+ depends_on:
+ - frontend
+ - backend
frontend:
container_name: frontend
build:
context: .
dockerfile: container/frontend/Dockerfile
volumes:
- ./frontend:/usr/src/app
command: yarn dev
ports:
- "3000:3000"
depends_on:
- backend
backend:
container_name: backend
build:
context: .
dockerfile: container/backend/Dockerfile
volumes:
- ./backend:/app
environment:
TZ: Asia/Tokyo
RAILS_ENV: development
ports:
- "3001:3000"
depends_on:
- db
db:
image: postgres:14.3-alpine
container_name: postgres
environment:
- TZ=Asia/Tokyo
- PGTZ=Asia/Tokyo
- POSTGRES_PASSWORD=password
volumes:
- ./container/db/data:/var/lib/postgresql/data
ports:
- "5432:5432"
- container/nginx/default.conf
upstream backend {
server unix:///backend/tmp/sockets/puma.sock fail_timeout=30s;
}
server {
listen 80;
# ドメインもしくはIPを指定
server_name localhost;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
########################################
# リバースプロキシ関連の設定
########################################
# 公開側(フロントエンド)
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://frontend:3000/;
}
# 管理側(バックエンド)
location /manage/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://backend;
}
}
- container/nginx/nginx.conf
user root;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
バックエンド側のPumaの設定を変更する
- backend/config/puma.rb
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
# Specifies the `worker_timeout` threshold that Puma will use to wait before
# terminating a worker in development environments.
#
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
- port ENV.fetch("PORT") { 3000 }
+ #port ENV.fetch("PORT") { 3000 }
+ bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
# Allow puma to be restarted by `bin/rails restart` command.
plugin :tmp_restart
バックエンド側のルート設定を変更する
- backend/config/environments/development.rb
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
# Enable server timing
config.server_timing = true
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join("tmp/caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :local
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Suppress logger output for asset requests.
config.assets.quiet = true
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
+ Rails.application.config.relative_url_root = "/manage"
end
- backend/config.ru
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
- run Rails.application
+ map ActionController::Base.config.relative_url_root || "/" do
+ run Rails.application
+ end
Rails.application.load_server
コンテナを再度立ち上げる
docker compose up -d
http://localhost/
へアクセスしフロントエンド側が表示されることを確認する
http://localhost/manage/
へアクセスしバックエンド側が表示されることを確認する
終わりに
弊社にお仕事を依頼したいお客様がいらっしゃいましたら、以下のフォームもしくはメールにてお気軽にお問い合わせ下さい。
システム開発部 森岡(morioka_tatsuaki@computer-tb.co.jp)