如何自定义正式 PostgreSQLDocker 映像的配置文件?

我正在使用 Postgres Docker 的官方图片尝试定制它的配置。为此,我使用命令 sed来更改 max_connections,例如:

sed -i -e"s/^max_connections = 100.*$/max_connections = 1000/" /var/lib/postgresql/data/postgresql.conf

我尝试了两种方法来应用此配置。第一种方法是将命令添加到脚本中,并将其复制到 init 文件夹“/docker-entrypoint-initdb。D.第二种方法是使用“ RUN”命令直接在 Dockerfile 中运行它们(这种方法可以很好地用于非官方的 Postgreql 映像,该映像具有到配置文件“/etc/postgres/...”的不同路径)。在这两种情况下,更改都会失败,因为缺少配置文件(我认为它还没有创建)。

我应该如何改变配置?

编辑1:

下面是用于创建图像的 Dockerfile:

# Database (http://www.cs3c.ma/)


FROM postgres:9.4
MAINTAINER Sabbane <contact@cs3c.ma>


ENV TERM=xterm


RUN apt-get update
RUN apt-get install -y nano


ADD scripts /scripts
# ADD scripts/setup-my-schema.sh /docker-entrypoint-initdb.d/


# Allow connections from anywhere.
RUN sed -i -e"s/^#listen_addresses =.*$/listen_addresses = '*'/" /var/lib/postgresql/data/postgresql.conf
RUN echo "host    all    all    0.0.0.0/0    md5" >> /var/lib/postgresql/data/pg_hba.conf


# Configure logs
RUN sed -i -e"s/^#logging_collector = off.*$/logging_collector = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_directory = 'pg_log'.*$/log_directory = '\/var\/log\/postgresql'/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_filename = 'postgresql-\%Y-\%m-\%d_\%H\%M\%S.log'.*$/log_filename = 'postgresql_\%a.log'/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_file_mode = 0600.*$/log_file_mode = 0644/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_truncate_on_rotation = off.*$/log_truncate_on_rotation = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_rotation_age = 1d.*$/log_rotation_age = 1d/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_min_duration_statement = -1.*$/log_min_duration_statement = 0/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_checkpoints = off.*$/log_checkpoints = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_connections = off.*$/log_connections = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_disconnections = off.*$/log_disconnections = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^log_line_prefix = '\%t \[\%p-\%l\] \%q\%u@\%d '.*$/log_line_prefix = '\%t \[\%p\]: \[\%l-1\] user=\%u,db=\%d'/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_lock_waits = off.*$/log_lock_waits = on/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#log_temp_files = -1.*$/log_temp_files = 0/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#statement_timeout = 0.*$/statement_timeout = 1800000        # in milliseconds, 0 is disabled (current 30min)/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^lc_messages = 'en_US.UTF-8'.*$/lc_messages = 'C'/" /var/lib/postgresql/data/postgresql.conf


# Performance Tuning
RUN sed -i -e"s/^max_connections = 100.*$/max_connections = 1000/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^shared_buffers =.*$/shared_buffers = 16GB/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#effective_cache_size = 128MB.*$/effective_cache_size = 48GB/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#work_mem = 1MB.*$/work_mem = 16MB/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#maintenance_work_mem = 16MB.*$/maintenance_work_mem = 2GB/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#checkpoint_segments = .*$/checkpoint_segments = 32/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#checkpoint_completion_target = 0.5.*$/checkpoint_completion_target = 0.7/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#wal_buffers =.*$/wal_buffers = 16MB/" /var/lib/postgresql/data/postgresql.conf
RUN sed -i -e"s/^#default_statistics_target = 100.*$/default_statistics_target = 100/" /var/lib/postgresql/data/postgresql.conf




VOLUME ["/var/lib/postgresql/data", "/var/log/postgresql"]


CMD ["postgres"]

使用这个 Dockerfile,构建过程将显示错误: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

176110 次浏览

从中继承的 postgres:9.4映像在 /var/lib/postgresql/data声明一个卷。这实际上意味着您不能将任何文件复制到映像中的路径; 更改将被丢弃。

你有几个选择:

  • 您可以在运行时使用 docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf ...作为卷添加自己的配置文件。然而,我不确定这将如何与现有的卷交互。

  • 您可以在容器启动时复制文件。要做到这一点,复制你的文件到一个位置,不在卷下面的构建,然后从 entrypointcmd调用脚本,这将复制文件到正确的位置,并启动 Postgres。

  • 在声明 VOLUME 之前,克隆 Postgres 官方图像后面的项目并编辑 Dockerfile 以添加您自己的配置文件(在 VOLUME 指令之前添加的任何内容都会在运行时自动复制进来)。

  • 在 docker-compose 文件中传递命令选项中的所有配置更改

像这样:

services:
postgres:
...
command:
- "postgres"
- "-c"
- "max_connections=1000"
- "-c"
- "shared_buffers=3GB"
- "-c"
...

在 Postgres Docker 容器中注入自定义 postgreql.conf

