Как настроить файл конфигурации официального образа 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
отладка
- Удалить
-d
(опция отсоединения) отdocker run
Команда, чтобы увидеть журналы сервера напрямую. Подключитесь к серверу 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"
- БД появляется как инициализированный с настройками изображения по умолчанию.
- Вы редактируете настройки conf внутри контейнера, например, если хотите увеличить максимальное количество одновременных соединений, требующих перезапуска
- остановить работающий контейнер (или уменьшить службу до нуля, а затем вернуться к единице)
- рой порождает новый контейнер, который на этот раз подбирает ваши сохраненные настройки конфигурации и весело применяет их.
Приятным побочным эффектом сохранения вашей конфигурации является то, что она также сохраняет ваши базы данных (или наоборот);-)
Используя 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
Еще один ответ для полноты картины — отредактируйте файл вручную!
Что вы уже делаете на этом этапе:
- Вы монтируете каталог хоста в контейнер во время выполнения.
- Вы инициализировали базу данных
Вы должны монтировать каталог данных как том, иначе база данных будет эфемерной, что сведет на нет смысл запуска базы данных. Поскольку вы уже монтируете его, файл уже существует на хост-компьютере (например, на вашем ноутбуке 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
подход.
Плюсы такого подхода:
- Просто: не нужно думать о жизненном цикле файлов и томов. Ваша отредактированная копия перезапишет любые другие изменения, которые были внесены в другом месте.
- Настройте каждую среду по-разному
Минусы:
- Никакой автоматизации
- Это нарушает парадигму «инфраструктура как код».
С другой стороны, вы также можете довольно легко смягчить эти недостатки.