¿Cómo personalizar el archivo de configuración de la imagen oficial de PostgreSQL Docker?

102

Estoy usando la imagen oficial de Postgres Docker tratando de personalizar su configuración. Para este propósito, uso el comando sedpara cambiar, max_connectionspor ejemplo:

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

Probé dos métodos para aplicar esta configuración. La primera es agregar los comandos a un script y copiarlo dentro de la carpeta de inicio "/docker-entrypoint-initdb.d". El segundo método es ejecutarlos directamente dentro de mi Dockerfile con el comando "RUN" (este método funcionó bien con una imagen de Postgresql no oficial con una ruta diferente al archivo de configuración "/ etc / postgres / ..."). En ambos casos, los cambios fallan porque falta el archivo de configuración (creo que aún no se ha creado).

¿Cómo debo cambiar la configuración?

Edición 1:

Aquí está el Dockerfile usado para crear la imagen:

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

Con este Dockerfile, el proceso de compilación muestra el error: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

Sakr
fuente
1
un método es usar la imagen oficial, iniciarla, conectarse dentro y docker exec -it container_id bashluego hacer sus modificaciones, luego docker commit container_id myuser/myimage_myPostegresql:myversionver el documento docs.docker.com/reference/commandline/cli/#commit
user2915097
2
Creo que una de las ventajas del paradigma de la ventana acoplable es automatizar todo el proceso de construcción. Como se mencionó con otra imagen, paintedfox/postgresqles posible cambiar la configuración directamente dentro del Dockerfile. Creo que eso también debería ser posible con la imagen oficial.
Sakr
el método sed debería funcionar, ¿puedes publicar tu Dcokerfile o un reproductor completo?
user2915097

Respuestas:

54

La postgres:9.4imagen que ha heredado declara un volumen en /var/lib/postgresql/data. Básicamente, esto significa que no puede copiar ningún archivo a esa ruta en su imagen; los cambios se descartarán.

Tienes algunas opciones:

  • Puede agregar sus propios archivos de configuración como un volumen en tiempo de ejecución con docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... Sin embargo, no estoy seguro de cómo interactuará exactamente con el volumen existente.

  • Puede copiar el archivo cuando se inicia el contenedor. Para hacer eso, copie su archivo en la compilación en una ubicación que no esté debajo del volumen, luego llame a un script desde el punto de entrada o cmd que copiará el archivo a la ubicación correcta e iniciará postgres.

  • Clone el proyecto detrás de la imagen oficial de Postgres y edite el Dockerfile para agregar su propio archivo de configuración antes de que se declare VOLUME (cualquier cosa agregada antes de que la instrucción VOLUME se copia automáticamente en el tiempo de ejecución).

  • Pase todos los cambios de configuración en la opción de comando en el archivo docker-compose

me gusta:

services:
  postgres:
    ...  
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...
Adrian Mouat
fuente
3
Eso fue todo, los cambios no deberían estar dentro del Dockerfile. Los moví a un script y lo llamé desde el punto de entrada y ahora funcionó bien. Gracias por la respuesta.
Sákr
5
Acabo de copiar el script dentro de la carpeta de inicio "/docker-entrypoint-initdb.d/" y también funcionó bien esta vez. Eso es extraño, pero parece que estaba tan concentrado en configurar la imagen con el Dockerfile, como estoy acostumbrado a hacer con la mayoría de las imágenes, que me perdí algo en mis primeros intentos usando el script de inicio.
Sákr
"Esto esencialmente significa que no puede copiar ningún archivo a esa ruta en su imagen; los cambios se descartarán". ¿Podría explicar por qué ese es el caso?
isco
@isco busca volúmenes en los documentos oficiales. Básicamente, los volúmenes no se almacenan en la imagen sino en el host, por lo que los datos se guardarán en el host, no en la imagen. Debería iniciar el contenedor con el mismo volumen adjunto para conservar los datos.
Adrian Mouat
cambio en /var/lib/postgres/data/pg_hba.conf para aceptar solo la conexión es el host todo 192.168.0.0/0 md5 y el host de comentarios todo todo md5 (es predeterminado). Pero no cambie el efecto
Lucas Resende
83

Con Docker Compose

Cuando se trabaja con estibador de composición, se puede utilizar command: postgres -c option=valueen su docker-compose.ymlconfigurar Postgres.

Por ejemplo, esto hace que Postgres se registre en un archivo:

command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs

Adaptando la respuesta de Vojtech Vitek , puede usar