默认的 postgresql.conf文件位于 PGDATA目录(/var/lib/postgresql/data)中,这使得事情变得更加复杂,特别是在第一次运行 Postgres 容器时,因为 docker-entrypoint.sh包装器调用 initdb步骤进行 PGDATA目录初始化。

为了在 Docker 中始终如一地定制 PostgreSQL 配置,我建议使用 config_file Postgres 选项和 Docker 卷一起使用,如下所示:

生产数据库(PGDATA 目录为持久卷)

docker run -d \
-v $CUSTOM_CONFIG:/etc/postgresql.conf \
-v $CUSTOM_DATADIR:/var/lib/postgresql/data \
-e POSTGRES_USER=postgres \
-p 5432:5432 \
--name postgres \
postgres:9.6 postgres -c config_file=/etc/postgresql.conf

测试数据库(PGDATA 目录将在 docker rm之后丢弃)

docker run -d \
-v $CUSTOM_CONFIG:/etc/postgresql.conf \
-e POSTGRES_USER=postgres \
--name postgres \
postgres:9.6 postgres -c config_file=/etc/postgresql.conf

正在调试

  1. docker run命令中删除 -d(分离选项)可以直接查看服务器日志。

  2. psql客户机连接到 Postgres 服务器并查询配置:

    docker run -it --rm --link postgres:postgres postgres:9.6 sh -c 'exec psql -h $POSTGRES_PORT_5432_TCP_ADDR -p $POSTGRES_PORT_5432_TCP_PORT -U postgres'
    
    
    psql (9.6.0)
    Type "help" for help.
    
    
    postgres=# SHOW all;
    

和 Docker Compose 一起

在使用 Docker Compose时,可以在 docker-compose.yml中使用 command: postgres -c option=value来配置 Postgres。

例如,这会使 Postgres 记录到一个文件:

command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs

适应 Vojtech Vitek 的回答,您可以使用

command: postgres -c config_file=/etc/postgresql.conf

更改 Postgres 将使用的配置文件:

volumes:
- ./customPostgresql.conf:/etc/postgresql.conf

下面是我的应用程序的 docker-compose.yml,展示了如何配置 Postgres:

# Start the app using docker-compose pull && docker-compose up to make sure you have the latest image
version: '2.1'
services:
myApp:
image: registry.gitlab.com/bullbytes/myApp:latest
networks:
- myApp-network
db:
image: postgres:9.6.1
# Make Postgres log to a file.
# More on logging with Postgres: https://www.postgresql.org/docs/current/static/runtime-config-logging.html
command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs
environment:
# Provide the password via an environment variable. If the variable is unset or empty, use a default password
# Explanation of this shell feature: https://unix.stackexchange.com/questions/122845/using-a-b-for-variable-assignment-in-scripts/122848#122848
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-4WXUms893U6j4GE&Hvk3S*hqcqebFgo!vZi}
# If on a non-Linux OS, make sure you share the drive used here. Go to Docker's settings -> Shared Drives
volumes:
# Persist the data between container invocations
- postgresVolume:/var/lib/postgresql/data
- ./logs:/logs
networks:
myApp-network:
# Our application can communicate with the database using this hostname
aliases:
- postgresForMyApp
networks:
myApp-network:
driver: bridge
# Creates a named volume to persist our data. When on a non-Linux OS, the volume's data will be in the Docker VM
# (e.g., MobyLinuxVM) in /var/lib/docker/volumes/
volumes:
postgresVolume:

写入日志目录的权限

注意,在 Linux 上,主机上的日志目录必须具有正确的权限。 否则你会得到一个稍微有点误导性的错误

无法打开日志文件 “/log/postgreql-2017-02-04 _ 115222. log”: 权限被拒绝

我说的是误导,因为错误消息表明目录 在集装箱里具有错误的权限,而实际上目录 在主机上不允许写入。

为了解决这个问题,我使用

chgroup ./logs docker && chmod 770 ./logs

当您运行正式的入口点(即启动容器)时,它在 $PGDATA中运行 initdb(默认情况下是 /var/lib/postgresql/data) ,然后在该目录中存储两个文件:

  • 具有默认手动设置的 postgresql.conf
  • 使用 ALTER SYSTEM命令自动重写设置的 postgresql.auto.conf

