版本说明

本文使用 Docker 在 Ubuntu 虚拟机中部署 PostgreSQL,并固定镜像版本为:

postgres:16.14-bookworm

不要使用 postgres:latestpostgres:16postgres: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:17postgres:18postgres:latest

PostgreSQL 大版本升级不能只改镜像标签直接启动。比如从 16 升到 17,需要先备份,再按 PostgreSQL 官方升级流程处理,常见方式是 pg_dump / pg_restorepg_upgrade

如果只是 16 系列的小版本升级,也建议先备份,再把 .env 中的版本从:

POSTGRES_VERSION=16.14-bookworm

改成目标版本,然后重新拉取和启动:

docker compose pull
docker compose up -d

本文为了部署命令长期稳定,默认不自动升级镜像版本。