Skip to content

快速参考

  • 由……维护
    PostgreSQL Docker 社区

  • 何处获取帮助:
    Docker 社区 Slack、服务器故障、Unix & Linux 或 Stack Overflow

支持的标签及相应的 Dockerfile 链接

快速参考(续)

什么是 PostgreSQL?

PostgreSQL,通常简称为“Postgres”,是一个对象关系型数据库管理系统(ORDBMS),强调可扩展性和符合标准。作为数据库服务器,其主要功能是安全地存储数据并支持最佳实践,然后根据其他软件应用程序(无论是同一台计算机上的还是通过网络(包括互联网)在另一台计算机上运行的那些应用程序)的请求检索数据。它可以处理从小型单机应用程序到具有许多并发用户的面向互联网的大型应用程序的工作负载。最近的版本还提供了数据库本身的复制以实现安全性和可扩展性。

PostgreSQL 实现了大部分 SQL:2011 标准,符合 ACID 且具有事务性(包括大多数 DDL 语句),通过多版本并发控制(MVCC)避免锁定问题,提供对脏读的免疫和完全可序列化;使用许多其他数据库中不可用的索引方法处理复杂的 SQL 查询;具有可更新视图和物化视图、触发器、外键;支持函数和存储过程以及其他可扩展性,并且有大量由第三方编写的扩展。除了可以与主要的专有和开源数据库一起工作之外,PostgreSQL 通过其广泛的标准 SQL 支持和可用的迁移工具支持从它们进行迁移。并且如果使用了专有扩展,通过其可扩展性可以通过一些内置和第三方开源兼容性扩展来模拟许多扩展,例如对于 Oracle。

wikipedia.org/wiki/PostgreSQL(维基百科关于 PostgreSQL 的页面)

logo

如何使用此图像

启动一个 Postgres 实例

$ docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres

在入口点使用 initdb 创建默认的 postgres 用户和数据库。

postgres 数据库是一个默认数据库,供用户、实用程序和第三方应用程序使用。

postgresql.org/docs

……或通过 psql

$ docker run -it --rm --network some-network postgres psql -h some-postgres -U postgres
psql (14.3)
Type "help" for help.

postgres=# SELECT 1;
 ?column? 
----------
        1
(1 row)

通过 docker-composedocker stack deploy

示例 docker-compose.yml 用于 postgres

# Use postgres/example user/password credentials
version: '3.9'

services:

  db:
    image: postgres
    restart: always
    # set shared memory limit when using docker-compose
    shm_size: 128mb
    # or set shared memory limit when deploy via swarm stack
    #volumes:
    #  - type: tmpfs
    #    target: /dev/shm
    #    tmpfs:
    #      size: 134217728 # 128*2^20 bytes = 128Mb
    environment:
      POSTGRES_PASSWORD: example

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

Try in PWD

运行 docker stack deploy -c stack.yml postgres (或 docker-compose -f stack.yml up ),等待其完全初始化,然后访问 http://swarm-ip:8080http://localhost:8080http://host-ip:8080 (视情况而定)。

如何扩展此图像

有许多方法可以扩展 postgres 图像。在不试图支持每种可能的用例的情况下,这里仅介绍一些我们发现有用的方法。

环境变量

PostgreSQL 镜像使用了几个容易被忽略的环境变量。唯一需要的变量是 POSTGRES_PASSWORD ,其余的都是可选的。

警告:只有在使用空数据目录启动容器时,Docker 特定变量才会生效;在容器启动时,任何预先存在的数据库都将保持不变。

POSTGRES_PASSWORD

此环境变量是你使用 PostgreSQL 镜像所必需的。它不能为空或未定义。此环境变量设置 PostgreSQL 的超级用户密码。默认超级用户由 POSTGRES_USER 环境变量定义。

注意 1:PostgreSQL 镜像在本地设置了 trust 身份验证,因此当从 localhost (在同一个容器内)连接时,您可能会注意到不需要密码。然而,如果从不同的主机/容器连接,则需要密码。

注意 2:此变量定义了 PostgreSQL 实例中的超级用户密码,由 initdb 脚本在初始容器启动期间设置。它对 PGPASSWORD 环境变量没有影响,该环境变量可能在运行时被 psql 客户端使用,如 https://www.postgresql.org/docs/14/libpq-envars.html 中所述。 PGPASSWORD (如果使用)将被指定为一个单独的环境变量。

POSTGRES_USER

此可选环境变量与 POSTGRES_PASSWORD 结合使用来设置用户及其密码。该变量将创建具有超级用户权限的指定用户以及同名数据库。如果未指定,则将使用 postgres 的默认用户。