入口点还执行任何 /docker-entrypoint-initdb.d/*.{sh,sql}文件。

所有这些意味着您可以在该文件夹中提供一个 shell/SQL 脚本,为下一次引导配置服务器(将在 DB 初始化后立即启动,或者下一次引导容器时启动)。

例如:

conf.sql文件:

ALTER SYSTEM SET max_connections = 6;
ALTER SYSTEM RESET shared_buffers;

Dockerfile文件:

FROM posgres:9.6-alpine
COPY *.sql /docker-entrypoint-initdb.d/
RUN chmod a+r /docker-entrypoint-initdb.d/*

然后,您必须在已经存在的数据库中手动执行 conf.sql。因为配置存储在卷中,所以它可以在重新构建后继续存在。


另一种选择是按照您的意愿多次传递 -c选项:

docker container run -d postgres -c max_connections=6 -c log_lock_waits=on

通过这种方式,您不需要构建新映像,也不需要关心已经存在的或不存在的数据库; 所有这些都将受到影响。

您可以将自定义 postgresql.conf放在容器内的临时文件中,并在运行时覆盖默认配置。

要做到这一点:

  • 在容器中复制自定义 postgresql.conf
  • 复制 /docker-entrypoint-initdb.d/中的 updateConfig.sh文件

Dockerfile

FROM postgres:9.6


COPY postgresql.conf      /tmp/postgresql.conf
COPY updateConfig.sh      /docker-entrypoint-initdb.d/_updateConfig.sh

updateConfig.sh

#!/usr/bin/env bash


cat /tmp/postgresql.conf > /var/lib/postgresql/data/postgresql.conf

在运行时,容器将在 /docker-entrypoint-initdb.d/中执行脚本,并用自定义配置覆盖默认配置。

对于这个问题,一个相当低技术含量的解决方案似乎是声明服务(我在 AWS 上使用 group 和 yaml 文件) ,并将数据库文件装入持久卷(这里是 AWS EFS,正如 Cloudstor: AWS 驱动程序规范所表示的那样)。

  version: '3.3'
services:
database:
image: postgres:latest
volumes:
- postgresql:/var/lib/postgresql
- postgresql_data:/var/lib/postgresql/data
volumes:
postgresql:
driver: "cloudstor:aws"
postgresql_data:
driver: "cloudstor:aws"
  1. 数据库以图像默认设置初始化的形式出现。
  2. 您可以在容器中编辑 conf 设置,例如,如果您想要增加需要重新启动的最大并发连接数量
  3. 停止正在运行的容器(或者将服务缩放到零,然后返回到一)
  4. 蜂群产生一个新的容器,这次它将获取您的持久化配置设置并愉快地应用它们。

持久化配置的一个令人愉快的副作用是,它还可以持久化数据库(或者反过来) ; -)

我查看了所有的答案,还有另一个选项: 您可以在 Dockerfile 中更改您的 CMD值(它不是最好的,但仍然是实现您的目标的一种可能的方法)。

基本上我们需要:

  • 将配置文件复制到 Docker 容器中
  • 重写 Postgres 启动选项

Dockerfile 示例:

FROM postgres:9.6
USER postgres


# Copy Postgres config file into container
COPY postgresql.conf /etc/postgresql


# Override default Postgres config file
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]

尽管我认为在 docker-compose.yml文件中使用 command: postgres -c config_file=/etc/postgresql/postgresql.confMatthias Braun提出的最佳选择。

我的解决方案是为那些需要在启动 docker-entrypoint-initdb. d 之前更改配置的同事提供的

我需要更改“ share _ preload _ library”设置,以便在其工作期间 postgres 已经预先加载了新的库,并在 docker-entrypoint-initdb 中编写了代码。我可以用它。

因此,我刚刚在 Dockerfile 修补了 postgreql.con.sample 文件:

RUN echo "shared_preload_libraries='citus,pg_cron'" >> /usr/share/postgresql/postgresql.conf.sample
RUN echo "cron.database_name='newbie'" >> /usr/share/postgresql/postgresql.conf.sample

通过这个补丁,可以在 docker-entrypoint-initdb. d/中添加. sql 文件的扩展名:

CREATE EXTENSION pg_cron;

使用 docker 组合可以用 postgresql.auto.conf挂载卷。 例如:

version: '2'


services:
db:
image: postgres:10.9-alpine
volumes:
- postgres:/var/lib/postgresql/data:z
- ./docker/postgres/postgresql.auto.conf:/var/lib/postgresql/data/postgresql.auto.conf
ports:
- 5432:5432

我还使用了官方图片(FROM postgres) 我可以通过执行以下命令来更改配置。

第一件事是找到 PostgreSQL 配置文件。 这可以通过在正在运行的数据库中执行此命令来完成。

SHOW config_file;

我的情况下它返回 /data/postgres/postgresql.conf

下一步是找出正在运行的 PostgreSQL docker 容器的散列值。

docker ps -a

这将返回所有正在运行的容器的列表。

...
0ba35e5427d9    postgres    "docker-entrypoint.s…" ....
...

现在您必须通过执行以下命令切换到容器内的 bash:

docker exec -it 0ba35e5427d9 /bin/bash

在容器内检查配置是否位于正确的路径并显示它。

cat /data/postgres/postgresql.conf

我希望将最大连接从100改为1000,并将共享缓冲区从128MB 改为3GB。 使用 sed 命令,我可以进行搜索并用配置中的相应变量替换。

sed -i -e"s/^max_connections = 100.*$/max_connections = 1000/" /data/postgres/postgresql.conf
sed -i -e"s/^shared_buffers = 128MB.*$/shared_buffers = 3GB/" /data/postgres/postgresql.conf

我们必须做的最后一件事是在容器中重新启动数据库。 找出你正在使用的 PostGres 的版本。

cd /usr/lib/postgresql/
ls

对我来说是 12 因此,现在可以通过执行以下命令来重新启动数据库,并使用正确的版本。

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"