背景

我在开发一个前后端项目时,后端连接的是A地服务器上的 PostgreSQL 数据库。平时在 A 地开发没有问题,因为电脑和服务器在同一个网络里,可以直接连接数据库。

但是问题来了:我下周要带着这台电脑去B地开发,B地网络肯定访问不到我A地的内网数据库。也就是说,项目代码在电脑上,但数据库在A地的服务器上。一旦离开A地的网络,后端就无法正常启动,接口也无法调试。

最初的连接方式是:

我的电脑 -> A地网络 -> A地服务器 PostgreSQL

去B地后需要变成:

我的电脑 -> 本机 Docker PostgreSQL

这篇文章记录我是如何把A地数据库复制到本机 Docker 里,让自己在B地也能继续开发的。
在这里插入图片描述

最终方案

核心思路很简单:

  1. 在自己的电脑上安装 Docker Desktop。
  2. 用 Docker 在本机启动 PostgreSQL 和 Redis。
  3. 在离开 A 地之前,把A地服务器数据库导出一份备份。
  4. 把备份导入本机 Docker PostgreSQL。
  5. 把项目的 DATABASE_URL 改成本地数据库地址。

这样即使到了B地,访问不到A地的数据库,也可以继续开发。

为什么用 Docker

导师提到可以本地安装 Docker。这里 Docker 的作用不是帮我们连接A地的数据库,而是让电脑本地跑一个数据库。

也就是说,Docker 解决的是:

B地连不上A地数据库,但我电脑本地可以自己跑一个数据库

相比直接在 Windows 上安装 PostgreSQL,用 Docker 有几个好处:

  • 环境更干净,不容易污染系统。
  • 数据库版本可控。
  • 以后换电脑或重装环境更方便。
  • PostgreSQL、Redis 等服务可以用一条命令启动。

安装 Docker Desktop

在 Windows 上安装 Docker Desktop 时,需要 WSL2 支持。

如果 Docker Desktop 提示 WSL 没安装,可以用管理员 PowerShell 执行:

wsl --install --no-distribution
wsl --update
wsl --set-default-version 2

如果提示需要重启电脑,就先重启。

安装完成后,检查 Docker 是否可用:

docker --version
docker compose version
wsl --list --verbose

正常情况下可以看到 Docker 版本,以及类似下面的 WSL 发行版:

docker-desktop    Running    2

关于 C 盘和 D 盘

Docker Desktop 主程序可以装在 C 盘,这个问题不大。真正占空间的是 Docker 镜像、容器和数据库数据。

安装完成后,可以在 Docker Desktop 里设置数据目录:

Settings -> Resources -> Advanced -> Disk image location

建议改到:

D:\software\DockerData

这样以后下载的镜像、本地 PostgreSQL 数据等主要会占用 D 盘空间。

需要注意:WSL 系统组件本身属于 Windows 功能,通常还是会在 C 盘。这个体积一般不是主要问题,真正大的数据可以迁到 D 盘。

准备 Docker Compose 文件

我在项目根目录准备了一个本地开发用的 docker-compose.dev.yml

services:
  postgres:
    image: postgres:16-alpine
    container_name: codestory-postgres
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-devpass}
      POSTGRES_DB: ${POSTGRES_DB:-codestory}
    ports:
      - '${POSTGRES_PORT:-55432}:5432'
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-codestory}']
      interval: 5s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    container_name: codestory-redis-dev
    ports:
      - '${REDIS_PORT:-6379}:6379'
    volumes:
      - redis_dev_data:/data
    restart: unless-stopped

volumes:
  postgres_data:
  redis_dev_data:

这里 PostgreSQL 暴露到本机的端口是 55432,不是 5432。原因是我电脑上本来就有一个 PostgreSQL 占用了 5432,所以 Docker 里的 PostgreSQL 改用 55432,避免端口冲突。

启动本地数据库

在项目根目录执行:

docker compose -f docker-compose.dev.yml up -d postgres redis

第一次执行时会下载镜像:

postgres:16-alpine
redis:7-alpine

下载完成后会启动两个容器:

codestory-postgres
codestory-redis-dev

可以用下面的命令查看运行状态:

docker ps

备份A地服务器数据库

离开 A 地之前,一定要在还能连接A地服务器数据库的时候导出备份。

备份命令:

