使用Docker构建Rails + Nginx的生产环境的故事

首先

我以前曾经在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镜像的大小。

参考: https://qiita.com/sasamuku/items/6aea2b4dffb43de161e3

参考链接: 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服务器。

铁轨相关

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的數據庫設置。我們會使用Docker容器內的網絡來連接到PostgreSQL服務器。

bin/rails db:migrate
bin/rails assets:precompile
bin/rails server -b 0.0.0.0 -p 3000

在服务器启动时设置要执行的命令。通过在启动时执行db:migrate命令,可以在启动时反映数据库模式。我认为可以在Dockerfile中执行assets:precompile(需要验证)。

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服务器。

最后

这次我们使用Docker来配置Rails + Nginx服务器进行公开。下一步,我们计划使用Docker来搭建将Rails服务器和前端Next服务器组合起来的生产环境。

请先参考相关资料。

 

广告
将在 10 秒后关闭
bannerAds