Come personalizzare il file di configurazione dell'immagine Docker PostgreSQL ufficiale?


102

Sto usando l' immagine Docker Postgres ufficiale cercando di personalizzarne la configurazione. A tal fine, utilizzo il comando sedper modificare max_connectionsad esempio:

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

Ho provato due metodi per applicare questa configurazione. Il primo consiste nell'aggiungere i comandi a uno script e copiarlo nella cartella init "/docker-entrypoint-initdb.d". Il secondo metodo è eseguirli direttamente nel mio Dockerfile con il comando "RUN" (questo metodo ha funzionato bene con un'immagine Postgresql non ufficiale con un percorso diverso al file di configurazione "/ etc / postgres / ..."). In entrambi i casi le modifiche falliscono perché manca il file di configurazione (credo che non sia ancora stato creato).

Come devo modificare la configurazione?

Modifica 1:

Ecco il Dockerfile utilizzato per creare l'immagine:

# 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 questo Dockerfile il processo di compilazione mostra l'errore: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory


1
un metodo è utilizzare l'immagine ufficiale, avviarla, connettersi all'interno con docker exec -it container_id bashquindi apportare le modifiche, quindi docker commit container_id myuser/myimage_myPostegresql:myversionconsultare il documento docs.docker.com/reference/commandline/cli/#commit
user2915097

2
Penso che uno dei vantaggi del paradigma docker sia l'automatizzazione dell'intero processo di compilazione. Come accennato con un'altra immagine, paintedfox/postgresqlè possibile modificare la configurazione direttamente all'interno del Dockerfile. Penso che dovrebbe essere possibile anche con l'immagine ufficiale.
Sakr

il metodo sed dovrebbe funzionare, puoi pubblicare il tuo Dcokerfile o un riproduttore completo?
user2915097

Risposte:


54

L' postgres:9.4immagine da cui hai ereditato dichiara un volume in /var/lib/postgresql/data. Ciò significa essenzialmente che non puoi copiare alcun file in quel percorso nella tua immagine; le modifiche verranno eliminate.

Hai alcune scelte:

  • Puoi semplicemente aggiungere i tuoi file di configurazione come volume in fase di esecuzione con docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... Tuttavia, non sono sicuro di come interagirà con il volume esistente.

  • È possibile copiare il file quando viene avviato il contenitore. Per fare ciò, copia il tuo file nella build in una posizione che non è sotto il volume, quindi chiama uno script dal punto di ingresso o cmd che copierà il file nella posizione corretta e avvierà postgres.

  • Clona il progetto dietro l'immagine ufficiale di Postgres e modifica il Dockerfile per aggiungere il tuo file di configurazione prima che venga dichiarato VOLUME (qualsiasi cosa aggiunta prima dell'istruzione VOLUME viene automaticamente copiata in fase di esecuzione).

  • Passa tutte le modifiche alla configurazione nell'opzione di comando nel file docker-compose

piace:

services:
  postgres:
    ...  
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...

3
Ecco fatto, le modifiche non dovrebbero essere all'interno del Dockerfile. Li ho spostati in uno script e l'ho chiamato dal punto di ingresso e ora ha funzionato bene. Grazie per la risposta.
Sakr

5
Ho appena copiato lo script nella cartella init "/docker-entrypoint-initdb.d/" e anche questa volta ha funzionato bene. È strano ma sembra che fossi così concentrato sull'impostazione dell'immagine con Dockerfile, come sono abituato a fare con la maggior parte delle immagini, che mi sono perso qualcosa nei miei primi tentativi con lo script di inizializzazione.
Sakr

"Ciò significa essenzialmente che non puoi copiare alcun file in quel percorso dell'immagine; le modifiche verranno eliminate." Potresti spiegare perché è così?
isco

@isco cerca i volumi nei documenti ufficiali. Fondamentalmente i volumi non sono archiviati nell'immagine ma nell'host, quindi i dati verranno salvati sull'host, non nell'immagine. Dovresti avviare il contenitore con lo stesso volume collegato per conservare i dati.
Adrian Mouat

