You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose部署Django+PostgreSQL+Gunicorn权限及启动报错修复

运行环境
  • 操作系统:Ubuntu 20.04 LTS
  • 容器版本:Docker Desktop 20.10.16
  • 部署组件:Django v3.2、PostgreSQL v14.3、Gunicorn v20.1.0,后续计划对接宿主机Nginx做反向代理,当前优先解决容器启动异常
本地项目结构
/path/to/myprojectweb/
├── myproj/
│   ├── myproj/
│   ├── settings.py
│   ├── wsgi.py
│   └── 其他项目文件
├── Dockerfile.prod
└── compose.prod.yml
问题现象

镜像和容器可正常构建,但启动Django应用时失败,存在两类报错:

  1. 写入/home/app/web/myproj.log文件权限不足,日志handler初始化失败
  2. Gunicorn启动时无法识别传入的命令行参数,容器退出码为127
    已在Dockerfile.prod中对相关目录执行过chown、chmod权限配置(甚至添加了粘滞位),权限问题仍未解决。
现有配置文件

Dockerfile.prod

# Builder Image
FROM python:3.8-slim-buster as Builder

WORKDIR /usr/src/app

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWEITEBYTECODE 1

RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev
  

RUN pip install --upgrade pip pipenv
COPY Pipfile* ./
RUN pipenv lock --keep-outdated --requirements > requirements.txt \
    && pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt


# Final Image
FROM python:3.8-slim-buster

RUN mkdir -p /home/app  /var/log/gunicorn

# 创建运行应用的非root用户和用户组
RUN groupadd -r app && useradd --no-log-init -r -g app app

ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
WORKDIR $APP_HOME


RUN apt-get update && apt-get install -y libpq-dev
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt ./

RUN chown -R app:app $HOME
RUN chown -R app:app $APP_HOME && chmod ug+rws $APP_HOME
RUN chown -R app:app /var/log/gunicorn

