Docker容器化部署Rails应用时静态资源无法加载如何解决
问题根因
静态资源加载失败是4处配置错误共同导致的:
- docker-compose配置的匿名卷覆盖了镜像构建阶段预编译的静态文件:app服务下配置的
- /var/wwww/quickcard、- /var/wwww/quickcard/public为匿名挂载,容器启动时会用空卷覆盖镜像内对应路径的所有内容,Dockerfile中执行assets:precompile生成的public/assets下的文件会被直接清空;同时路径存在笔误,正确路径为/var/www,配置中多写了一个w。 - Nginx容器未挂载静态资源目录:nginx服务的volumes配置仅挂载了日志目录,配置中写的
/var/www/quickcard/public路径在nginx容器内部为空,根本无法读取到静态文件。 - Nginx静态资源匹配规则错误:
/assets/路径下多余的rewrite规则逻辑错误,会打乱正常的文件查找路径。 - 运行环境配置不统一:Dockerfile中预编译资产时未指定
RAILS_ENV=production,原compose中启动命令强制指定了development环境,Rails开发环境默认不会读取预编译的静态资产,也不会主动托管public目录下的静态文件。
修复步骤
- 修正docker-compose.yml配置
删除错误的匿名卷配置,改用命名卷在app和nginx容器间共享静态资源,统一环境变量为生产模式,修正路径笔误,参考配置如下:version: '2.2' services: app: build: context: . dockerfile: ./Dockerfile command: ['bundle','exec','puma', '-C', 'config/puma.rb'] environment: RAILS_ENV: production RAILS_SERVE_STATIC_FILES: true volumes: - assets_volume:/var/www/quickcard/public - app_tmp:/var/www/quickcard/tmp ports: - 5000:5000 sidekiq: build: . command: bundle exec sidekiq -C config/sidekiq.yml environment: RAILS_ENV: production volumes: - app_tmp:/var/www/quickcard/tmp nginx: build: context: . dockerfile: ./nginx.Dockerfile volumes: - ./log-nginx:/var/log/nginx/ - assets_volume:/var/www/quickcard/public:ro ports: - 80:80 depends_on: - app volumes: assets_volume: app_tmp: - 修正Dockerfile资产预编译逻辑
找到Dockerfile中预编译静态资源的行,替换为指定生产环境的执行命令,避免环境差异导致的资产路径不匹配:RUN RAILS_ENV=production bundle exec rake assets:precompile --trace - 修正Nginx配置规则
删除/assets/路径下错误的rewrite规则,调整根路径匹配逻辑,优先读取本地静态文件,读不到再转发给Puma处理,参考配置如下:upstream puma { server app:5000 fail_timeout=0; } server { listen 80 default_server deferred; root /var/www/quickcard/public; index index.html index.htm; access_log /var/www/quickcard/log/nginx.access.log; error_log /var/www/quickcard/log/nginx.error.log; location / { try_files $uri $uri/index.html $uri.html @puma; } location @puma { proxy_pass http://puma; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; add_header Strict-Transport-Security ""; try_files $uri =404; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; } - 清理旧缓存后重新部署
之前生成的错误匿名卷会残留脏数据,执行以下命令彻底清理后重新构建启动:docker compose down -v docker compose build --no-cache docker compose up -d
验证方法
启动后执行命令进入nginx容器检查静态文件是否存在:
docker compose exec nginx ls /var/www/quickcard/public/assets
如果输出列表中能看到编译日志里带hash的css、图片文件,访问页面时静态资源请求返回200状态码,即修复完成。
内容的提问来源于stack exchange,提问作者Saad Saddique
相关产品推荐
相关产品推荐