command: postgres -c config_file=/etc/postgresql.conf

para cambiar el archivo de configuración que utilizará Postgres. Montarías tu archivo de configuración personalizado con un volumen:

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

Aquí está el docker-compose.ymlde mi aplicación, que muestra cómo configurar 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:

Permiso para escribir en el directorio de registro

Tenga en cuenta que cuando está en Linux, el directorio de registro del host debe tener los permisos adecuados. De lo contrario, obtendrá el error ligeramente engañoso

FATAL: no se pudo abrir el archivo de registro "/logs/postgresql-2017-02-04_115222.log": Permiso denegado

Digo engañoso, ya que el mensaje de error sugiere que el directorio en el contenedor tiene el permiso incorrecto, cuando en realidad el directorio en el host no permite escribir.

Para solucionar esto, configuré los permisos correctos en el host usando

chgroup ./logs docker && chmod 770 ./logs
Matthias Braun
fuente
¿Recomendaría hacer un registro de postgres en un archivo, en lugar de stdout y usar los comandos de registros de docker para manejarlo? felicitaciones por la reticulación en el problema de github !
jpic
1
No estoy decidido si es preferible iniciar sesión en un archivo o usar los registros de Docker, jpic.
Matthias Braun
agregó la contraseña, que probablemente desee enmascarar aquí
vidstige
3
@vidstige: No uso esta cadena aleatoria como contraseña, es solo para demostración.
Matthias Braun
1
@Gherman: ¿Agregaste esto a tu Dockerfile? Porque no deberías. Mi respuesta usa docker-compose.yml.
Matthias Braun
39

Inyecte postgresql.conf personalizado en el contenedor Docker de postgres

El postgresql.confarchivo predeterminado vive dentro de PGDATAdir ( /var/lib/postgresql/data), lo que complica las cosas, especialmente cuando se ejecuta el contenedor postgres por primera vez, ya que el docker-entrypoint.shcontenedor invoca el initdbpaso para la PGDATAinicialización de dir.

Para personalizar la configuración de PostgreSQL en Docker de manera consistente, sugiero usar la config_fileopción de postgres junto con volúmenes de Docker como este:

Base de datos de producción (directorio PGDATA como volumen persistente)

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