# 提前切换用户安装依赖,方便后续执行makemigrations/migrate更新第三方包
USER app
RUN pip install --no-cache /wheels/*

COPY . $APP_HOME

compose.prod.yml

services:
  db:
    image: postgres:14.3
    restart: always
    container_name: myproj_postgres_db
    env_file:
      - .env
    volumes:
      - postgres_data:/var/lib/postgresql/data/

  web:
    build: 
      context: .
      dockerfile: Dockerfile.prod
    container_name: myproj_app
    restart: always
    command: >
      sh -c "python manage.py makemigrations && python manage.py migrate &&
             gunicorn --capture-output \
                      --access-logfile /var/log/gunicorn/access.log  \
                      --error-logfile /var/log/gunicorn/error.log  \
                      --enable-stdio-inheritance  \
                      --workers 3  \
                      --worker-tmp-dir /dev/shm \
                      --bind 0.0.0.0:8000 \
                       myproj.wsgi:application" 
    ports:
      - 8000:8000
    env_file:
      - .env
    depends_on:
      - db

volumes:
  postgres_data:      
启动报错片段

执行sudo docker compose -f compose.prod.yml up --build后报错如下:

myproj_app          | Traceback (most recent call last):
myproj_app          |   File "/usr/local/lib/python3.8/logging/config.py", line 563, in configure
myproj_app          |     handler = self.configure_handler(handlers[name])
myproj_app          |   File "/usr/local/lib/python3.8/logging/config.py", line 744, in configure_handler
myproj_app          |     result = factory(**kwargs)
myproj_app          |   File "/usr/local/lib/python3.8/logging/handlers.py", line 200, in __init__
myproj_app          |     BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
myproj_app          |   File "/usr/local/lib/python3.8/logging/handlers.py", line 55, in __init__
myproj_app          |     logging.FileHandler.__init__(self, filename, mode, encoding, delay)
myproj_app          |   File "/usr/local/lib/python3.8/logging/__init__.py", line 1147, in __init__
myproj_app          |     StreamHandler.__init__(self, self._open())
myproj_app          |   File "/usr/local/lib/python3.8/logging/__init__.py", line 1176, in _open
myproj_app          |     return open(self.baseFilename, self.mode, encoding=self.encoding)
myproj_app          | PermissionError: [Errno 13] Permission denied: '/home/app/web/myproj.log'
myproj_app          | 
myproj_app          | The above exception was the direct cause of the following exception:
myproj_app          | 
myproj_app          | Traceback (most recent call last):
myproj_app          |   File "manage.py", line 22, in <module>
myproj_app          |     main()
myproj_app          |   File "manage.py", line 18, in main
myproj_app          |     execute_from_command_line(sys.argv)
myproj_app          |   File "/home/app/.local/lib/python3.8/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
myproj_app          |     utility.execute()
myproj_app          |   File "/home/app/.local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
myproj_app          |     django.setup()
myproj_app          |   File "/home/app/.local/lib/python3.8/site-packages/django/__init__.py", line 19, in setup
myproj_app          |     configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
myproj_app          |   File "/home/app/.local/lib/python3.8/site-packages/django/utils/log.py", line 75, in configure_logging
myproj_app          |     logging_config_func(logging_settings)
myproj_app          |   File "/usr/local/lib/python3.8/logging/config.py", line 808, in dictConfig
myproj_app          |     dictConfigClass(config).configure()
myproj_app          |   File "/usr/local/lib/python3.8/logging/config.py", line 570, in configure
myproj_app          |     raise ValueError('Unable to configure handler ')
myproj_app          | ValueError: Unable to configure handler 'logfile'
myproj_app          | sh: 3: --access-logfile: not found
myproj_app          | sh: 4: --error-logfile: not found
myproj_app          | sh: 5: --enable-stdio-inheritance: not found
myproj_app          | sh: 6: --workers: not found
myproj_app          | sh: 7: --worker-tmp-dir: not found
myproj_app          | sh: 8: --bind: not found
myproj_app          | sh: 9: myproj.wsgi:application: not found
myproj_app exited with code 127
修复方案

两个问题分别对应独立根因,按以下步骤修改即可解决:

1. 修复myproj.log文件权限问题

权限配置顺序错误:Dockerfile里先执行了chown app:app $APP_HOME,之后才执行COPY . $APP_HOME把本地项目代码复制到容器内。Dockerfile中USER指令仅对后续执行的RUN/CMD/ENTRYPOINT生效,COPY操作默认以root身份执行,复制进来的文件所有者为root,不会继承之前设置的目录权限,导致运行时app用户没有项目目录下文件的写入权限。
修改Dockerfile.prod,把COPY . $APP_HOME移动到权限配置命令之前,调整后对应片段如下:

# 省略前面不变的配置
RUN chown -R app:app $HOME
# 先复制项目代码
COPY . $APP_HOME
# 再统一给所有项目文件设置权限
RUN chown -R app:app $APP_HOME && chmod ug+rws $APP_HOME
RUN chown -R app:app /var/log/gunicorn

# 切换用户再装依赖
USER app
RUN pip install --no-cache /wheels/*

如果不想调整COPY顺序,也可以在COPY之后补执行一次RUN chown -R app:app $APP_HOME,效果一致。

2. 修复Gunicorn参数无法识别的问题

compose文件里command块用了>折叠换行符,这种写法会把换行替换成空格,但你在gunicorn命令的每一行末尾加了\转义符,转义符加空格之后会被sh解析成命令结束标记,后续的参数会被当成独立的shell命令执行,才会报--xxx: not found的错误。
两种修改方式二选一即可:

  • 方式一:去掉所有gunicorn参数末尾的\,因为>折叠符本身就会把多行拼成单行命令,不需要额外加转义换行
  • 方式二:把折叠符从>换成|-,保留换行的同时让\正常生效
    推荐用方式一,修改后command块如下:
command: >
  sh -c "python manage.py makemigrations && python manage.py migrate &&
         gunicorn --capture-output
                  --access-logfile /var/log/gunicorn/access.log
                  --error-logfile /var/log/gunicorn/error.log
                  --enable-stdio-inheritance
                  --workers 3
                  --worker-tmp-dir /dev/shm
                  --bind 0.0.0.0:8000
                  myproj.wsgi:application"

修改完成后重新执行构建启动命令即可正常拉起服务。

补充提示:生产环境不建议每次容器启动都执行makemigrations,该操作会自动生成模型迁移文件,容易造成迁移文件冲突,建议仅保留migrate命令,迁移文件在本地开发环境生成后提交到代码仓库。

内容的提问来源于stack exchange,提问作者Homunculus Reticulli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:33:43