Skip to content

Docker 安装 PostgreSQL ​

参考仓库中的 MySQL 安装笔记,本文使用 Docker 官方镜像 postgres 启动单机 PostgreSQL,完成数据持久化、连接和基本排错。postgres:16 是 Docker Hub 上 docker.io/library/postgres:16 的简写,公开镜像通常可以匿名拉取;遇到 Docker Hub 拉取限额时可登录后重试。

下面以 postgres:16 为例,在 Linux/macOS 的 Bash 中启动一个仅供本机访问的实例。固定主版本便于控制升级,正式部署可进一步固定经过验证的具体版本或 digest。示例密码在交互提示中输入。

一、创建网络和数据卷 ​

bash
docker network create pg-net
docker volume create pg16-data

自定义网络使同一网络内的其他容器能够通过 pg16:5432 访问数据库。命名卷保留数据库文件,删除容器时不会随容器一起消失。

二、启动 PostgreSQL ​

bash
read -rsp 'PostgreSQL password: ' POSTGRES_PASSWORD; echo
export POSTGRES_PASSWORD

docker run --name pg16 --restart unless-stopped -d \
  --network pg-net \
  -p 127.0.0.1:5432:5432 \
  --mount type=volume,source=pg16-data,target=/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD \
  postgres:16

unset POSTGRES_PASSWORD

POSTGRES_PASSWORD 为新实例的数据库超级用户设置密码,不能为空。-e POSTGRES_PASSWORD 把当前 Shell 中的变量传入容器,避免把密码值写入命令历史;本地环境变量仍可能被同机有权限的进程读取,正式部署应使用适合环境的密钥管理方式。-p 127.0.0.1:5432:5432 只在宿主机回环地址开放端口;需要远程访问时,应另行设计网络和访问控制。

这里把卷挂到 PostgreSQL 16 默认的数据目录 /var/lib/postgresql/data。普通官方镜像 17 及以前的版本不能直接照搬 DHI 的父目录挂载方式:镜像在该子目录声明了卷,只挂父目录可能使数据库写入另一个匿名卷,重建容器后不会自动复用那份数据。

如果之前按 DHI 示例创建过 pg16-data,请为本次普通镜像部署使用一个新的空卷,并在命令中同步替换卷名;不要直接复用已有 DHI 数据卷。

三、验证与连接 ​

先检查容器和日志,再用镜像自带的 PostgreSQL 工具验证连接:

bash
docker ps --filter name=pg16
docker logs --tail 30 pg16
docker exec pg16 pg_isready -U postgres
docker exec pg16 psql -U postgres -d postgres -c 'SELECT current_user, current_database();'

没有设置 POSTGRES_USER、POSTGRES_DB 时,两者默认都是 postgres。从宿主机连接需要先安装 psql 客户端;-W 会提示输入密码:

bash
psql -h 127.0.0.1 -p 5432 -U postgres -d postgres -W

同处 pg-net 网络的应用容器应连接 pg16:5432,不需要经过宿主机映射端口;宿主机客户端则连接 127.0.0.1:5432。127.0.0.1 在另一个容器内指向那个容器自身,不能用来访问 PostgreSQL 容器。

需要验证数据确实留在卷内时,可写入一条测试数据后重启容器:

bash
docker exec pg16 psql -U postgres -d postgres -c \
  'CREATE TABLE IF NOT EXISTS container_check (id integer PRIMARY KEY); INSERT INTO container_check VALUES (1) ON CONFLICT DO NOTHING;'
docker stop pg16
docker start pg16
until docker exec pg16 pg_isready -U postgres; do sleep 1; done
docker exec pg16 psql -U postgres -d postgres -c 'SELECT * FROM container_check;'

最后一个查询应返回 id = 1。测试表会留在示例数据库中,不再需要时可自行删除。

四、数据目录、初始化与升级的特殊点 ​

  • 初始化变量只作用于新数据目录。 POSTGRES_USER 指定新建的数据库超级用户,默认 postgres;POSTGRES_DB 指定初始数据库,省略时使用 POSTGRES_USER 的值。修改已有容器的初始化变量不会修改数据库用户或密码。应用应另建权限受限的业务账号。
  • 不要无故指定初始化编码。 本文不设置 POSTGRES_INITDB_ARGS。默认情况下,initdb 根据容器内初始化环境的 locale 配置选择编码,不会直接继承宿主机的编码设置。只有业务明确要求固定编码或 locale 时,才通过该参数传入相应选项,并确认编码与 locale 兼容。初始化后可执行 SHOW server_encoding; 查看实际编码;修改该环境变量不会转换已有数据库的编码。
  • 不同主版本的挂载目录不同。 本文 postgres:16 挂载 /var/lib/postgresql/data;官方镜像 18 起默认 PGDATA 改为 /var/lib/postgresql/18/docker,推荐挂载父目录 /var/lib/postgresql。切换主版本时需同时核对目录布局。
  • 大版本升级不会自动完成。 把镜像从 postgres:16 改成 postgres:18,不会转换旧数据库文件。先备份,再选择 pg_dump/pg_restore 或 pg_upgrade,验证恢复与回滚方案后再切换。
  • 停机需要留出时间。 PostgreSQL 官方镜像同样使用 SIGINT 进行 fast shutdown:拒绝新连接、中止活动事务并执行检查点。数据量较大时可用 docker stop -t 30 pg16 延长等待时间,超时后 Docker 仍可能强制结束进程。

