14
15

More than 1 year has passed since last update.

Nginx+Next.js+Rails+PostgreSQLを使用した開発環境構築

Last updated at Posted at 2023-02-01

概要

※当記事は所属している株式会社コンピュータテクノブレインにて投稿した内容を転載したものです。

再度環境構築の話となりますが、タイトルにある通りNginxのリバースプロキシを使用しNext.jsRuby on RailsDockerを使用した開発環境の構築についての手順を紹介します。

データベースは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

データベース情報を設定する

  • backend/config/database.yml
 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/へアクセスし、フロントエンド側の画面が表示されることを確認する

57809f476bd9b40e887f909b6c721ec5-1024x486.png

http://localhost:3001/へアクセスし、バックエンド側の画面が表示されることを確認する

536721958ea42bc1f3ba9ca40c0a65f8-1024x485.png

コンテナを落とす

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/へアクセスしフロントエンド側が表示されることを確認する

57809f476bd9b40e887f909b6c721ec5-1024x486.png

http://localhost/manage/へアクセスしバックエンド側が表示されることを確認する

536721958ea42bc1f3ba9ca40c0a65f8-1024x485.png

終わりに

弊社にお仕事を依頼したいお客様がいらっしゃいましたら、以下のフォームもしくはメールにてお気軽にお問い合わせ下さい。

お問合せ

システム開発部 森岡(morioka_tatsuaki@computer-tb.co.jp

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15