Docker 官方 Postgres 镜像
PostgreSQL,通常简称为“Postgres”,是一种对象关系型数据库管理系统(ORDBMS),强调可扩展性和标准合规性。作为数据库服务器,其主要功能是安全地存储数据,支持最佳实践,并在其他软件应用程序请求时检索数据,无论是运行在同一台计算机上的应用还是通过网络(包括互联网)运行在另一台计算机上的应用。它可以处理从小型单机应用到大型面向互联网的应用的各种工作负载,支持大量并发用户。最近的版本还提供了数据库本身的复制功能,以增强安全性和可扩展性。
PostgreSQL 实现了 SQL:2011 标准的大部分内容,是 ACID 兼容和事务性的(包括大多数 DDL 语句),通过多版本并发控制(MVCC)避免锁定问题,提供对脏读的免疫和完全可串行化;使用多种索引方法处理复杂的 SQL 查询,这些方法在其他数据库中不可用;具有可更新视图和物化视图、触发器、外键;支持函数和存储过程,以及其他可扩展性功能,并拥有大量由第三方编写的扩展。除了能够与主要的专有和开源数据库协同工作外,PostgreSQL 还支持从这些数据库的迁移,通过其广泛的标准 SQL 支持和可用的迁移工具实现。如果使用了专有扩展,PostgreSQL 的可扩展性还可以通过一些内置的和第三方开源兼容性扩展来模拟许多功能,例如对 Oracle 的兼容性。
使用 docker CLI 启动容器:
1 | docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres |
使用 Docker Compose 启动容器:
1 | # Use postgres/example user/password credentials |
一、环境变量
环境变量 | 作用 |
---|---|
POSTGRES_PASSWORD |
|
POSTGRES_USER |
|
POSTGRES_DB |
|
POSTGRES_INITDB_ARGS |
|
POSTGRES_INITDB_WALDIR |
|
POSTGRES_HOST_AUTH_METHOD |
|
PGDATA |
1、POSTGRES_PASSWORD
此环境变量是使用 PostgreSQL 镜像所必需的。它不能为空或未定义。此环境变量设置 PostgreSQL 的超级用户密码。默认的超级用户由 POSTGRES_USER
环境变量定义。
注意:
- PostgreSQL 镜像在本地设置了信任认证,因此在从 localhost(同一容器内)连接时可能不需要密码。然而,从不同主机/容器连接时则需要密码。
- 此变量定义了 PostgreSQL 实例中的超级用户密码,这是在初始容器启动时由
initdb
脚本设置的。它不会影响运行时psql
客户端可能使用的PGPASSWORD
环境变量,具体参见 libpq-envars | PostgreSQL 文档。如果使用PGPASSWORD
,它将作为一个单独的环境变量指定。
2、POSTGRES_USER
这个可选的环境变量与 POSTGRES_PASSWORD
一起使用,用于设置用户及其密码。此变量将创建一个具有超级用户权限的指定用户,并创建一个同名的数据库。如果不指定,则默认使用 postgres
用户。
注意:如果指定了此参数,PostgreSQL 仍会在初始化期间显示“属于此数据库系统的文件将由用户 ‘postgres’ 所有”。这指的是镜像中 /etc/passwd
文件中的 Linux 系统用户,该用户运行 postgres
守护进程,与 POSTGRES_USER
选项无关。详情请参见“任意 –user 注释”部分。
3、POSTGRES_DB
这个可选的环境变量可用于在首次启动镜像时定义默认数据库的名称。如果不指定,则使用 POSTGRES_USER
的值。
4、POSTGRES_INITDB_ARGS
这个可选的环境变量可用于向 postgres initdb
发送参数。值是一个由空格分隔的参数字符串,形式与 postgres initdb
所期望的一致。这对于添加类似数据页校验和的功能非常有用,例如 -e POSTGRES_INITDB_ARGS="--data-checksums"
。
5、POSTGRES_INITDB_WALDIR
这个可选的环境变量可用于定义 Postgres 事务日志的另一个位置。默认情况下,事务日志存储在主 Postgres 数据文件夹(PGDATA
)的子目录中。有时,将事务日志存储在具有不同性能或可靠性特性的存储中可能是有益的。
注意:在 PostgreSQL 9.x 版本中,此变量为 POSTGRES_INITDB_XLOGDIR
(反映了 PostgreSQL 10+ 中 --xlogdir
标志更改为 --waldir
)。
6、POSTGRES_HOST_AUTH_METHOD
这个可选的环境变量可用于控制所有数据库、所有用户和所有地址的主机连接认证方法。如果不指定,则使用 scram-sha-256
密码认证(14+ 版本;旧版本使用 md5
)。在未初始化的数据库中,这将通过以下近似行填充 pg_hba.conf
:
1 | echo "host all all all $POSTGRES_HOST_AUTH_METHOD" >> pg_hba.conf |
有关可能的值及其含义的更多信息,请参见 PostgreSQL 文档中的 pg_hba.conf 部分
**注意 **:
- 不建议使用
trust
,因为它允许任何人无需密码即可连接,即使设置了密码(如通过POSTGRES_PASSWORD
设置)。更多详细信息请参见 PostgreSQL 文档中的信任认证部分。 - 如果将
POSTGRES_HOST_AUTH_METHOD
设置为trust
,则不需要POSTGRES_PASSWORD
。 - 如果将此值设置为其他值(如
scram-sha-256
),可能需要额外的POSTGRES_INITDB_ARGS
以便数据库正确初始化(如POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256
)。
7、PGDATA
重要提示:当挂载卷到 /var/lib/postgresql
时,/var/lib/postgresql/data
路径是容器运行时的本地卷,因此数据不会持久化到挂载的卷上。
这个可选的环境变量可用于定义数据库文件的另一个位置,例如子目录。默认值为 /var/lib/postgresql/data
。如果使用的数据卷是文件系统挂载点(如 GCE 持久磁盘),或远程文件夹(如某些 NFS 挂载),或包含文件夹/文件(如 lost+found
),则需要在挂载点内创建一个子目录来存放数据。
二、Docker Secrets
作为通过环境变量传递敏感信息的替代方案,可以在前面提到的一些环境变量后面附加 _FILE
,这会使初始化脚本从容器中存在的一些文件中加载这些变量的值。特别是,这可以用于从存储在 /run/secrets/<secret_name>
文件中的 Docker 密钥中加载密码。例如:
1 | $ docker run --name some-postgres -e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd -d postgres |
目前,这种方法仅支持以下环境变量:POSTGRES_INITDB_ARGS
、POSTGRES_PASSWORD
、POSTGRES_USER
和 POSTGRES_DB
。
三、初始化脚本
如果希望在镜像之外进行额外的初始化,可以在 /docker-entrypoint-initdb.d
目录下添加一个或多个 *.sql
、*.sql.gz
或 *.sh
脚本(必要时创建该目录)。在入口点调用 initdb
创建默认的 postgres
用户和数据库之后,它会运行该目录中找到的所有 *.sql
文件,执行所有可执行的 *.sh
脚本,并且获得化所有不可执行的 *.sh
脚本,以在启动服务之前进行进一步的初始化。
警告:只有在使用空数据目录启动容器时,/docker-entrypoint-initdb.d
目录中的脚本才会运行;任何预存在的数据库在容器启动时都不会受到影响。一个常见的问题是,如果其中一个 /docker-entrypoint-initdb.d
脚本失败(这将导致入口点脚本退出),而你的编排器重新启动带有已初始化数据目录的容器,它将不会继续执行你的脚本。
例如,要添加一个额外的用户和数据库,可以将以下内容添加到 /docker-entrypoint-initdb.d/init-user-db.sh
:
1 | !/bin/bash |
这些初始化文件将按当前区域设置定义的排序名称顺序执行,默认区域设置为 en_US.utf8
。任何 *.sql
文件都将由 POSTGRES_USER
执行,默认为 postgres
超级用户。建议在 *.sh
脚本中运行的任何 psql
命令都使用 --username "$POSTGRES_USER"
标志以 POSTGRES_USER
身份执行。由于容器内部的 Unix 套接字连接存在信任认证,此用户可以无需密码连接。
此外,自 docker-library/postgres#253 起,这些初始化脚本将以 postgres
用户身份运行(或以 docker run
命令的 --user
标志指定的“半任意用户”身份运行;详情参见“任意 –user 注释”部分)。自 docker-library/postgres#440 起,为这些初始化脚本启动的临时守护进程仅监听 Unix 套接字,因此任何 psql
使用都应该省略主机名部分(例如,参见 docker-library/postgres#474 (评论))。
四、数据库配置
有许多方法可以设置 PostgreSQL 服务器配置。关于可用的配置选项,可以参考你正在运行的 PostgreSQL 版本的 PostgreSQL 文档。以下是几种设置配置的方法:
1、使用自定义配置文件
创建配置文件并将其放入容器中。如果你需要一个配置文件的起点,可以使用 PostgreSQL 提供的样本配置文件,该文件在容器中的路径为 /usr/share/postgresql/postgresql.conf.sample
(Alpine 变体中的路径为 /usr/local/share/postgresql/postgresql.conf.sample
)。
重要提示:必须设置 listen_addresses = '*'
,以便其他容器能够访问 PostgreSQL。
1 | # 获取默认配置 |
2、直接在运行命令中设置选项
入口点脚本的设计:入口点脚本设计为将传递给 Docker 命令的任何选项转发给 PostgreSQL 服务器守护进程。根据 PostgreSQL 文档,任何在 .conf
文件中可用的选项都可以通过 -c
设置。
1 | $ docker run -d --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword postgres -c shared_buffers=256MB -c max_connections=200 |
3、示例
获取默认配置文件:
1 | $ docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf |
编辑 my-postgres.conf
文件,添加或修改所需的配置项。例如:
1 | listen_addresses = '*' |
使用自定义配置文件运行 PostgreSQL:
1 | $ docker run -d --name some-postgres -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf -e POSTGRES_PASSWORD=mysecretpassword postgres -c 'config_file=/etc/postgresql/postgresql.conf' |
直接在运行命令中设置选项:
1 | $ docker run -d --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword postgres -c shared_buffers=256MB -c max_connections=200 |
五、语言环境自定义
你可以通过一个简单的 Dockerfile 扩展基于 Debian 的镜像来设置不同的语言环境。以下示例将默认语言环境设置为 de_DE.utf8
:
1 | FROM postgres:14.3 |
由于数据库初始化仅在容器启动时发生,这允许我们在数据库创建之前设置语言环境。
值得注意的是,从 PostgreSQL 15 开始,基于 Alpine 的变体支持 ICU 语言环境。之前的基于 Alpine 的 PostgreSQL 版本不支持语言环境;更多详细信息请参见 musl 文档 中的“字符集和语言环境”。
你可以在基于 Alpine 的镜像中使用 POSTGRES_INITDB_ARGS
来设置不同的语言环境。以下示例将新初始化的数据库的默认语言环境设置为 de_DE.utf8
:
1 | docker run -d -e LANG=de_DE.utf8 -e POSTGRES_INITDB_ARGS="--locale-provider=icu --icu-locale=de-DE" -e POSTGRES_PASSWORD=mysecretpassword postgres:15-alpine |
六、数据存储位置
有多种方法可以存储运行在 Docker 容器中的应用程序所使用的数据。
让 Docker 管理数据库数据存储:通过将数据库文件写入主机系统的磁盘,使用 Docker 内部的卷管理。这是默认选项,操作简单且对用户来说相对透明。缺点是文件可能难以被直接在主机系统上运行的工具和应用程序定位,即在容器外部。
在主机系统上创建数据目录并将其挂载到容器内的目录:这将数据库文件放置在主机系统上的已知位置,使主机系统上的工具和应用程序可以轻松访问这些文件。缺点是用户需要确保该目录存在,并且主机系统上的目录权限和其他安全机制设置正确。
Docker 文档是理解不同存储选项和变化的好起点,同时有许多博客和论坛帖子讨论并提供建议。这里我们仅展示上述第二种选项的基本步骤:
七、镜像选择
PostgreSQL 镜像有多种变体,每个变体都针对特定的使用场景设计。
1、postgres:<version>
这是默认的镜像。如果你不确定自己的需求是什么,通常应该选择这一种。它设计为既可以作为一次性容器使用(挂载源代码并启动容器以启动应用),也可以作为构建其他镜像的基础。
这些标签中可能包含如 bookworm
或 bullseye
这样的名称。这些是 Debian 发行版的套件代码名称,指示镜像基于哪个 Debian 发行版。如果你的镜像需要安装超出镜像自带的额外包,建议明确指定其中一个以最小化因 Debian 新发行版带来的破坏。
2、postgres:<version>-alpine
此镜像是基于流行的 Alpine Linux 项目,可在官方的 alpine 镜像中找到。Alpine Linux 的体积远小于大多数发行版的基础镜像(约 5MB),因此通常会导致更精简的镜像。
这种变体适用于最终镜像大小尽可能小的情况。主要需要注意的是,它使用的是 musl libc 而不是 glibc 及其相关库,因此软件可能会因 libc 需求/假设的深度而遇到问题。更多关于可能出现的问题和使用 Alpine 基础镜像的优缺点讨论,可以参见 Hacker News 的评论线程。
为了最小化镜像大小,Alpine 基础镜像通常不包含额外的相关工具(如 git
或 bash
)。使用此镜像作为基础时,可以在你自己的 Dockerfile 中添加所需的内容(如果你不熟悉如何安装包,可以参见 alpine 镜像描述 中的示例)。
相关链接
postgres - Official Image | Docker Hub
docs/postgres/README.md at master · docker-library/docs
PostgreSQL: Documentation: 16: Chapter 20. Server Configuration
PostgreSQL 文档中的 pg_hba.conf 部分
docker-library/postgres#474 (评论))
OB links
OB tags
#Docker #PostgreSQL #数据库