cambio in /var/lib/postgres/data/pg_hba.conf per accettare solo la connessione è host tutti tutti 192.168.0.0/0 md5 e commentare tutti tutti tutti md5 (è l'impostazione predefinita). Ma non cambiare effetto
Lucas Resende

83

Con Docker Compose

Quando lavori con Docker Compose, puoi usare command: postgres -c option=valuenel tuo docker-compose.ymlper configurare Postgres.

Ad esempio, questo fa sì che Postgres registri in un file:

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

Adattando la risposta di Vojtech Vitek , puoi usare

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

per modificare il file di configurazione che Postgres utilizzerà. Dovresti montare il tuo file di configurazione personalizzato con un volume:

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

Ecco la docker-compose.ymlmia applicazione, che mostra come configurare 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:

Autorizzazione a scrivere nella directory di registro

Tieni presente che quando sei su Linux, la directory di log sull'host deve avere le autorizzazioni corrette. Altrimenti otterrai l'errore leggermente fuorviante

IRREVERSIBILE: impossibile aprire il file di registro "/logs/postgresql-2017-02-04_115222.log": autorizzazione negata

Dico fuorviante, poiché il messaggio di errore suggerisce che la directory nel contenitore ha il permesso sbagliato, quando in realtà la directory sull'host non consente la scrittura.

Per risolvere questo problema, ho impostato le autorizzazioni corrette sull'host utilizzando

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

Consiglieresti di creare un log di postgres in un file, piuttosto che stdout e utilizzare i comandi docker logs per gestirlo? complimenti per la reticolazione nel problema di github !
jpic

1
Non sono deciso se sia preferibile la registrazione su file o l'utilizzo dei log Docker, jpic.
Matthias Braun

hai aggiunto la password, che probabilmente vorrai mascherare qui
vidstige

3
@vidstige: non uso questa stringa casuale come password, è solo a scopo dimostrativo.
Matthias Braun

1
@ German: hai aggiunto questo al tuo Dockerfile? Perché non dovresti. La mia risposta usa docker-compose.yml.
Matthias Braun

39

Inietta postgresql.conf personalizzato nel container Docker di postgres

Il postgresql.conffile predefinito risiede all'interno di PGDATAdir ( /var/lib/postgresql/data), il che rende le cose più complicate soprattutto quando si esegue il contenitore postgres per la prima volta, poiché il docker-entrypoint.shwrapper invoca il initdbpassaggio per l' PGDATAinizializzazione di dir.

Per personalizzare la configurazione di PostgreSQL in Docker in modo coerente, suggerisco di utilizzare l' config_fileopzione postgres insieme a volumi Docker come questo:

Database di produzione (PGDATA dir as 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

Database di test (la directory PGDATA verrà eliminata dopo 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

Debug

  1. Rimuovere l ' -d(opzione di scollegamento) dal docker runcomando per visualizzare direttamente i log del server.
  2. Connettiti al server postgres con il client psql e interroga la configurazione:

    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;

30

Quando si esegue l'entrypoint ufficiale (AKA quando si avvia il contenitore), viene eseguito initdbin $PGDATA( /var/lib/postgresql/dataper impostazione predefinita), e quindi memorizza in tale directory questi 2 file:

  • postgresql.conf con le impostazioni manuali predefinite.
  • postgresql.auto.confcon le impostazioni sovrascritte automaticamente dai ALTER SYSTEMcomandi.

Il punto di ingresso esegue anche qualsiasi /docker-entrypoint-initdb.d/*.{sh,sql}file.

Tutto ciò significa che puoi fornire uno script shell / SQL in quella cartella che configura il server per il prossimo avvio (che sarà immediatamente dopo l'inizializzazione del DB, o la prossima volta che avvierai il contenitore).

Esempio:

conf.sql file:

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

Dockerfile file:

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

E poi dovrai eseguire conf.sqlmanualmente in database già esistenti. Poiché la configurazione è archiviata nel volume, sopravviverà alle ricostruzioni.


Un'altra alternativa è passare la -cbandiera tutte le volte che vuoi:

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

In questo modo non è necessario creare una nuova immagine e non è necessario preoccuparsi di database già esistenti o meno; tutto sarà influenzato.


2
Quest'ultimo, passando -c, è il mio preferito. Questo è così pulito e semplice da generare per diversi ambienti.
epic_fil

10

È possibile inserire la personalizzazione postgresql.confin un file temporaneo all'interno del contenitore e sovrascrivere la configurazione predefinita in fase di esecuzione.

Fare quello :

  • Copia la tua personalizzazione postgresql.confall'interno del tuo contenitore
  • Copia il updateConfig.shfile in formato/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

In fase di esecuzione, il contenitore eseguirà lo script all'interno /docker-entrypoint-initdb.d/e sovrascriverà la configurazione predefinita con quella personalizzata.


perché "_" nel secondo comando di copia? non dovrebbe che si tratti di: /docker-entrypoint-initdb.d/updateConfig.sh?
Fernando Castilla Ospina

3
È perché la cartella docker-entrypoint-initdb.d / esegue gli script in ordine alfabetico. E voglio applicare questo script prima degli altri.
alphayax

tnx ho dimenticato che la copia ha rinominato il file per utilizzare il trattino basso
Fernando Castilla Ospina

9

Ho esaminato tutte le risposte e rimane un'altra opzione. Puoi modificare il tuo valore CMD nel file docker (non è il migliore, ma è comunque il modo possibile per raggiungere il tuo obiettivo).

Fondamentalmente ne abbiamo bisogno

  • Copia il file di configurazione nel contenitore Docker
  • Ignora le opzioni di avvio di postgres

Esempio di file 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"]

Anche se penso che l'utilizzo command: postgres -c config_file=/etc/postgresql/postgresql.confnel tuo docker-compose.ymlfile proposto da Matthias Braun sia l'opzione migliore.


2

Una soluzione abbastanza a bassa tecnologia a questo problema sembra essere quella di dichiarare il servizio (sto usando swarm su AWS e un file yaml) con i file di database montati su un volume persistente (qui AWS EFS come indicato dal cloudstor: driver aws specifica).

  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. Il db si presenta come inizializzato con le impostazioni predefinite dell'immagine.
  2. Si modificano le impostazioni di configurazione all'interno del contenitore, ad esempio se si desidera aumentare il numero massimo di connessioni simultanee che richiedono un riavvio
  3. fermare il container in esecuzione (o ridimensionare il servizio fino a zero e poi di nuovo a uno)
  4. lo sciame genera un nuovo contenitore, che questa volta raccoglie le impostazioni di configurazione persistenti e le applica allegramente.

Un piacevole effetto collaterale del persistere della configurazione è che persiste anche i tuoi database (o era il contrario) ;-)


2

La mia soluzione è per i colleghi che hanno bisogno di apportare modifiche alla configurazione prima di avviare docker-entrypoint-initdb.d

Avevo bisogno di cambiare l'impostazione 'shared_preload_libraries' così durante il suo lavoro postgres ha già una nuova libreria precaricata e il codice in docker-entrypoint-initdb.d può usarla.

Quindi ho appena corretto il file postgresql.conf.sample in 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

E con questa patch è possibile aggiungere l'estensione nel file .sql in docker-entrypoint-initdb.d /:

CREATE EXTENSION pg_cron;

1

Questo funziona per me:

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

Perché questo non ha ricevuto alcun voto positivo? È la proposta più sensata qui ... Grazie.
Paflow,

0

Utilizzando docker compose puoi montare un volume con postgresql.auto.conf. Esempio:

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

Non modificare il file postgresql.auto.confpoiché viene sovrascritto. Usa il postgresql.confnella stessa posizione.
Baschdl

0

Stavo anche usando l'immagine ufficiale ( FROM postgres) e sono stato in grado di modificare la configurazione eseguendo i seguenti comandi.

La prima cosa è individuare il file di configurazione di PostgreSQL. Questo può essere fatto eseguendo questo comando nel database in esecuzione.

SHOW config_file;

Se il mio caso ritorna /data/postgres/postgresql.conf.

Il passo successivo è scoprire qual è l'hash del tuo container Docker PostgreSQL in esecuzione.

docker ps -a

Questo dovrebbe restituire un elenco di tutti i contenitori in esecuzione. Nel mio caso sembra così.

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

Ora devi passare alla bash all'interno del tuo contenitore eseguendo:

docker exec -it 0ba35e5427d9 /bin/bash

All'interno del contenitore controlla se la configurazione è nel percorso corretto e visualizzalo.

cat /data/postgres/postgresql.conf

Volevo modificare le connessioni massime da 100 a 1000 e il buffer condiviso da 128 MB a 3 GB. Con il comando sed posso fare una ricerca e sostituire con le variabili corrispondenti nel file config.

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

L'ultima cosa che dobbiamo fare è riavviare il database all'interno del contenitore. Scopri quale versione di PostGres stai utilizzando.

cd /usr/lib/postgresql/
ls 

Nel mio caso è 12 quindi ora possibile riavviare il database eseguendo il seguente comando con la versione corretta in atto.

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.