DockerHub 仓库中的原生 PostgreSQL 镜像操作说明(一)原文翻译

文章介绍了如何使用Docker运行PostgreSQL实例,包括启动命令、环境变量设置如POSTGRES_PASSWORD,以及如何通过环境变量扩展镜像功能。还讨论了数据存储位置、初始化脚本和数据库配置的方法,并提到了Docker私密信息的使用。文章强调了数据持久化和容器安全性的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原生的 PostgreSQL 镜像的制作还是比较合理的,推荐大家深入研究这个镜像的使用操作,能熟悉构建脚本最好不过。
原文链接:https://hub.docker.com/_/postgres

如何使用这个镜像

启动一个 postgres 实例

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

入口点(entrypoint)会使用 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 stack deploydocker-compose

例子用于 postgresstack.yml

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

services:

  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: example

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-30Sx9bu8-1677600497745)(null)]

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

如何扩展这个镜像

有许多方法可以扩展postgres镜像。在不尝试支持每种可能的用例的情况下,以下是我们发现有用的一些方法。

环境变量

PostgreSQL 镜像使用了几个环境变量,这些变量很容易被忽略。唯一必需的变量是POSTGRES_PASSWORD,其余变量是可选的。
警告:仅当你使用一个空的数据目录启动容器时,这些 Docker 特定的变量才会生效;任何现有的数据库都将在容器启动时保持不变。

POSTGRES_PASSWORD

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

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

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

POSTGRES_USER

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

注意,如果指定了该参数,PostgreSQL 仍然会显示属于该数据库系统的文件将在初始化过程中由用户“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

此可选变量可用于控制所有数据库所有用户所有地址的主机连接的认证方法(auth-method)。如果未指定,则使用scram-sha-256密码身份验证(这是在 14+ 版本中;而早期版本中则使用MD5)。在未初始化的数据库上,这将通过以下近似行填充 pg_hba.conf:

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

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

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

注意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/data。如果你使用的数据卷是文件系统挂载点(例如 GCE 持久磁盘)或无法修改所有权(chowned)为postgres用户的远程文件夹(例如某些 NFS 挂载),则 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 文档),因此入口点(entrypoint)脚本会对它加以重视。

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_USER、和POSTGRES_DB

初始化脚本

如果你想要在派生自此镜像的镜像中进行额外的初始化,请在 /docker-entrypoint-initdb.d 目录下添加一个或多个 *.sql*.sql.gz*.sh 脚本(如果必要,创建该目录)。在 entrypoint 调用 initdb 创建默认的 postgres 用户和数据库之后,它将运行任何 *.sql 文件、运行任何可执行的 *.sh 脚本,并在该目录中 source 任何非可执行的 *.sh 脚本以在启动服务之前进行进一步的初始化。

警告:仅在使用空数据目录启动容器时,/docker-entrypoint-initdb.d 中的脚本才会被运行;任何现存的数据库都将在容器启动时保持不变。一个常见的问题是,如果你的 /docker-entrypoint-initdb.d 中的脚本失败(这将导致 entrypoint 脚本退出),并且你的编排器使用已初始化的数据目录重新启动容器,它将不会继续运行您的脚本。

例如,要添加一个额外的用户和数据库,请将以下内容添加到 /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 的使用都应该删除主机名(hostname)部分(请参见 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。
    $ # 获取默认配置
    $ docker run -i --rm postgres cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf
    
    $ # 自定义这个配置(即:my-postgres.conf)
    
    $ # 使用自定义配置运行 postgres
    $ 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 文档中的“字符集和语言环境”

你可以使用POSTGRES_INITDB_ARGS在基于 alpine 的镜像中设置语言环境,来设置一个不同的语言环境。下面的例子将一个新初始化的数据库的默认区域设置为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开始,该镜像支持通过 docker run 上的 --user 以(大多数)任意用户身份运行。从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
这个数据库系统的文件将属于用户“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
    这个数据库系统的文件将属于用户“jsmith”。
    ...
    
  3. 与最终运行分开,单独先初始化目标目录(在两者中间插入一个chown操作):

    $ docker volume create pgdata
    $ docker run -it --rm -v pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword postgres
    属于该数据库系统的文件将由用户“postgres”拥有。
    ...
    (如果 PostgreSQL 成功初始化并等待连接,那么可以停止它)
    $ 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的错误。你需要向docker run传递--shm-size=256MB之类的参数,或者在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 将在这里写入它的数据文件。

1. 下载CentOS镜像 首先,我们需要下载CentOS的镜像文件。可以从官方网站下载,也可以从镜像站点下载。这里我们选择从镜像站点下载CentOS 7的镜像文件。 2. 安装Docker 安装Docker的步骤可以参考官方文档。这里不再赘述。 3. 创建Dockerfile文件 在本地机器上创建个目录,用来存放Dockerfile和其他需要的文件。 ```bash mkdir postgresql cd postgresql ``` 然后,创建Dockerfile文件。 ```bash touch Dockerfile ``` 编辑Dockerfile文件,输入以下内容。 ```dockerfile # 基础镜像,使用centos 7 FROM centos:7 # 作者信息 MAINTAINER Your Name <[email protected]> # 安装postgresql RUN yum install -y postgresql-server postgresql-contrib # 初始化数据库 RUN postgresql-setup initdb # 启动postgresql服务 RUN systemctl start postgresql # 设置postgresql服务开机自启动 RUN systemctl enable postgresql # 开放postgresql服务端口 EXPOSE 5432 # 启动命令 CMD ["/usr/bin/postgres", "-D", "/var/lib/pgsql/data", "-c", "config_file=/var/lib/pgsql/data/postgresql.conf"] ``` Dockerfile的解释如下: - 第行指定基础镜像为centos 7。 - 第二行指定作者信息。 - 第三行安装postgresql。 - 第四行初始化数据库。 - 第五行启动postgresql服务。 - 第六行设置postgresql服务开机自启动。 - 第七行开放postgresql服务端口。 - 第八行指定启动命令。 4. 构建镜像postgresql目录下执行以下命令,构建postgresql镜像。 ```bash docker build -t postgresql:latest . ``` 其中,postgresql:latest是镜像的名称和标签。 5. 保存镜像 在本地机器上保存postgresql镜像。 ```bash docker save -o postgresql.tar postgresql:latest ``` 6. 导入镜像postgresql.tar文件拷贝到离线机器上,执行以下命令,导入postgresql镜像。 ```bash docker load -i postgresql.tar ``` 7. 运行容器 在离线机器上运行postgresql容器。 ```bash docker run -d --name postgresql -p 5432:5432 postgresql:latest ``` 其中,-d表示后台运行容器,--name指定容器名称,-p指定端口映射。 至此,我们就成功地在离线机器上制作了postgresql镜像,并且成功地运行了postgresql容器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值