Prueba de base de datos (el directorio PGDATA se descartará después 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

Depuración

  1. Elimine la -d(opción de desconexión) del docker runcomando para ver los registros del servidor directamente.
  2. Conéctese al servidor de postgres con el cliente psql y consulte la configuración:

    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;
Vojtech Vitek
fuente
30

Cuando se ejecuta el punto de entrada oficial (También conocido como cuando se lanza el contenedor), que se ejecuta initdben $PGDATA( /var/lib/postgresql/datapor defecto), y luego se almacena en el directorio que estos 2 archivos:

  • postgresql.conf con la configuración manual predeterminada.
  • postgresql.auto.confcon configuraciones anuladas automáticamente con ALTER SYSTEMcomandos.

El punto de entrada también ejecuta cualquier /docker-entrypoint-initdb.d/*.{sh,sql}archivo.

Todo esto significa que puede proporcionar un script shell / SQL en esa carpeta que configura el servidor para el próximo inicio (que será inmediatamente después de la inicialización de la base de datos, o las próximas veces que inicie el contenedor).

Ejemplo:

conf.sql expediente:

ALTER SYSTEM SET max_connections = 6;
ALTER SYSTEM RESET shared_buffers;

Dockerfile expediente:

FROM posgres:9.6-alpine
COPY *.sql /docker-entrypoint-initdb.d/
RUN chmod a+r /docker-entrypoint-initdb.d/*

Y luego tendrá que ejecutar conf.sqlmanualmente en bases de datos ya existentes. Dado que la configuración se almacena en el volumen, sobrevivirá a las reconstrucciones.


Otra alternativa es pasar la -cbandera tantas veces como desee:

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

De esta manera, no necesita crear una nueva imagen y no necesita preocuparse por las bases de datos ya existentes o no; todos se verán afectados.

Yajo
fuente
2
Este último, que pasa -c, es mi favorito. Esto es tan limpio y simple de generar para diferentes entornos.
epic_fil
10

Puede poner su personalizado postgresql.confen un archivo temporal dentro del contenedor y sobrescribir la configuración predeterminada en tiempo de ejecución.

Para hacer eso :

  • Copie su costumbre postgresql.confdentro de su contenedor
  • Copie el updateConfig.sharchivo en/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

En tiempo de ejecución, el contenedor ejecutará el script dentro /docker-entrypoint-initdb.d/y sobrescribirá la configuración predeterminada con la personalizada.

alphayax
fuente
¿Por qué el "_" en el segundo comando de copia? ¿No debería ser /docker-entrypoint-initdb.d/updateConfig.sh:?
Fernando Castilla Ospina
3
Es porque la carpeta docker-entrypoint-initdb.d / ejecuta scripts en orden alfabético. Y quiero aplicar este script antes que los demás.
alphayax
tnx Olvidé que la copia cambió el nombre del archivo para usar el guión bajo
Fernando Castilla Ospina
9

Revisé todas las respuestas y me queda otra opción. Puede cambiar su valor de CMD en el archivo de la ventana acoplable (no es la mejor, pero aún es una forma posible de lograr su objetivo).

Básicamente necesitamos

  • Copie el archivo de configuración en el contenedor de la ventana acoplable
  • Anular las opciones de inicio de postgres

Ejemplo de archivo 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"]

Aunque creo que usarlo command: postgres -c config_file=/etc/postgresql/postgresql.confen su docker-compose.ymlarchivo propuesto por Matthias Braun es la mejor opción.

Dr. Botwing
fuente
2

Una solución de baja tecnología para este problema parece ser declarar el servicio (estoy usando swarm en AWS y un archivo yaml) con los archivos de su base de datos montados en un volumen persistente (aquí AWS EFS como lo indica el controlador cloudstor: aws especificación).

  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. El db aparece como inicializado con la configuración predeterminada de la imagen.
  2. Edita la configuración de conf dentro del contenedor, por ejemplo, si desea aumentar el número máximo de conexiones simultáneas que requieren un reinicio
  3. detener el contenedor en funcionamiento (o reducir el servicio a cero y luego volver a uno)
  4. el enjambre genera un nuevo contenedor, que esta vez recoge sus ajustes de configuración persistentes y los aplica alegremente.

Un efecto secundario agradable de conservar su configuración es que también conserva sus bases de datos (o fue al revés) ;-)

Eoan
fuente
2

Mi solución es para colegas que necesitan realizar cambios en la configuración antes de iniciar docker-entrypoint-initdb.d

Se me necesitaba para cambiar la configuración de 'shared_preload_libraries', por lo que durante su trabajo, Postgres ya tiene una nueva biblioteca precargada y el código en docker-entrypoint-initdb.d puede usarlo.

Así que acabo de parchear el archivo postgresql.conf.sample en 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

Y con este parche es posible agregar una extensión en el archivo .sql en docker-entrypoint-initdb.d /:

CREATE EXTENSION pg_cron;
40min
fuente
1

Esto funciona para mi:

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"]
Guillermo Solís
fuente
¿Por qué esto no recibió ningún voto positivo? Es la propuesta más sensata aquí ... Gracias.
Paflow
0

Utilizando docker compose puede montar un volumen con postgresql.auto.conf. Ejemplo:

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
Calvo
fuente
No debe editar el postgresql.auto.confya que se sobrescribe. Utilice el postgresql.confen el mismo lugar.
Baschdl
0

También estaba usando la imagen oficial ( FROM postgres) y pude cambiar la configuración ejecutando los siguientes comandos.

Lo primero es ubicar el archivo de configuración de PostgreSQL. Esto se puede hacer ejecutando este comando en su base de datos en ejecución.

SHOW config_file;

Yo mi caso vuelve /data/postgres/postgresql.conf.

El siguiente paso es averiguar cuál es el hash de su contenedor Docker PostgreSQL en ejecución.

docker ps -a

Esto debería devolver una lista de todos los contenedores en ejecución. En mi caso se ve así.

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

Ahora tienes que cambiar al bash dentro de tu contenedor ejecutando:

docker exec -it 0ba35e5427d9 /bin/bash

Dentro del contenedor, verifique si la configuración está en la ruta correcta y muéstrela.

cat /data/postgres/postgresql.conf

Quería cambiar las conexiones máximas de 100 a 1000 y el búfer compartido de 128 MB a 3 GB. Con el comando sed puedo hacer una búsqueda y reemplazar con las variables correspondientes en la configuración.

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

Lo último que tenemos que hacer es reiniciar la base de datos dentro del contenedor. Descubra qué versión de PostGres está utilizando.

cd /usr/lib/postgresql/
ls 

En mi caso, es 12 así que ahora puede reiniciar la base de datos ejecutando el siguiente comando con la versión correcta en su lugar.

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"
Sebastián
fuente