如何自定义官方PostgreSQL Docker映像的配置文件?


101

我正在使用官方的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中运行它们(此方法在非官方的Postgresql映像(配置文件的路径不同于“ / 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


1
一种方法是使用正式映像,启动它,在内部进行连接,docker exec -it container_id bash然后进行修改,然后docker commit container_id myuser/myimage_myPostegresql:myversion查看文档docs.docker.com/reference/commandline/cli/#commit
user2915097 2015年

2
我认为docker范式的优点之一是使整个构建过程自动化。如另一幅图片所述,paintedfox/postgresql可以直接在Dockerfile中更改配置。我认为官方形象也应该可行。
Sakr 2015年

sed方法应该起作用,您可以发布Dcokerfile还是完整的复制器?
user2915097 2015年

Answers:


54

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

您有几种选择:

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

  • 您可以在启动容器时复制文件。为此,请将文件复制到构建中不在卷下方的位置,然后从入口点或cmd调用脚本,该脚本会将文件复制到正确的位置并启动postgres。

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

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

喜欢:

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

3
就是这样,更改不应在Dockerfile内。我已经将它们移到脚本中,并从入口点开始调用它,现在可以正常工作了。谢谢你的回答。
Sakr 2015年

5
我刚刚将脚本复制到了init文件夹“ /docker-entrypoint-initdb.d/”中,这次也可以正常工作。这很奇怪,但是似乎我非常专注于使用Dockerfile设置映像,就像我过去处理大多数映像一样,以至于我第一次尝试使用init脚本时错过了一些东西。
Sakr 2015年

“这实质上意味着您无法将任何文件复制到映像中的该路径;更改将被丢弃。” 你能解释为什么会这样吗?
isco

@isco在官方文档中查找卷。卷基本上不存储在映像中,而是存储在主机中,因此数据将保存在主机中,而不是映像中。您需要以附加的相同容量启动容器以保留数据。
Adrian Mouat

我在/var/lib/postgres/data/pg_hba.conf中更改为仅接受连接是托管所有192.168.0.0/0 md5,并注释托管所有所有md5(默认设置)。但不要改变效果
Lucas Resende

83

使用Docker Compose

在使用Docker Compose时,您可以command: postgres -c option=value在其中使用它docker-compose.yml来配置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
       - 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上,主机上的日志目录必须具有正确的权限。否则,您会得到稍微误导的错误

严重:无法打开日志文件“ /logs/postgresql-2017-02-04_115222.log”:权限被拒绝

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

为了解决这个问题,我使用以下命令在主机上设置了正确的权限

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

您是否建议将postgres日志记录到文件而不是stdout并使用docker logs命令处理该文件?在github问题中交联的荣誉!
jpic

1
我不确定是否要记录文件还是使用Docker日志,jpic。
马提亚斯·布劳恩

您添加了密码,您可能会希望在此处屏蔽它
vidstige

3
@vidstige:我不使用此随机字符串作为密码,仅用于演示。
马提亚斯·布劳恩

1
@Gherman:您是否将此添加到了Dockerfile中?因为你不应该。我的答案使用docker-compose.yml
马提亚斯·布劳恩

39

将自定义postgresql.conf注入postgres Docker容器

默认postgresql.conf文件位于PGDATAdir(/var/lib/postgresql/data)中,这使事情变得更加复杂,尤其是在首次运行postgres容器时,因为docker-entrypoint.sh包装程序将调用dir初始化initdb步骤PGDATA

为了一致地自定义Docker中的PostgreSQL配置,我建议将config_filepostgres选项与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. -ddocker run命令中删除(分离选项)以直接查看服务器日志。
  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;

30

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

  • postgresql.conf 使用默认的手动设置。
  • postgresql.auto.conf使用ALTER SYSTEM命令自动覆盖的设置。

入口点还执行任何/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

这样,您无需构建新映像,也无需关心数据库是否已经存在;所有都会受到影响。


2
最后一个,通过-c是我的最爱。这很干净,并且可以针对不同的环境轻松生成。
epic_fil

10

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

要做到这一点 :

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

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/并使用您的自定义脚本覆盖默认配置。


为什么在第二个复制命令中使用“ _”?不应该说,它是:/docker-entrypoint-initdb.d/updateConfig.sh
Fernando Castilla Ospina

3
这是因为docker-entrypoint-initdb.d /文件夹按字母顺序执行脚本。我想在其他脚本之前应用此脚本。
alphayax

tnx我忘记了副本将文件重命名为使用下划线
Fernando Castilla Ospina

9

我查看了所有答案,然后剩下另一个选择。您可以在docker文件中更改CMD值(这不是最好的方法,但是仍然可以实现目标)。

基本上我们需要

  • 在Docker容器中复制配置文件
  • 覆盖postgres启动选项

Docker文件示例:

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"]

尽管我认为command: postgres -c config_file=/etc/postgresql/postgresql.confMatthias Braundocker-compose.yml建议的文件中使用是最佳选择。


2

解决此问题的技术含量较低的解决方案似乎是在将数据库文件安装到持久卷(此处为cloudstor:aws驱动程序表示的AWS EFS)的情况下声明服务(我在AWS上使用swarm和yaml文件)规范)。

  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. 群产生了一个新的容器,这一次它拾取了您持久的配置设置并愉快地应用了它们。

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


2

我的解决方案适用于需要在启动docker-entrypoint-initdb.d之前更改配置的同事

我需要更改'shared_preload_libraries'设置,因此在工作期间postgres已经预先加载了新库,并且docker-entrypoint-initdb.d中的代码可以使用它。

所以我只是在Dockerfile中修补了postgresql.conf.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;

1

这对我有用:

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"]

为什么没有收到任何支持?这是最明智的主张...谢谢。
Paflow

0

使用docker compose可以使用安装卷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

您不应编辑,postgresql.auto.conf因为它已被覆盖。使用postgresql.conf在相同的位置。
巴什德尔

0

我也使用了官方映像(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命令,我可以进行搜索并用config中的相应变量替换。

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"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.