请注意,如果指定此参数,PostgreSQL 在初始化期间仍将显示 The files belonging to this database system will be owned by user "postgres" 。这指的是 postgres 守护进程以其运行的 Linux 系统用户(来自图像中的 /etc/passwd ),因此与 POSTGRES_USER 选项无关。有关更多详细信息,请参阅标题为“任意 --user 注释”的部分。

POSTGRES_DB

这个可选的环境变量可用于为首次启动镜像时创建的默认数据库定义不同的名称。如果未指定,则将使用 POSTGRES_USER 的值。

POSTGRES_INITDB_ARGS

这个可选的环境变量可用于向 postgres initdb 发送参数。其值是一个以空格分隔的参数字符串,就像 postgres initdb 期望的那样。这对于添加诸如数据页校验和之类的功能很有用: -e POSTGRES_INITDB_ARGS="--data-checksums"

POSTGRES_INITDB_WALDIR

这个可选的环境变量可用于为 Postgres 事务日志定义另一个位置。默认情况下,事务日志存储在 Postgres 主数据文件夹的子目录中( PGDATA )。有时,将事务日志存储在不同的目录中可能是理想的,该目录可能由具有不同性能或可靠性特征的存储支持。

注意:在 PostgreSQL 9.x 上,此变量是 POSTGRES_INITDB_XLOGDIR (反映了在 PostgreSQL 10 及以上版本中 --xlogdir 标志的名称更改为 --waldir )。

POSTGRES_HOST_AUTH_METHOD

这个可选变量可用于控制针对 host 连接的 auth-method ,用于 all 数据库、 all 用户和 all 地址。如果未指定,则使用 scram-sha-256 密码身份验证(在 14+ 中;在较早版本中为 md5 )。在未初始化的数据库上,这将通过以下大致行填充 pg_hba.conf

echo "host all all all $POSTGRES_HOST_AUTH_METHOD" >> pg_hba.conf

有关可能的值及其含义的更多信息,请参阅 pg_hba.conf 上的 PostgreSQL 文档。

注意 1:不建议使用 trust ,因为它允许任何人在没有密码的情况下连接,即使设置了密码(如通过 POSTGRES_PASSWORD )。更多信息请参阅 PostgreSQL 关于信任认证的文档。

注意 2:如果将 POSTGRES_HOST_AUTH_METHOD 设置为 trust ,那么 POSTGRES_PASSWORD 就不需要了。

注意 3:如果将此设置为替代值(例如 scram-sha-256 ),则可能需要额外的 POSTGRES_INITDB_ARGS 才能使数据库正确初始化(例如 POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 )。

PGDATA

重要说明:将卷挂载到 /var/lib/postgresql 时, /var/lib/postgresql/data 路径是容器运行时的本地卷,因此数据不会持久化到挂载的卷上。

这个可选变量可用于为数据库文件定义另一个位置 - 例如子目录。默认是 /var/lib/postgresql/data 。如果您正在使用的数据卷是文件系统挂载点(如 GCE 持久磁盘),或者是无法将所有者更改为 postgres 用户的远程文件夹(如某些 NFS 挂载),或者包含文件夹/文件(例如 lost+found ),则 Postgres initdb 需要在挂载点内创建一个子目录来包含数据。

例如:

$ docker run -d \
    --name some-postgres \
    -e POSTGRES_PASSWORD=mysecretpassword \
    -e PGDATA=/var/lib/postgresql/data/pgdata \
    -v /custom/mount:/var/lib/postgresql/data \
    postgres

这是一个并非特定于 Docker 的环境变量。由于该变量被 postgres 服务器二进制文件使用(参见 PostgreSQL 文档),入口点脚本会考虑到它。

Docker 机密

作为通过环境变量传递敏感信息的替代方法,可将 _FILE 附加到前面列出的一些环境变量上,这会导致初始化脚本从容器中存在的文件加载这些变量的值。特别是,这可用于从存储在 /run/secrets/<secret_name> 文件中的 Docker 机密加载密码。例如:

$ docker run --name some-postgres -e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd -d postgres

目前,这仅支持 POSTGRES_INITDB_ARGSPOSTGRES_PASSWORDPOSTGRES_USERPOSTGRES_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

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL

这些初始化文件将按照当前区域设置定义的按名称排序的顺序执行,默认为 en_US.utf8 。任何 *.sql 文件将由 POSTGRES_USER 执行,默认为 postgres 超级用户。建议在 *.sh 脚本内运行的任何 psql 命令通过使用 --username "$POSTGRES_USER" 标志作为 POSTGRES_USER 执行。由于容器内进行的 Unix 套接字连接存在 trust 身份验证,此用户将能够无需密码进行连接。

