Как настроить файл конфигурации официального образа PostgreSQL Docker?

Я использую официальный образ Postgres Docker, пытаясь настроить его конфигурацию. Для этого я использую команду sed изменить max_connections например:

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

Я попробовал два способа применить эту конфигурацию. Первый - это добавить команды в скрипт и скопировать его в папку инициализации "/docker-entrypoint-initdb.d". Второй метод заключается в запуске их непосредственно в моем Dockerfile с помощью команды "RUN" (этот метод отлично работал с неофициальным образом 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

13 ответов

Решение

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

При работе с 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 каталог журналов на хосте должен иметь необходимые разрешения. В противном случае вы получите слегка вводящую в заблуждение ошибку

FATAL: не удалось открыть файл журнала "/logs/postgresql-2017-02-04_115222.log": разрешение отклонено

Я говорю, что вводит в заблуждение, поскольку сообщение об ошибке предполагает, что каталог в контейнере имеет неправильное разрешение, хотя в действительности каталог на хосте не разрешает запись.

Чтобы исправить это, я установил правильные разрешения на хосте, используя

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

Когда вы запускаете официальную точку входа (AKA, когда вы запускаете контейнер), она запускается initdb в $PGDATA (/var/lib/postgresql/data по умолчанию), а затем сохраняет в этом каталоге эти 2 файла:

  • postgresql.conf с ручными настройками по умолчанию.
  • postgresql.auto.conf настройки переопределяются автоматически ALTER SYSTEM команды.

Точка входа также выполняет любые /docker-entrypoint-initdb.d/*.{sh,sql} файлы.

Все это означает, что в эту папку можно добавить сценарий оболочки /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

Таким образом, вам не нужно создавать новый образ, и вам не нужно заботиться о уже существующих или не базах данных; все будет затронуто.

Внедрить пользовательский файл postgresql.conf в контейнер Postgres Docker

По умолчанию postgresql.conf файл живет в пределах PGDATA реж (/var/lib/postgresql/data), что усложняет задачу, особенно при первом запуске контейнера postgres, поскольку docker-entrypoint.sh обертка вызывает initdb шаг для PGDATA dir инициализация.

Чтобы последовательно настроить конфигурацию PostgreSQL в Docker, я предлагаю использовать config_file Опция postgres вместе с такими томами Docker:

Производственная база данных (PGDATA dir как постоянный том)

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. Удалить -d (опция отсоединения) от docker run Команда, чтобы увидеть журналы сервера напрямую.
  2. Подключитесь к серверу postgres с помощью клиента psql и запросите конфигурацию:

    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;
    

Вы можете поставить свой заказ 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/ и перезаписать конфигурацию по умолчанию своей собственной.

Я просмотрел все ответы и остался еще один вариант. Вы можете изменить значение CMD в файле Docker (это не самый лучший, но все же возможный способ достижения вашей цели).

В основном нам нужно

  • Скопируйте файл конфигурации в 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.confв вашем docker-compose.yml Файл, предложенный Матиасом Брауном, является лучшим вариантом.

Это работает для меня:

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

Я также использовал официальное изображение (FROM postgres), и мне удалось изменить конфигурацию, выполнив следующие команды.

Во-первых, найдите файл конфигурации PostgreSQL. Это можно сделать, выполнив эту команду в вашей работающей базе данных.

SHOW config_file;

В моем случае он возвращается /data/postgres/postgresql.conf.

Следующим шагом является определение хэша вашего запущенного контейнера докеров PostgreSQL.

docker ps -a

Это должно вернуть список всех работающих контейнеров. В моем случае это выглядит так.

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

Теперь вам нужно переключиться на bash внутри вашего контейнера, выполнив:

docker exec -it 0ba35e5427d9 /bin/bash

Внутри контейнера проверьте правильность пути конфигурации и отобразите ее.

cat /data/postgres/postgresql.conf

Я хотел изменить максимальное количество подключений со 100 до 1000, а общий буфер со 128 МБ до 3 ГБ. С помощью команды 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"

Мое решение для коллег, которым необходимо внести изменения в конфигурацию перед запуском docker-entrypoint-initdb.d

Мне нужно было изменить настройку shared_preload_libraries, чтобы во время работы postgres уже предварительно загружала новую библиотеку и могла использовать код в docker-entrypoint-initdb.d.

Поэтому я просто пропатчил файл postgresql.conf.sample в Dockerfile:

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

И с этим патчем стало возможным добавить расширение в файл.sql в docker-entrypoint-initdb.d/:

CREATE EXTENSION pg_cron;

Похоже, что довольно простое решение этой проблемы состоит в том, чтобы объявить службу (я использую swarm на AWS и файл 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. рой порождает новый контейнер, который на этот раз подбирает ваши сохраненные настройки конфигурации и весело применяет их.

Приятным побочным эффектом сохранения вашей конфигурации является то, что она также сохраняет ваши базы данных (или наоборот);-)

Используя 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

В моем конкретном случае меня интересовало включение SSL при использовании стандартного образа postgres через docker-compose. Это решение позволяет initdb запускаться как обычно, что полезно для настройки БД и пользователей.

docker-compose.yaml

      version: '3'
services:
  postgres:
    image: postgres:12.2
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_USER=myuser
      - POSTGRES_HOST_AUTH_MTHOD=trust
    volumes:
      - ./postgres-initdb:/docker-entrypoint-initdb.d/
      - ./postgres-certs/:/var/lib/postgresql/certs/

postgres-initdb/config.sql

      ALTER SYSTEM SET ssl_cert_file TO '/var/lib/postgresql/certs/server.crt';
ALTER SYSTEM SET ssl_key_file TO '/var/lib/postgresql/certs/server.key';
ALTER SYSTEM SET ssl TO 'ON';

Это будет работать для любой конфигурации. Для SSL вы также захотите сгенерировать сертификаты (взятые из Gist ):

      set -euo pipefail

mkdir postgres-certs
cd postgres-certs

openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt
chmod 600 server.key
test $(uname -s) == Linux && chown 999 server.key

Еще один ответ для полноты картины — отредактируйте файл вручную!

Что вы уже делаете на этом этапе:

  1. Вы монтируете каталог хоста в контейнер во время выполнения.
  2. Вы инициализировали базу данных

Вы должны монтировать каталог данных как том, иначе база данных будет эфемерной, что сведет на нет смысл запуска базы данных. Поскольку вы уже монтируете его, файл уже существует на хост-компьютере (например, на вашем ноутбуке Macos), поэтому просто отредактируйте его.

      # you're mounting this into the container anyway, just edit it
vim data/pg_hba.conf

# Mount a volume and run, like you're already doing
docker run -v ./data:/var/lib/postgresql/data image cmd

Это хорошо работает дляpg_hba.conf, где вам часто нужно добавить строку, но вы не хотите, чтобы эта строка повторялась каждый раз при запуске сервера (что может произойти, если вы используете/docker-entrypoint-initdb.d/00-init.shподход.

Плюсы такого подхода:

  1. Просто: не нужно думать о жизненном цикле файлов и томов. Ваша отредактированная копия перезапишет любые другие изменения, которые были внесены в другом месте.
  2. Настройте каждую среду по-разному

Минусы:

  1. Никакой автоматизации
  2. Это нарушает парадигму «инфраструктура как код».

С другой стороны, вы также можете довольно легко смягчить эти недостатки.

Другие вопросы по тегам