版本说明
本文使用 Docker 在 Ubuntu 虚拟机中部署 PostgreSQL,并固定镜像版本为:
postgres:16.14-bookworm
不要使用 postgres:latest、postgres:16 或 postgres:16-bookworm 这类浮动标签。浮动标签后续可能指向新的镜像内容,重装、迁移或重新拉取时就可能出现和当初部署不一致的情况。
postgres:16.14-bookworm 的含义:
16.14:固定 PostgreSQL 16 的具体小版本。bookworm:固定 Debian 12 作为基础系统系列。
镜像标签可以在 Docker Hub PostgreSQL 官方镜像 查看。
前置条件
Ubuntu 虚拟机中需要先安装 Docker Engine 和 Docker Compose Plugin。如果还没有安装,可以参考本站的 Docker 入门:Ubuntu 安装与基础配置。
验证 Docker 是否可用:
docker version
docker compose version
创建部署目录
本文把 PostgreSQL 放在 /opt/postgresql 目录中,数据文件放在同级的 data 目录。
sudo mkdir -p /opt/postgresql
sudo chown -R "$USER:$USER" /opt/postgresql
cd /opt/postgresql
mkdir -p data
创建环境变量文件
cat > .env <<'EOF'
POSTGRES_VERSION=16.14-bookworm
POSTGRES_CONTAINER_NAME=postgres16
POSTGRES_DB=appdb
POSTGRES_USER=appuser
POSTGRES_PASSWORD=change-me-to-a-strong-password
POSTGRES_PORT=5432
EOF
建议马上修改 POSTGRES_PASSWORD。这个密码只会在第一次初始化数据库时生效,如果数据库目录已经初始化过,后面再改 .env 不会自动修改数据库里的用户密码。
创建 Docker Compose 文件
cat > compose.yaml <<'EOF'
services:
postgres:
image: postgres:${POSTGRES_VERSION}
container_name: ${POSTGRES_CONTAINER_NAME}
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "${POSTGRES_PORT}:5432"
volumes:
- ./data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
EOF
这里的 image 最终会解析成 postgres:16.14-bookworm,不会因为官方后续发布 PostgreSQL 17、18 或新的 Debian 基础镜像而自动变化。
如果只允许本机访问,可以把端口改成只监听 127.0.0.1:
ports:
- "127.0.0.1:${POSTGRES_PORT}:5432"
启动 PostgreSQL
docker compose up -d
查看容器状态:
docker compose ps
docker logs -f postgres16
第一次启动时,PostgreSQL 会初始化 ./data 目录。看到类似 database system is ready to accept connections 的日志,就说明数据库已经可以连接。
连接测试
进入容器使用 psql:
docker exec -it postgres16 psql -U appuser -d appdb
执行一条 SQL:
select version();
从其他机器连接时,先确认 Ubuntu 虚拟机 IP:
ip addr
然后在客户端连接:
psql -h <Ubuntu虚拟机IP> -p 5432 -U appuser -d appdb
防火墙设置
如果 Ubuntu 开启了 ufw,需要放行 PostgreSQL 端口。建议只允许可信网段访问,例如只允许 192.168.3.0/24:
sudo ufw allow from 192.168.3.0/24 to any port 5432 proto tcp
sudo ufw status
不要直接把数据库端口暴露到公网。如果必须远程访问,优先使用 VPN、SSH 隧道或只放行固定来源 IP。
修改密码
如果数据库已经初始化,修改 .env 中的 POSTGRES_PASSWORD 不会生效,需要进入数据库执行 SQL:
docker exec -it postgres16 psql -U appuser -d appdb
alter user appuser with password 'new-strong-password';
然后再把 .env 中的密码同步改掉,避免后续维护时混淆。
停止、启动和重启
cd /opt/postgresql
docker compose stop
docker compose start
docker compose restart
停止并删除容器,但保留数据:
docker compose down
删除 ./data 目录才会真正删除数据库数据,操作前一定要确认已经备份。
备份和恢复
备份单个数据库:
cd /opt/postgresql
docker exec postgres16 pg_dump -U appuser -d appdb -Fc > appdb_$(date +%F).dump
恢复到已有数据库:
cat appdb_2026-06-06.dump | docker exec -i postgres16 pg_restore -U appuser -d appdb --clean --if-exists
如果要恢复到一个全新的库,可以先创建数据库:
docker exec -it postgres16 createdb -U appuser appdb_restore
cat appdb_2026-06-06.dump | docker exec -i postgres16 pg_restore -U appuser -d appdb_restore
后续升级原则
固定版本部署后,不要随手把镜像改成 postgres:17、postgres:18 或 postgres:latest。
PostgreSQL 大版本升级不能只改镜像标签直接启动。比如从 16 升到 17,需要先备份,再按 PostgreSQL 官方升级流程处理,常见方式是 pg_dump / pg_restore 或 pg_upgrade。
如果只是 16 系列的小版本升级,也建议先备份,再把 .env 中的版本从:
POSTGRES_VERSION=16.14-bookworm
改成目标版本,然后重新拉取和启动:
docker compose pull
docker compose up -d
本文为了部署命令长期稳定,默认不自动升级镜像版本。