此外,截至 docker-library/postgres#253,这些初始化脚本以 postgres 用户(或使用 --user 标志指定的“半任意用户”到 docker run ;有关更多详细信息,请参阅标题为“任意 --user 注释”的部分)运行。另外,截至 docker-library/postgres#440,为这些初始化脚本启动的临时守护进程仅在 Unix 套接字上监听,因此任何 psql 使用都应删除主机名部分(例如,参见 docker-library/postgres#474(注释))。

数据库配置

有许多方法可以设置 PostgreSQL 服务器配置。有关可配置内容的信息,请参阅您正在运行的特定版本的 PostgreSQL 的 PostgreSQL 文档。以下是一些设置配置的选项:

  • 使用自定义配置文件。创建一个配置文件并将其放入容器中。如果您的配置文件需要一个起始点,您可以使用 PostgreSQL 提供的示例,该示例在容器中的 /usr/share/postgresql/postgresql.conf.sample (在 Alpine 变体中为 /usr/local/share/postgresql/postgresql.conf.sample )处可用。

    • 重要说明:您必须设置 listen_addresses = '*' ,以便其他容器能够访问 postgres。

      $ # get the default config $ docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf

      $ # customize the config

      $ # run postgres with custom config $ 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'

  • 直接在运行行上设置选项。入口点脚本是这样制作的,以便传递给 docker 命令的任何选项都将传递给 postgres 服务器守护进程。从 PostgreSQL 文档中我们看到,在 .conf 文件中可用的任何选项都可以通过 -c 来设置。

    $ docker run -d --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword postgres -c shared_buffers=256MB -c max_connections=200
    

区域设置自定义

你可以使用简单的 Dockerfile 来扩展基于 Debian 的镜像以设置不同的区域设置。以下示例将把默认区域设置为 de_DE.utf8

FROM postgres:14.3
RUN localedef -i de_DE -c -f UTF-8 -A /usr/share/locale/locale.alias de_DE.UTF-8
ENV LANG de_DE.utf8

由于数据库初始化仅在容器启动时发生,这使我们能够在创建之前设置语言。

同样值得注意的是,从 Postgres 15 开始基于 Alpine 的变体支持 ICU 区域设置。以前基于 alpine 的 Postgres 版本不支持区域设置;有关更多详细信息,请参阅 musl 文档中的“字符集和区域设置”。

您可以在基于 Alpine 的镜像中使用 POSTGRES_INITDB_ARGS 设置区域设置,以设置不同的区域。以下示例将把新初始化数据库的默认区域设置为 de_DE.utf8

$ 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

附加扩展

当使用默认(基于 Debian)的变体时,安装额外的扩展(例如 PostGIS)应该像安装相关软件包一样简单(有关具体示例,请参阅 github.com/postgis/docker-postgis)。

当使用 Alpine 变体时,任何未在 postgres-contrib 中列出的 postgres 扩展都需要在你自己的镜像中进行编译(再次,可查看 github.com/postgis/docker-postgis 以获取具体示例)。

任意 --user 笔记

截至 docker-library/postgres#253,此镜像支持通过 --userdocker run 上以(大部分)任意用户身份运行。截至 docker-library/postgres#1018,对于 Alpine 变体也是如此。

需要注意的主要警告是, postgres 不在乎它以什么 UID 运行(只要 /var/lib/postgresql/data 的所有者匹配),但 initdb 在乎(并且需要用户存在于 /etc/passwd 中):

$ docker run -it --rm --user www-data -e POSTGRES_PASSWORD=mysecretpassword postgres
The files belonging to this database system will be owned by user "www-data".
...

$ docker run -it --rm --user 1000:1000 -e POSTGRES_PASSWORD=mysecretpassword postgres
initdb: could not look up effective user ID 1000: user does not exist

