前端手摸手跑路之 AI 应用开发(四)

Docker Compose 管理 PostgreSQL:容器可以重建,数据不能丢

前面的用户数据保存在 Python 列表里,只要 FastAPI 重启,已经创建的用户就会消失

要让数据真正持久化,需要引入数据库。这一阶段先不写 SQLAlchemy,也不急着改业务代码,只解决一个更基础的问题:怎样稳定地启动 PostgreSQL,以及删除并重建容器后,数据为什么还能保留

一、先分清镜像、容器与 Compose

这三个概念经常一起出现,但职责不同:

text 复制代码
Image
→ 创建容器的只读模板

Container
→ 镜像的一次运行实例

Docker Compose
→ 根据 compose.yaml 统一描述和管理一组服务

postgres:17.10 是镜像,运行它后得到 PostgreSQL 容器;docker compose 则负责按配置创建、启动、停止和删除这个容器

可以把镜像理解为系统安装模板,容器是用模板创建出来的运行环境

二、用 compose.yaml 描述 PostgreSQL

项目根目录创建 compose.yaml

yaml 复制代码
services:
  postgres:
    image: postgres:17.10

    environment:
      POSTGRES_USER: ai_workspace
      POSTGRES_PASSWORD: ai_workspace_dev
      POSTGRES_DB: ai_workspace

    ports:
      - "5432:5432"

    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

这里声明了一个名为 postgres 的服务,使用 PostgreSQL 17.10 镜像

三个环境变量只在数据库第一次初始化时使用:

text 复制代码
POSTGRES_USER
→ 创建数据库用户

POSTGRES_PASSWORD
→ 设置该用户的密码

POSTGRES_DB
→ 创建默认数据库

这里的密码只适合本地学习环境,不能照搬到生产环境

三、端口映射的方向

配置中的端口格式是:

text 复制代码
宿主机端口:容器端口

因此:

yaml 复制代码
ports:
  - "5432:5432"

表示访问电脑上的 5432,Docker 会把连接转发到 PostgreSQL 容器内部的 5432

如果电脑上的 5432 已经被占用,可以改成:

yaml 复制代码
ports:
  - "15432:5432"

这时,在宿主机运行的 FastAPI 应连接:

text 复制代码
localhost:15432

PostgreSQL 容器内部仍然监听默认的 5432

四、启动并检查服务

在项目根目录执行:

bash 复制代码
cd /d/code/ai-workspace-rebuild  # 进入包含 compose.yaml 的项目根目录

docker compose config  # 解析并显示 Compose 最终配置

docker compose up -d  # 创建并在后台启动服务

docker compose ps  # 查看当前 Compose 项目的容器状态

docker compose logs postgres  # 查看 postgres 服务日志

up 表示创建并启动服务,-d--detach 的缩写,让容器在后台运行

config 适合在启动前检查 YAML 是否能够被 Compose 正确解析;ps 用来确认容器是否运行;logs postgres 用来判断 PostgreSQL 是否已经完成初始化并开始接受连接

五、数据究竟保存在哪里

最关键的是这一行:

yaml 复制代码
volumes:
  - postgres_data:/var/lib/postgresql/data

格式是:

text 复制代码
命名卷:容器内目录

PostgreSQL 把数据库文件写入 /var/lib/postgresql/data。这个目录挂载了命名卷 postgres_data,所以文件实际由 Docker 的 volume 保存

命名卷的生命周期独立于容器:容器可以删除,卷仍然保留

六、进入 PostgreSQL 做持久化实验

进入正在运行的数据库容器:

bash 复制代码
docker compose exec postgres \
  psql -U ai_workspace -d ai_workspace

参数含义:

text 复制代码
exec postgres
→ 在 postgres 服务容器中执行命令

psql
→ 打开 PostgreSQL 命令行客户端

-U ai_workspace
→ 使用 ai_workspace 用户

-d ai_workspace
→ 连接 ai_workspace 数据库

\
→ Bash 命令尚未结束,下一行继续输入

psql 中创建测试表:

sql 复制代码
CREATE TABLE persistence_test (
    message text NOT NULL
);