五、DHI 是什么,为什么本文默认不用 ​

原始参考链接介绍的是 Docker Hardened Images(DHI),例如 dhi.io/postgres。它是 Docker 托管并维护的安全加固镜像服务,不是托管数据库服务:数据库实例、数据卷和备份仍由使用者运行与管理。DHI 通过精简运行时组件、减少攻击面和持续安全维护提供更强的安全基线,但仍需正确配置权限、网络和更新策略。

对一般学习、本地开发及没有特定加固要求的部署,优先使用本文的 postgres 官方镜像即可。DHI 会增加账号登录、凭据分发和运行时适配工作,没有明确的安全、合规或组织标准要求时,无需为了安装 PostgreSQL 专门使用它。

确需使用 DHI 时,先完成以下准备:

  1. 注册 Docker 账号,并在目录中确认目标镜像、标签和可用权限。基础 DHI 可以使用免费账号开始,不应把“需要登录”理解为“一律付费”。企业定制、私有镜像或特定服务权益,应由组织管理员确认订阅及访问授权。
  2. 使用 Docker 账号登录 dhi.io;仅登录默认 Docker Hub 并不等于已经登录该仓库。官方入门命令为 docker login dhi.io。
  3. 使用双因素认证或 CI 时,使用符合 Docker 认证要求的访问令牌代替交互密码。凭据应通过 CI 密钥或凭据存储管理,不要写入文章、代码或 Dockerfile;执行拉取的构建节点也需具备相应凭据和权限。
  4. 遇到 unauthorized 或 denied 时,先检查登录的仓库地址、凭据有效期及目标仓库权限;登录成功不代表能够访问所有私有或定制镜像。

DHI 与普通镜像还存在下面的适配差异,不能只改镜像名:

关注点Docker Official Image postgresDocker Hardened Image dhi.io/postgres
数据目录17 及以前默认 /var/lib/postgresql/data;18 起采用版本化目录各版本均使用 /var/lib/postgresql/<主版本>/data
推荐挂载新版同样推荐挂载父目录 /var/lib/postgresql推荐挂载父目录 /var/lib/postgresql
运行时工具常见变体可用 Shell 和包管理器运行时变体通常没有 Shell、包管理器或调试工具
运行用户使用镜像配置的 PostgreSQL 用户运行时变体默认以非 root 用户运行

使用 DHI 时还需留意:

  • 目录由镜像管理。 PG_MAJOR 和 PGDATA 由 DHI 设置,不应覆盖。宿主机绑定目录还必须保证镜像的非 root 用户有读写权限。
  • 主机认证方式受限。 DHI 的 POSTGRES_HOST_AUTH_METHOD 支持 scram-sha-256 和 md5,不支持 trust 或 password。这项限制由入口脚本在初始化时执行;从别的镜像迁入的既有数据目录不会自动获得相同的保护。
  • 不能照搬进入容器的方式。 运行时镜像通常没有 sh/bash 和 apt/apk,但可直接 docker exec pg16 psql ...。需要调试时可用 docker logs 或官方建议的 Docker Debug;需要额外软件时应检查 dev 变体与多阶段构建方案。

旧的 postgres:13.9-alpine 示例把宿主机目录挂到 /var/lib/postgresql/data。迁移到 DHI 时,不要把该目录直接挂到 /var/lib/postgresql 后启动:目录布局和主版本都可能不匹配。先备份旧实例,在目标版本的新数据卷中初始化,再按 PostgreSQL 的跨版本迁移流程恢复和校验数据。

六、常见问题 ​

  • 容器启动后立即退出: 查看 docker logs pg16。先确认密码非空、数据卷可写,再核对数据目录是否属于当前 PostgreSQL 主版本。
  • 宿主机连不上: 检查 docker ps 的端口映射、5432 是否被占用,以及客户端是否连接 127.0.0.1;其他机器不能通过本文的回环地址映射访问。
  • 重启后新密码没有生效: 初始化环境变量不会修改已有数据库。使用 SQL 管理现有用户密码,并妥善更新应用配置。

参考资料 ​