绕过此问题的三种最简单方法:

  1. 允许图像使用 nss_wrapper 库为你“伪造” /etc/passwd 内容(更多细节见 docker-library/postgres#448)

  2. 绑定挂载 /etc/passwd 从主机以只读方式(如果您想要的 UID 是您主机上的有效用户):

    $ docker run -it --rm --user "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -e POSTGRES_PASSWORD=mysecretpassword postgres
    The files belonging to this database system will be owned by user "jsmith".
    ...
    
  3. 从最终运行时单独初始化目标目录(中间有一个 chown ):

    $ docker volume create pgdata
    $ docker run -it --rm -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword postgres
    The files belonging to this database system will be owned by user "postgres".
    ...
    ( once it's finished initializing successfully and is waiting for connections, stop it )
    $ docker run -it --rm -v pgdata:/var/lib/postgresql/data bash chown -R 1000:1000 /var/lib/postgresql/data
    $ docker run -it --rm --user 1000:1000 -v pgdata:/var/lib/postgresql/data postgres
    LOG:  database system was shut down at 2017-01-20 00:03:23 UTC
    LOG:  MultiXact member wraparound protections are now enabled
    LOG:  autovacuum launcher started
    LOG:  database system is ready to accept connections
    

注意事项

如果在容器中 postgres 启动时没有数据库,那么 postgres 将为您创建默认数据库。虽然这是 postgres 的预期行为,但这意味着在此期间它将不接受传入连接。当使用诸如 docker-compose 之类的自动化工具同时启动多个容器时,这可能会导致问题。

还请注意,容器的默认 /dev/shm 大小为 64MB。如果共享内存耗尽,您将遇到 ERROR: could not resize shared memory segment . . . : No space left on device 。例如,您将希望传递 --shm-size=256MBdocker run ,或者在 docker-compose 中另一种选择。

数据存储在哪里

重要说明:有几种方法可以存储在 Docker 容器中运行的应用程序所使用的数据。我们鼓励 postgres 镜像的用户熟悉可用的选项,包括:

  • 让 Docker 通过使用其自身内部的卷管理将数据库文件写入主机系统的磁盘来管理数据库数据的存储。这是默认设置,对用户来说简单且相当透明。缺点是对于直接在主机系统上运行(即在容器外部)的工具和应用程序而言,这些文件可能很难定位。
  • 在主机系统(容器外部)上创建一个数据目录,并将其挂载到容器内部可见的目录。这会将数据库文件放置在主机系统上的已知位置,并且使主机系统上的工具和应用程序易于访问这些文件。缺点是用户需要确保该目录存在,并且例如主机系统上的目录权限和其他安全机制已正确设置。

Docker 文档是了解不同存储选项和变体的良好起点,并且有多个博客和论坛帖子在该领域进行讨论并提供建议。我们将在此处仅展示上述后一种选项的基本过程:

  1. 在主机系统的合适卷上创建一个数据目录,例如 /my/own/datadir

  2. 像这样启动你的 postgres 容器:

    $ docker run --name some-postgres -v /my/own/datadir:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword -d postgres:tag
    

命令的 -v /my/own/datadir:/var/lib/postgresql/data 部分将底层主机系统中的 /my/own/datadir 目录挂载为容器内的 /var/lib/postgresql/data ,在那里 PostgreSQL 默认会写入其数据文件。

图像变体

postgres 图像有多种类型,每种都针对特定的用例而设计。

postgres:<version>

这是事实上的镜像。如果你不确定自己的需求是什么,你可能想要使用这个。它被设计既可用作一次性容器(挂载你的源代码并启动容器以启动你的应用程序),也可用作构建其他镜像的基础。

其中一些标签可能包含诸如“书虫”或“靶心”之类的名称。这些是 Debian 发行版的套件代号,表明该镜像基于哪个发行版。如果你的镜像需要安装除镜像自带的软件包之外的任何其他软件包,你可能希望明确指定其中之一,以便在 Debian 有新版本发布时最大程度地减少损坏。

postgres:<version>-alpine

此镜像基于流行的 Alpine Linux 项目,在 alpine 官方镜像中可用。Alpine Linux 比大多数发行版基础镜像小得多(约 5MB),因此通常会生成更精简的镜像。

当尽可能小的最终镜像大小是你主要关心的问题时,这个变体很有用。需要注意的主要警告是,它确实使用 musl libc 而不是 glibc 及其同类,所以软件通常会根据其对 libc 要求/假设的深度而遇到问题。有关可能出现的问题以及使用基于 Alpine 的镜像的一些优缺点比较的更多讨论,请参阅此 Hacker News 评论线程。

为了最小化镜像大小,在基于 Alpine 的镜像中包含额外的相关工具(例如 gitbash )是不常见的。使用此镜像作为基础,在你自己的 Dockerfile 中添加你需要的东西(如果你不熟悉,可查看 alpine 镜像描述以获取如何安装软件包的示例)。

许可证

查看此映像中包含的软件的许可证信息。

与所有 Docker 镜像一样,这些镜像可能还包含其他可能受其他许可证约束的软件(例如来自基础发行版的 Bash 等,以及所包含的主要软件的任何直接或间接依赖项)。

一些能够自动检测到的额外许可证信息可能会在 repo-info 存储库的 postgres/ 目录中找到。

对于任何预构建镜像的使用,镜像用户有责任确保对此镜像的任何使用都符合其中包含的所有软件的任何相关许可证。