写入一条容易辨认的数据:

sql 复制代码
INSERT INTO persistence_test (message)
VALUES ('volume keeps this row');

查询确认:

sql 复制代码
SELECT * FROM persistence_test;

SQL 可以换行输入,直到分号 ; 出现后才会执行;如果未完成的 SQL 不想继续,可以按 Ctrl+C 取消;输入 \q 退出 psql

七、删除容器,再重新创建

退出 psql 后执行:

bash 复制代码
docker compose down  # 删除当前项目的容器和默认网络,保留命名卷

docker compose ps -a  # 确认当前项目已经没有容器

docker volume ls --filter name=ai-workspace-rebuild  # 查看项目相关命名卷

容器已经被删除,但类似下面的命名卷仍然存在:

text 复制代码
ai-workspace-rebuild_postgres_data

重新创建容器:

bash 复制代码
docker compose up -d  # 使用同一份配置重新创建 PostgreSQL 容器

再次进入数据库:

bash 复制代码
docker compose exec postgres \
  psql -U ai_workspace -d ai_workspace

重新查询:

sql 复制代码
SELECT * FROM persistence_test;

结果仍然包含:

text 复制代码
volume keeps this row

这证明保留数据的不是旧容器,而是重新挂载到新容器上的同一个命名卷

八、down 与 down -v 的区别

bash 复制代码
docker compose down  # 删除容器和默认网络,保留命名卷

如果加上 -v

bash 复制代码
docker compose down -v  # 同时删除 Compose 管理的命名卷

-v--volumes 的缩写。数据库文件保存在卷里,卷被删除后,当前数据库数据也会消失

因此,日常停止和重建开发容器时,不应该随手添加 -v

九、宿主机与容器中的数据库地址不同

当 FastAPI 在宿主机运行时,连接地址使用宿主机暴露的端口:

text 复制代码
localhost:5432

如果 FastAPI 以后也放进 Compose,localhost 将指向 FastAPI 容器自己,不再指向电脑,更不会指向 PostgreSQL 容器

同一个 Compose 网络中的服务可以通过服务名互相访问:

text 复制代码
FastAPI 容器 → postgres:5432 → PostgreSQL 容器

这里的 postgres 来自:

yaml 复制代码
services:
  postgres:

因此,两种运行方式对应两种地址:

text 复制代码
FastAPI 在宿主机运行
→ localhost:5432

FastAPI 在 Compose 容器中运行
→ postgres:5432

阶段结果

现在 PostgreSQL 已经能够稳定启动,删除并重建容器后数据也不会丢失

但业务接口还没有真正连接数据库:

  • 用户仍然保存在 Python 内存列表中
  • FastAPI 还不知道数据库连接地址
  • 还没有 SQLAlchemy Engine
  • 还没有 ORM 模型和数据库迁移
  • 还没有用 Repository 替换内存存储

下一阶段将使用 SQLAlchemy 和 psycopg 建立 Python 到 PostgreSQL 的连接,再逐步把用户数据迁移到数据库中

相关推荐
可涵不会debug44 分钟前
LangChain 文本分割器详解:字符分割、Token 分割、硬约束递归分割实战
java·前端·数据库
LEE1 小时前
Agent 的控制权,为什么正在回到模型手里?
前端·后端
沃夫上校1 小时前
跨域这件事,其实浏览器在替你挡刀
前端·后端·nginx
十年一梦惊觉醒1 小时前
快手视频发布助手,全自动视频发布带货工具
开发语言·前端·javascript
Solara1 小时前
中文字体子集化实录:3.2MB → 200KB 的完整脚本、踩坑清单与三条反直觉经验
前端·css·架构
Htr_1 小时前
Cortex 使用指南:开源 API 知识层
前端·数据库·人工智能·重构·计算机外设
计算机魔术师1 小时前
Dario Amodei 发文呼吁 AI 行业放慢前沿速度并公布三步计划
前端
EatFan1 小时前
前后端分离项目中 Token 到底应该怎么设计?Access Token + Refresh Token 实战
java·前端·后端
dsyyyyy11011 小时前
Typescript装饰器
前端·javascript·typescript