【问题标题】:How to customize the configuration file of the official PostgreSQL Docker image?如何自定义官方PostgreSQL Docker镜像的配置文件?
【发布时间】:2015-08-31 03:43:45
【问题描述】:

我正在使用official Postgres Docker image 尝试自定义其配置。为此,我使用命令sed 更改max_connections 例如:

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

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

我应该如何更改配置?

编辑 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

【问题讨论】:

  • 一种方法是使用官方镜像,启动它,用docker exec -it container_id bash连接内部然后进行修改,然后docker commit container_id myuser/myimage_myPostegresql:myversion查看文档docs.docker.com/reference/commandline/cli/#commit
  • 我认为 docker 范式的优点之一是自动化整个构建过程。正如另一个镜像paintedfox/postgresql 所提到的,可以直接在 Dockerfile 中更改配置。我认为官方图片应该也可以。
  • sed 方法应该可以工作,你能发布你的 Dcokerfile 或完整的复制器吗?

标签: postgresql docker


【解决方案1】:

使用 Docker 撰写

使用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's answer,可以使用

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 上时,主机上的日志目录必须具有正确的权限。 否则你会得到稍微误导的错误

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

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

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

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

【讨论】:

  • 您是否建议将 postgres 日志记录到文件,而不是 stdout 并使用 docker logs 命令来处理它?感谢github issue 中的交联!
  • 我还没有决定是记录到文件还是使用 Docker 日志更可取,jpic。
  • @vidstige:我不使用这个随机字符串作为密码,只是为了演示。
  • @Gherman:您是否将其添加到您的 Dockerfile 中?因为你不应该。我的回答使用docker-compose.yml
  • @BennyChan:我自己没试过,但here 是一些重新加载 Postgres 配置的方法,例如 pg_ctl reload
【解决方案2】:

您继承的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"
      ...

【讨论】:

  • 就是这样,更改不应该在 Dockerfile 中。我已将它们移至脚本并从入口点调用它,现在它工作正常。谢谢你的回答。
  • 我刚刚在初始化文件夹“/docker-entrypoint-initdb.d/”中复制了脚本,这次它也运行良好。这很奇怪,但我似乎非常专注于使用 Dockerfile 设置图像,就像我习惯于处理大多数图像一样,我在第一次尝试使用 init 脚本时错过了一些东西。
  • “这实际上意味着您不能将任何文件复制到映像中的该路径;更改将被丢弃。”你能解释一下为什么会这样吗?
  • @isco 在官方文档中查找卷。基本上卷不是存储在映像中而是存储在主机上,因此数据将保存在主机上,而不是映像中。您需要启动具有相同卷的容器以保留数据。
  • 我在 /var/lib/postgres/data/pg_hba.conf 中更改为仅接受连接是 host all all 192.168.0.0/0 md5 并评论 host all all all md5(默认)。但不要改变效果
【解决方案3】:

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

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

要在 Docker 中一致地自定义 PostgreSQL 配置,我建议将 config_file postgres 选项与 Docker 卷一起使用,如下所示:

生产数据库(PGDATA dir 作为 Persistent Volume)

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

测试数据库(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

调试

  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;
    

【讨论】:

    【解决方案4】:

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

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

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

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

    例子:

    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
    

    这样你就不需要构建新的镜像,也不需要关心是否已经存在的数据库;都会受到影响。

    【讨论】:

    • 最后一个,通过 -c,是我最喜欢的。为不同的环境生成它是如此干净和简单。
    【解决方案5】:

    您可以将自定义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
    • 这是因为 docker-entrypoint-initdb.d/ 文件夹按字母顺序执行脚本。我想在其他人之前应用这个脚本。
    • tnx 我忘记了副本将文件重命名为使用下划线
    【解决方案6】:

    我浏览了所有答案,还有另一个选择。您可以在 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"]
    

    虽然我认为在Matthias Braun 提出的docker-compose.yml 文件中使用command: postgres -c config_file=/etc/postgresql/postgresql.conf 是最好的选择。

    【讨论】:

      【解决方案7】:

      这对我有用:

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

      【讨论】:

      • 为什么没有收到任何赞成票?这是这里最明智的提议...谢谢。
      • @GuillermoSolis:你刚刚复制了@Dr.Botwing 的答案吗?
      【解决方案8】:

      这个问题的一个相当低技术的解决方案似乎是声明服务(我在 AWS 上使用 swarm 和一个 yaml 文件),并将您的数据库文件安装到一个持久卷(这里 AWS EFS 由 cloudtor 表示: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. db 以图像默认设置初始化。
      2. 您可以编辑容器内的 conf 设置,例如,如果您想增加需要重启的最大并发连接数
      3. 停止正在运行的容器(或将服务缩减到零,然后再回到一)
      4. swarm 生成一个新容器,这一次它会拾取您的持久配置设置并愉快地应用它们。

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

      【讨论】:

        【解决方案9】:

        我的解决方案适用于需要在启动 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;
        

        【讨论】:

          【解决方案10】:

          我也在使用官方图片(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"
          

          【讨论】:

            【解决方案11】:

            使用 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
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-12-30
            • 2015-07-06
            • 1970-01-01
            • 2022-12-21
            • 2019-08-26
            • 2019-03-28
            相关资源
            最近更新 更多