Docker部署Django-React应用生产环境静态文件加载失败排查
问题描述
本地运行正常,部署到ECS生产环境后静态文件返回404。已执行collectstatic命令,/vol/web/static目录下静态文件齐全,但浏览器请求https://site/static/js/main.db771bdd.js这类资源时仍返回404错误。
相关配置信息
Django settings.py 核心配置
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'build')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] STATIC_URL = '/static/' MEDIA_URL = '/media/' STATIC_ROOT = '/vol/web/static' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'build', 'static')]
Nginx 代理配置
server { listen ${LISTEN_PORT}; location /static { alias /vol/static; } location / { uwsgi_pass ${APP_HOST}:${APP_PORT}; include /etc/nginx/uwsgi_params; client_max_body_size 10M; } }
API容器 Dockerfile
FROM python:3.9-alpine ENV PYTHONUNBUFFERED 1 ENV PATH="/scripts:${PATH}" RUN pip install --upgrade "pip<24.1" COPY ./requirements.txt /requirements.txt RUN apk add --update --no-cache postgresql-client jpeg-dev \ && apk add --update --no-cache --virtual .tmp-build-deps \ gcc libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev libffi-dev \ && pip install -r /requirements.txt \ && apk del .tmp-build-deps RUN mkdir -p /app /vol/web/media /vol/web/static RUN adduser -D user RUN chown -R user:user /vol /app COPY ./app /app COPY ./scripts /scripts COPY ./requirements.txt /requirements.txt RUN chmod -R 755 /vol/web /app /scripts \ && chmod +x /scripts/* USER user WORKDIR /app VOLUME /vol/web CMD ["entrypoint.sh"]
ECS任务容器挂载核心配置
- API容器:将
static卷挂载到/vol/web,通过entrypoint.sh执行collectstatic到/vol/web/static - Proxy容器:将
static卷挂载到/vol/static,Nginx通过/static路径指向该目录
entrypoint.sh 启动脚本
#!/bin/sh set -e python manage.py collectstatic --noinput --settings=app.settings.staging python manage.py wait_for_db --settings=app.settings.staging python manage.py wait_for_es --settings=app.settings.staging python manage.py migrate --settings=app.settings.staging python manage.py search_index --rebuild --settings=app.settings.staging -f uwsgi --socket :9000 --workers 4 --master --enable-threads --module app.wsgi --env DJANGO_SETTINGS_MODULE=app.settings.staging
排查方向与解决方法
1. 跨容器卷挂载路径不匹配
API容器把共享卷挂到/vol/web,静态文件收集后存放在/vol/web/static;但Proxy容器把同一份共享卷挂到了/vol/static,导致Proxy容器内的/vol/static实际对应API容器的/vol/web目录,而非/vol/web/static。
解决:二选一调整配置
- 方案1:修改Proxy容器挂载路径为
/vol/web,同时更新Nginx配置:location /static { alias /vol/web/static; } - 方案2:修改API容器的
STATIC_ROOT为/vol/static,并调整API容器挂载路径为/vol/static,保持Nginx配置不变。
2. Nginx alias 路径拼接错误
使用alias时,路径末尾的斜杠会影响匹配逻辑:如果location是/static,alias路径为/vol/static,请求/static/js/xxx.js会被错误映射为/vol/staticjs/xxx.js。
解决:统一路径斜杠规则:
location /static/ { alias /vol/web/static/; }
3. 共享卷类型不支持跨容器同步
ECS默认的空卷是容器本地卷,无法跨容器共享文件。需确认使用的是可共享卷类型(如Amazon EFS、绑定挂载到主机目录)。
验证:
- 进入API容器执行
ls /vol/web/static确认文件存在 - 进入Proxy容器执行
ls [对应挂载路径]/static确认文件同步
4. 静态文件权限不足
即使修改过权限,仍需确认Nginx进程用户(通常为nginx或www-data)对静态文件有读权限。
解决:在entrypoint.sh的collectstatic命令后添加权限修正:
chmod -R 644 /vol/web/static chmod -R 755 /vol/web/static
5. 模板中静态文件路径硬编码
确保React构建后的index.html中静态文件引用使用Django的{% static %}标签生成,而非硬编码路径;若直接使用build目录作为模板,需保证src/href路径为/static/xxx,与STATIC_URL匹配。
调试命令
- 查看Nginx错误日志:进入Proxy容器执行
cat /var/log/nginx/error.log,可看到文件找不到的具体路径 - 本地测试静态文件访问:在Proxy容器内执行
curl http://localhost:8000/static/js/main.db771bdd.js - 查看ECS任务日志:通过AWS控制台查看API/Proxy容器日志,确认
collectstatic执行状态、卷挂载是否报错
内容的提问来源于stack exchange,提问作者Lucas

