Docker部署生产环境Ruby on Rails的Puma与Nginx配置排查
Docker容器化部署Rails生产环境问题排查与配置修正
容器内Puma运行状态检查方法
所有服务均运行于Docker环境时,无需在宿主机部署任何Puma相关服务,按以下步骤即可完成状态检查:
- 查看容器运行状态:执行
docker compose ps,确认app服务状态为Up,若显示Exited则为启动失败,直接读取启动日志定位问题 - 查看Puma启动日志:执行
docker compose logs app,正常启动会输出* Listening on tcp://0.0.0.0:5000标识,若存在数据库连接失败、依赖缺失、环境变量未配置等问题,错误信息会直接打印在日志中 - 容器内端口监听验证:执行
docker compose exec app ss -tulpn | grep 5000,若存在puma进程监听0.0.0.0:5000的记录则为正常;若容器内未预装ss工具,可直接执行docker compose exec app curl http://localhost:5000,返回HTTP响应即代表Puma可正常处理请求 - 进程状态检查:执行
docker compose exec app ps aux | grep puma,可看到puma主进程与配置的worker进程运行,若仅存在grep进程则代表Puma未成功启动
访问异常配置修正方案
现有配置存在路径拼写错误、启动命令覆盖、跨容器文件映射缺失、路由规则错误等问题,所有调整均在Docker配置文件内完成,无需修改宿主机系统配置:
现存核心问题
- docker-compose.yml中app服务的command覆盖了Dockerfile内的puma启动命令,且volume路径存在拼写错误(
/var/wwww多写一个w),全目录匿名挂载会覆盖容器内构建好的代码文件,直接导致启动失败 - nginx运行于独立容器,未配置静态资源目录挂载,容器内不存在代码路径,静态资源直接返回404
- nginx配置中
server_name写死为quickcard,直接访问服务器IP时无法匹配对应server块 - Dockerfile内BUNDLE_PATH缺少开头斜杠为相对路径、apt缓存清理命令适配错误、存在无用的systemd软链接配置(容器环境不运行systemd)
- 旧版本links配置不稳定,未配置服务依赖顺序
修正后配置文件
1. Dockerfile
FROM ruby:2.7.2 ENV RAILS_ROOT /var/www/quickcard ENV BUNDLE_VERSION 2.1.4 ENV BUNDLE_PATH /usr/local/bundle/gems ENV RAILS_LOG_TO_STDOUT true ENV RAILS_PORT 5000 ENV RAILS_ENV production COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh RUN apt-get update -qq && apt-get install -y build-essential \ git \ libxml2-dev \ libpq-dev \ libxslt-dev \ nodejs \ yarn \ imagemagick \ tzdata \ less \ && rm -rf /var/lib/apt/lists/* RUN gem install bundler --version "$BUNDLE_VERSION" RUN bundle config set path $BUNDLE_PATH RUN mkdir -p $RAILS_ROOT WORKDIR $RAILS_ROOT ADD Gemfile Gemfile ADD Gemfile.lock Gemfile.lock RUN bundle install --without development test COPY . . RUN bundle exec rails assets:precompile EXPOSE $RAILS_PORT ENTRYPOINT ["entrypoint.sh"] CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
entrypoint.sh内需提前写入生产环境数据库迁移、临时文件清理逻辑,无需手动进入容器执行
2. docker-compose.yml
version: '3.8' services: app: build: context: . dockerfile: ./Dockerfile volumes: - ./public:/var/www/quickcard/public - ./tmp:/var/www/quickcard/tmp - ./log:/var/www/quickcard/log ports: - "127.0.0.1:5000:5000" environment: - RAILS_ENV=production restart: always sidekiq: build: . command: bundle exec sidekiq -C config/sidekiq.yml volumes: - ./tmp:/var/www/quickcard/tmp - ./log:/var/www/quickcard/log environment: - RAILS_ENV=production depends_on: - app restart: always nginx: build: context: . dockerfile: ./nginx.Dockerfile ports: - 80:80 volumes: - ./public:/var/www/quickcard/public depends_on: - app restart: always
同一compose环境下服务默认通过服务名做域名解析,无需配置旧版links规则;app服务5000端口仅绑定宿主机本地回环,不对外暴露,所有外部流量统一经nginx转发
3. nginx配置文件
upstream app { server app:5000; } server { listen 80; server_name _; root /var/www/quickcard/public; index index.html index.htm; location / { try_files $uri $uri/ @app; } location @app { proxy_pass http://app; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_redirect off; proxy_read_timeout 300; } location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; }
server_name _可匹配所有IP/域名访问请求;静态资源直接由nginx返回,动态请求转发至Puma处理,性能更优
nginx镜像基于官方nginx:stable-alpine构建,将上述配置复制到容器内/etc/nginx/conf.d/default.conf即可
部署验证步骤
- 重新构建镜像:
docker compose build --no-cache - 后台启动所有服务:
docker compose up -d - 按前文Puma检查步骤确认app服务正常运行
- 查看nginx日志确认无配置报错:
docker compose logs nginx - 服务器本地执行
curl http://127.0.0.1返回Rails响应即为正常,此时外部访问服务器IP的80端口即可正常打开站点
内容的提问来源于stack exchange,提问作者Saad Saddique
相关产品推荐
相关产品推荐