docker run --rm -v "${PWD}:/backup" postgres:16-alpine pg_dump -Fc "postgresql://用户名:密码@A地服务器地址:5432/数据库名?schema=public" -f /backup/codestory-dev.dump

这里的数据库连接地址就是项目原来使用的 DATABASE_URL

注意:DATABASE_URL 里通常包含数据库密码,不要截图发给别人,也不要提交到 Git。

备份成功后,项目根目录会出现:

codestory-dev.dump

建议在 .gitignore 里加入:

*.dump
*.backup

避免把数据库备份误提交。

导入到本地 Docker PostgreSQL

先把备份文件复制进 PostgreSQL 容器:

docker cp codestory-dev.dump codestory-postgres:/tmp/codestory-dev.dump

再执行恢复:

docker exec codestory-postgres pg_restore -U postgres -d codestory --clean --if-exists --no-owner /tmp/codestory-dev.dump

如果没有报错,一般就说明导入成功。

可以查看有哪些表:

docker exec codestory-postgres psql -U postgres -d codestory -c "\dt"

也可以查看关键表的数据量:

docker exec codestory-postgres psql -U postgres -d codestory -c "select 'users' as table_name, count(*) from users union all select 'courses', count(*) from courses union all select 'chapters', count(*) from chapters union all select 'lessons', count(*) from lessons union all select 'exercises', count(*) from exercises;"

修改项目数据库连接

导入完成后,把项目后端的 .env 改成本机 Docker 数据库:

DATABASE_URL=postgresql://postgres:devpass@localhost:55432/codestory?schema=public
REDIS_URL=redis://localhost:6379

注意端口是 55432

如果你没有端口冲突,也可以使用 5432。但我这里因为本机已有 PostgreSQL,所以 Docker PostgreSQL 使用 55432

验证 Prisma 能连接数据库

如果项目使用 Prisma,可以在后端目录执行:

npx prisma db pull --print

只要没有认证失败、连接失败之类的错误,就说明后端能连接到本地数据库。

也可以正常启动后端:

cd backend
pnpm run dev

用 Navicat 查看数据库

如果想用 Navicat、DBeaver、DataGrip 或 pgAdmin 查看本地 Docker 数据库,连接信息如下:

类型:PostgreSQL
主机:localhost
端口:55432
初始数据库:codestory
用户名:postgres
密码:devpass
SSL:关闭

连接成功后,就可以直接查看 userscourseslessonsexercises 等表。

每次开发前要做什么

以后每次开发前,先确保 Docker Desktop 已经启动。

然后在项目根目录执行:

docker compose -f docker-compose.dev.yml up -d postgres redis

如果容器已经在运行,重复执行这条命令也没关系,它不会清空数据库,也不会重复创建数据。

可以用下面命令确认:

docker ps

如果能看到:

codestory-postgres
codestory-redis-dev

说明本地数据库已经在运行。

Navicat 没有关,不代表数据库一定在运行。Navicat 只是客户端,真正的数据库服务由 Docker 容器提供。

这套方案解决了什么

最后形成的开发方式是:

在 A 地:
电脑 -> A地服务器数据库

去B地:
电脑 -> 本机 Docker PostgreSQL

这样就算B地网络访问不到A地的服务器,也可以继续开发、调接口、看数据。

需要同步的内容分两类:

  • 代码:用 Git 同步。
  • 数据库结构:用 Prisma migration 或 SQL migration 同步。
  • 开发数据:离开 A 地前导出一份备份,导入本机 Docker。

注意事项

不要直接把A地数据库端口暴露到公网。这样虽然能远程连数据库,但安全风险很高。

如果一定要在B地实时连接A地的服务器,应该使用:

  • Tailscale
  • ZeroTier
  • WireGuard
  • VPN

但对于日常开发来说,本地 Docker 数据库更稳定,也不依赖网络。

总结

这次问题的本质不是代码问题,而是开发环境依赖了A地的内网数据库。一旦离开这个网络,项目就失去了关键依赖。

Docker 的作用是把这个依赖本地化:

远程数据库依赖 -> 本机 Docker 数据库

最终我实现了:

  • Docker Desktop 正常运行。
  • 本地 PostgreSQL 和 Redis 正常启动。
  • A地数据库成功备份并导入本机。
  • 项目后端改为连接本地 Docker 数据库。
  • Navicat 可以正常查看本地数据库。

这样去B地以后,只要启动 Docker,本机就有完整的开发数据库环境,可以继续开发。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