如何自定义官方PostgreSQL Docker镜像的configuration文件?

我正在使用正式的Postgres Docker镜像尝试自定义其configuration。 为此,我使用命令sed来更改max_connections ,例如:

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

我尝试了两种方法来应用此configuration。 首先是将命令添加到脚本中,并将其复制到init文件夹“/docker-entrypoint-initdb.d”中。 第二种方法是通过使用“RUN”命令直接在Dockerfile中运行它们(这种方法在configuration文件“/ etc / postgres / …”的非官方Postgresql映像中工作正常)。 在这两种情况下,更改失败,因为configuration文件丢失(我认为它还没有创build)。

我应该如何改变configuration?

编辑1:

以下是用于创build映像的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的构build过程显示错误: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

你从后继的postgres:9.4镜像在/var/lib/postgresql/data声明了一个卷。 这基本上意味着你不能将任何文件复制到图像中的path; 这些更改将被丢弃。

你有几个select:

  • 你可以在运行时用docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf ...把你自己的configuration文件作为一个卷来添加。 但是,我不确定如何与现有卷交互。

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

  • 克隆Postgres官方镜像背后的项目,编辑Dockerfile,在声明VOLUME之前添加自己的configuration文件(在运行时自动复制VOLUME指令之前添加的任何内容)。

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

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

要一致地定制Docker中的PostgreSQLconfiguration,我build议使用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 

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

 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 

debugging

  1. docker run命令中除去-d (detach选项)以直接查看服务器日志。
  2. 用psql客户端连接到postgres服务器并查询configuration:

     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撰写

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

例如,这使得Postgreslogin到一个文件:

 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将使用的configuration文件。 你可以用一个卷来挂载你的自定义configuration文件:

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

这里是我的应用程序docker-compose.yml ,展示了如何configurationPostgres:

 # 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 # (eg, MobyLinuxVM) in /var/lib/docker/volumes/ volumes: postgresVolume: 

写入日志目录的权限

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

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

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

我使用主机设置正确的权限

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

当你运行官方入口点(启动容器时的AKA)时,它会在$PGDATA/var/lib/postgresql/data默认)下运行initdb ,然后在这个目录中存储这两个文件:

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

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

所有这一切意味着您可以在该文件夹中提供一个shell / SQL脚本,用于configuration服务器以进行下一次引导(在数据库初始化之后立即启动,或者下次引导容器时)。

例:

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 。 由于configuration存储在卷中,所以它将在重build之后存活。


另一种select是按照您的意愿多次传递-c标志:

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

这样你就不需要build立一个新的映像,而且你不需要关心已经存在的或者不需要关心的数据库。 一切都会受到影响。

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

要做到这一点 :

  • 在您的容器中复制您的自定义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/的脚本,并使用自定义configuration覆盖默认configuration。

这个问题的一个相当低技术的解决scheme似乎是声明服务(我正在AWS上使用swarm和yaml文件),并将您的数据库文件挂载到一个持久化卷(这里是AWS EFS,如cloudstor:aws driver规范)。

  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. 您可以编辑容器内的configuration设置,例如,如果要增加需要重新启动的最大并发连接数
  3. 停止正在运行的容器(或者将服务缩减到零,然后返回到一个)
  4. 群体会产生一个新的容器,这个容器会拿起持久的configuration设置,并快速地应用它们。

坚持你的configuration一个愉快的副作用是它也坚持你的数据库(或者是相反的);-)