如何用Docker Compose部署Django+PostgreSQL应用

文章导读
建议将 Docker Compose 项目文件与 Django 项目根目录放在同一层级。典型的目录结构包含 Django 源码、requirements.txt、Dockerfile、docker-compose.yml 以及一个 .env 文件用于管理环境变量。分离代码与配置可以避免敏感信息泄露,同时便于不同环境复用 compose 文件。如果你已经有一个 Django 项目,只需要在项目根目录
📋 目录
  1. 项目结构准备
  2. 服务定义与环境变量
  3. 数据持久化配置
  4. 启动依赖与网络通信
  5. 验证与回滚
A A

项目结构准备

建议将 Docker Compose 项目文件与 Django 项目根目录放在同一层级。典型的目录结构包含 Django 源码、requirements.txt、Dockerfile、docker-compose.yml 以及一个 .env 文件用于管理环境变量。分离代码与配置可以避免敏感信息泄露,同时便于不同环境复用 compose 文件。如果你已经有一个 Django 项目,只需要在项目根目录下新建 docker-compose.yml 和 .env,再把 Dockerfile 加进去就好。.env 文件不要提交到 Git,记得加进 .gitignore。

我个人习惯把 .env 写成 key=value 格式,例如 POSTGRES_DB=myappdb,然后在 docker-compose.yml 里用 ${POSTGRES_DB} 读取。这样同一个 compose 文件换一套 .env 就能部署到测试或线上,不用修改 yaml 本身。但要注意:.env 文件中的变量如果在 shell 环境里也有同名变量,Docker Compose 会优先读取 shell 环境变量,容易造成混淆。建议在启动前先用 env 检查一下当前运行环境,或者干脆在 compose 文件里用 env_file 明确指向 .env 文件路径。

服务定义与环境变量

docker-compose.yml 中需要定义 web 和 db 两个服务。web 服务基于 Python 镜像构建,通过 build 或 image 指定;db 服务直接使用 postgres 官方镜像。注意为 db 服务设置 POSTGRES_DB、POSTGRES_USER、POSTGRES_PASSWORD 环境变量,这些值需与 Django 的 DATABASES 配置中的 NAME、USER、PASSWORD 对应。常见错误是拼写错误导致连接失败,建议将变量统一写在 .env 文件中。

实际配置时,我在 Django 的 settings.py 里这样写:

import os
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('POSTGRES_DB'),
        'USER': os.environ.get('POSTGRES_USER'),
        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'db'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

这样 web 容器启动时会从环境变量里读这些值。如果 .env 里写错了名字,比如 POSTGRES_USER 写成了 POSTGRES_USERNAME,数据库连接肯定失败。docker-compose up 之后看到 web 容器退出码为 1,可以先 docker logs web 看看异常信息,多半是“could not connect to server”或者“FATAL: password authentication failed”。别急着怀疑网络,先检查环境变量是否一致。

数据持久化配置

PostgreSQL 容器默认将数据存储在容器内部文件系统,一旦容器删除数据就会丢失。必须在 docker-compose.yml 中为 db 服务声明一个命名 volume 并挂载到 /var/lib/postgresql/data,例如:volumes: - pgdata:/var/lib/postgresql/data。同时要在顶层声明 volumes: pgdata:。忽视这一步是初学者常见失误,尤其在重启或升级容器时可能造成数据清零。

加入持久化之后,即使 docker-compose down 再 up,只要 volume 没有被手动删除,数据都在。我遇到过同事用 docker-compose down -v 清理卷导致数据全丢的情况,所以最好在团队内约定:用 down 不带 -v,除非明确要重置数据。另外,在生产环境建议定期备份 volume 内容,最简单的办法是用 docker run —rm -v pgdata:/backup -v $(pwd):/dest alpine tar czf /dest/pg_backup.tar.gz -C /backup . 把数据打包出来。备份策略要结合业务容忍度决定备份频率,这里不再展开。

如何用Docker Compose部署Django+PostgreSQL应用

启动依赖与网络通信

Docker Compose 自动为服务创建默认网络,容器间通过服务名通信。web 服务要访问数据库,HOST 必须设置为 db,而不是 localhost。这个配置写在 settings.py 的环境变量 DB_HOST 里,默认值设为 'db' 就好。如果你本地开发也用了 Docker Compose,可以直接用这个配置;如果本地单独跑 PostgreSQL 服务,需要用不同的 .env 覆盖 DB_HOST 为 localhost。

关于启动顺序,depends_on 只能保证 db 容器启动,不能保证 PostgreSQL 实例就绪。Django 在数据库未就绪时迁移或启动会报错。我的做法是在 web 服务的 Dockerfile 里复制 wait-for-it.sh 脚本,然后在 docker-compose yml 的 web 服务 command 里加上类似 /wait-for-it.sh db:5432 — python manage.py runserver 0.0.0.0:8000。或者直接配置 PostgreSQL 的 healthcheck:

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
  interval: 5s
  timeout: 5s
  retries: 5

然后 web 的 depends_on 里加上 condition: service_healthy。这样 web 容器会等到数据库健康后再启动,避免反复重启。注意 healthcheck 依赖 pg_isready 工具,postgres 官方镜像自带,不需要额外安装。

验证与回滚

全部配置好之后,运行 docker-compose up -d 启动。观察容器状态:docker-compose ps 应该看到两个容器都是 Up 状态。然后进入 web 容器执行迁移:docker-compose exec web python manage.py migrate。如果没有报错,说明数据库连接正常。创建超级用户后尝试登录管理后台,确认读写正常。

如果需要回滚,最稳的方式是先停止当前版本:docker-compose down,然后用旧的镜像标签重新启动。如果用 volume 持久化了数据,数据库内容不会丢失。如果改动涉及数据库 schema,回滚前要准备好迁移的反向操作(比如 django migrate app 0001_previous),否则旧代码可能无法兼容新 schema。建议每次部署前都要先备份 volume,回滚时如果代码与数据不兼容,可以从备份恢复旧数据。

以上就是我用 Docker Compose 部署 Django + PostgreSQL 的常规做法。每个环节的配置都有对应检查点:环境变量一致性、数据卷声明、健康检查、连接主机名。按照这个顺序逐步确认,通常能一次性跑通。如果遇到问题,优先看容器日志,而不是盲目修改配置。