Comment personnaliser le fichier de configuration de l'image Docker officielle de PostgreSQL?

102

J'utilise l' image officielle de Postgres Docker pour essayer de personnaliser sa configuration. Pour cela, j'utilise la commande sedpour changer max_connectionspar exemple:

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

J'ai essayé deux méthodes pour appliquer cette configuration. La première consiste à ajouter les commandes à un script et à le copier dans le dossier init "/docker-entrypoint-initdb.d". La deuxième méthode consiste à les exécuter directement dans mon Dockerfile avec la commande "RUN" (cette méthode a bien fonctionné avec une image Postgresql non officielle avec un chemin différent vers le fichier de configuration "/ etc / postgres / ..."). Dans les deux cas, les modifications échouent car le fichier de configuration est manquant (je pense qu'il n'est pas encore créé).

Comment changer la configuration?

Modifier 1:

Voici le Dockerfile utilisé pour créer l'image:

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

Avec ce Dockerfile, le processus de construction affiche l'erreur: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

Sakr
la source
1
une méthode consiste à utiliser l'image officielle, à la démarrer, à vous connecter à l'intérieur docker exec -it container_id bashpuis à effectuer vos modifications, puis à docker commit container_id myuser/myimage_myPostegresql:myversionconsulter le document docs.docker.com/reference/commandline/cli/#commit
user2915097
2
Je pense que l'un des avantages du paradigme docker est d'automatiser l'ensemble du processus de construction. Comme mentionné avec une autre image, paintedfox/postgresqlil est possible de modifier la configuration directement dans le Dockerfile. Je pense que cela devrait également être possible avec l'image officielle.
Sakr
la méthode sed devrait fonctionner, pouvez-vous poster votre fichier Dcoker ou un reproducteur complet?
user2915097

Réponses:

54

L' postgres:9.4image dont vous avez hérité déclare un volume à/var/lib/postgresql/data . Cela signifie essentiellement que vous ne pouvez copier aucun fichier sur ce chemin dans votre image; les modifications seront supprimées.

Vous avez quelques choix:

  • Vous pouvez simplement ajouter vos propres fichiers de configuration en tant que volume au moment de l'exécution avec docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... Cependant, je ne sais pas exactement comment cela interagira avec le volume existant.

  • Vous pouvez copier le fichier au démarrage du conteneur. Pour ce faire, copiez votre fichier dans la construction à un emplacement qui n'est pas sous le volume, puis appelez un script depuis le point d'entrée ou cmd qui copiera le fichier à l'emplacement correct et lancera postgres.

  • Clonez le projet derrière l'image officielle de Postgres et éditez le Dockerfile pour ajouter votre propre fichier de configuration avant que le VOLUME ne soit déclaré (tout ce qui a été ajouté avant que l'instruction VOLUME soit automatiquement copiée au moment de l'exécution).

  • Passer toutes les modifications de configuration dans l'option de commande dans le fichier docker-compose

comme:

services:
  postgres:
    ...  
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...
Adrian Mouat
la source
3
C'était tout, les modifications ne devraient pas être dans le Dockerfile. Je les ai déplacés vers un script et l'ai appelé à partir du point d'entrée et cela a bien fonctionné maintenant. Merci pour la réponse.
Sakr
5
Je viens de copier le script dans le dossier init "/docker-entrypoint-initdb.d/" et cela a également bien fonctionné cette fois. C'est bizarre mais il semble que j'étais tellement concentré sur la définition de l'image avec le Dockerfile, comme j'ai l'habitude de le faire avec la plupart des images, que j'ai raté quelque chose lors de mes premiers essais en utilisant le script init.
Sakr
"Cela signifie essentiellement que vous ne pouvez copier aucun fichier vers ce chemin dans votre image; les modifications seront annulées." Pouvez-vous expliquer pourquoi c'est le cas?
isco
@isco recherche des volumes dans la documentation officielle. Fondamentalement, les volumes ne sont pas stockés dans l'image mais sur l'hôte, de sorte que les données seront enregistrées sur l'hôte, pas dans l'image. Vous devez démarrer le conteneur avec le même volume attaché pour conserver les données.
Adrian Mouat le
Je change dans /var/lib/postgres/data/pg_hba.conf pour accepter uniquement la connexion est l'hôte tous les 192.168.0.0/0 md5 et commente l'hôte tous tous tous les md5 (par défaut). Mais ne changez pas d'effet
Lucas Resende
83

Avec Docker Compose

Lorsque vous travaillez avec Docker Compose, vous pouvez utiliser command: postgres -c option=valuedans votredocker-compose.yml pour configurer Postgres.

Par exemple, cela crée un journal Postgres dans un fichier:

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

En adaptant la réponse de Vojtech Vitek , vous pouvez utiliser

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

pour changer le fichier de configuration que Postgres utilisera. Vous monteriez votre fichier de configuration personnalisé avec un volume:

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

Voici le docker-compose.ymlde mon application, montrant comment configurer 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:

Autorisation d'écrire dans le répertoire du journal

Notez que sous Linux, le répertoire du journal sur l'hôte doit disposer des autorisations appropriées. Sinon, vous obtiendrez l'erreur légèrement trompeuse

FATAL: impossible d'ouvrir le fichier journal "/logs/postgresql-2017-02-04_115222.log": autorisation refusée

Je dis trompeur, car le message d'erreur suggère que le répertoire dans le conteneur a la mauvaise autorisation, alors qu'en réalité le répertoire sur l'hôte ne permet pas d'écrire.

Pour résoudre ce problème, j'ai défini les autorisations correctes sur l'hôte en utilisant

chgroup ./logs docker && chmod 770 ./logs
Matthias Braun
la source
Recommanderiez-vous de créer un journal postgres dans un fichier, plutôt que stdout et d'utiliser les commandes docker logs pour le gérer? bravo pour la réticulation dans le problème github !
jpic
1
Je ne suis pas décidé si la journalisation dans un fichier ou l'utilisation des journaux Docker est préférable, jpic.
Matthias Braun
vous avez ajouté le mot de passe, que vous voudrez probablement masquer ici
vidstige
3
@vidstige: Je n'utilise pas cette chaîne aléatoire comme mot de passe, c'est uniquement à des fins de démonstration.
Matthias Braun
1
@Gherman: Avez-vous ajouté ceci à votre Dockerfile? Parce que tu ne devrais pas. Ma réponse utilise docker-compose.yml.
Matthias Braun
39

Injecter postgresql.conf personnalisé dans le conteneur Docker postgres

Le postgresql.conffichier par défaut se trouve dans PGDATAdir ( /var/lib/postgresql/data), ce qui rend les choses plus compliquées, en particulier lors de l'exécution du conteneur postgres pour la première fois, car le docker-entrypoint.shwrapper appelle l' initdbétape d' PGDATAinitialisation du répertoire.

Pour personnaliser la configuration PostgreSQL dans Docker de manière cohérente, je suggère d'utiliser config_file option postgres avec des volumes Docker comme celui-ci:

Base de données de production (répertoire PGDATA comme volume persistant)

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

Base de données de test (le répertoire PGDATA sera supprimé aprè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

Débogage

  1. Retirer le -d (detach option) de docker runpour afficher directement les journaux du serveur.
  2. Connectez-vous au serveur postgres avec le client psql et interrogez la configuration:

    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
la source
30

Lorsque vous exécutez le point d'entrée officiel (AKA lorsque vous lancez le conteneur), il s'exécute initdbdans $PGDATA( /var/lib/postgresql/datapar défaut), puis il stocke dans ce répertoire ces 2 fichiers:

  • postgresql.conf avec les paramètres manuels par défaut.
  • postgresql.auto.confavec des paramètres remplacés automatiquement avec des ALTER SYSTEMcommandes.

Le point d'entrée exécute également tous les /docker-entrypoint-initdb.d/*.{sh,sql}fichiers.

Tout cela signifie que vous pouvez fournir un script shell / SQL dans ce dossier qui configure le serveur pour le prochain démarrage (qui aura lieu immédiatement après l'initialisation de la base de données ou lors du prochain démarrage du conteneur).

Exemple:

conf.sql fichier:

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

Dockerfile fichier:

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

Et puis vous devrez exécuter conf.sqlmanuellement dans des bases de données déjà existantes. La configuration étant stockée dans le volume, elle survivra aux reconstructions.


Une autre alternative est de passer le -cdrapeau autant de fois que vous le souhaitez:

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

De cette façon, vous n'avez pas besoin de créer une nouvelle image, et vous n'avez pas besoin de vous soucier des bases de données déjà existantes ou non; tout sera affecté.

Yajo
la source
2
Ce dernier, passant -c, est mon préféré. C'est tellement propre et simple à générer pour différents environnements.
epic_fil
10

Vous pouvez placer votre personnalisation postgresql.confdans un fichier temporaire à l'intérieur du conteneur et remplacer la configuration par défaut lors de l'exécution.

Pour faire ça :

  • Copiez votre personnalisé postgresql.confdans votre conteneur
  • Copiez le updateConfig.shfichier dans/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

Au moment de l'exécution, le conteneur exécutera le script à l'intérieur /docker-entrypoint-initdb.d/et écrasera la configuration par défaut par votre configuration personnalisée.

alphayax
la source
pourquoi le "_" dans la deuxième commande de copie? on doit bien pouvoir: /docker-entrypoint-initdb.d/updateConfig.sh?
Fernando Castilla Ospina
3
C'est parce que le dossier docker-entrypoint-initdb.d / exécute les scripts dans l'ordre alphabétique. Et je veux appliquer ce script avant les autres.
alphayax
tnx j'ai oublié que la copie a renommé le fichier pour utiliser le trait de soulignement
Fernando Castilla Ospina
9

J'ai parcouru toutes les réponses et il reste une autre option. Vous pouvez modifier la valeur de votre CMD dans le fichier docker (ce n'est pas le meilleur, mais toujours le moyen possible d'atteindre votre objectif).

Fondamentalement, nous devons

  • Copier le fichier de configuration dans le conteneur Docker
  • Remplacer les options de démarrage postgres

Exemple de fichier 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"]

Bien que je pense que l'utilisation command: postgres -c config_file=/etc/postgresql/postgresql.confdans votre docker-compose.ymlfichier proposé par Matthias Braun est la meilleure option.

Dr Botwing
la source
2

Une solution assez low-tech à ce problème semble être de déclarer le service (j'utilise swarm sur AWS et un fichier yaml) avec vos fichiers de base de données montés sur un volume persistant (ici AWS EFS comme indiqué par le pilote cloudstor: aws spécification).

  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. La base de données apparaît comme initialisée avec les paramètres par défaut de l'image.
  2. Vous modifiez les paramètres de configuration à l'intérieur du conteneur, par exemple si vous souhaitez augmenter le nombre maximum de connexions simultanées qui nécessitent un redémarrage
  3. arrêter le conteneur en cours d'exécution (ou réduire le service à zéro, puis le remettre à un)
  4. l'essaim engendre un nouveau conteneur, qui cette fois-ci récupère vos paramètres de configuration persistants et les applique joyeusement.

Un effet secondaire agréable de la persistance de votre configuration est qu'elle persiste également dans vos bases de données (ou était-ce l'inverse) ;-)

Eoan
la source
2

Ma solution s'adresse aux collègues qui doivent apporter des modifications à la configuration avant de lancer docker-entrypoint-initdb.d

J'avais besoin de changer le paramètre 'shared_preload_libraries', donc pendant son travail, postgres a déjà une nouvelle bibliothèque préchargée et le code dans docker-entrypoint-initdb.d peut l'utiliser.

Je viens donc de patcher le fichier postgresql.conf.sample dans 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

Et avec ce patch, il devient possible d'ajouter une extension dans le fichier .sql dans docker-entrypoint-initdb.d /:

CREATE EXTENSION pg_cron;
40 min
la source
1

Cela fonctionne pour moi:

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 Solis
la source
Pourquoi n'a-t-il pas reçu de votes positifs? C'est la proposition la plus saine ici ... Merci.
Paflow
0

En utilisant docker compose, vous pouvez monter un volume avec postgresql.auto.conf. Exemple:

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
Chauve
la source
Vous ne devez pas modifier le postgresql.auto.confcar il est écrasé. Utilisez le postgresql.confau même endroit.
Baschdl
0

J'utilisais également l'image officielle ( FROM postgres) et j'ai pu modifier la configuration en exécutant les commandes suivantes.

La première chose à faire est de localiser le fichier de configuration PostgreSQL. Cela peut être fait en exécutant cette commande dans votre base de données en cours d'exécution.

SHOW config_file;

Moi mon cas ça revient /data/postgres/postgresql.conf.

L'étape suivante consiste à déterminer quel est le hachage de votre conteneur Docker PostgreSQL en cours d'exécution.

docker ps -a

Cela devrait renvoyer une liste de tous les conteneurs en cours d'exécution. Dans mon cas, ça ressemble à ça.

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

Vous devez maintenant passer au bash à l'intérieur de votre conteneur en exécutant:

docker exec -it 0ba35e5427d9 /bin/bash

À l'intérieur du conteneur, vérifiez si la configuration est dans le bon chemin et affichez-la.

cat /data/postgres/postgresql.conf

Je voulais changer le nombre maximum de connexions de 100 à 1000 et le tampon partagé de 128 Mo à 3 Go. Avec la commande sed, je peux faire une recherche et remplacer par les variables correspondantes dans la configuration.

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

La dernière chose que nous devons faire est de redémarrer la base de données dans le conteneur. Découvrez quelle version de PostGres vous utilisez.

cd /usr/lib/postgresql/
ls 

Dans mon cas 12 , vous pouvez maintenant redémarrer la base de données en exécutant la commande suivante avec la version correcte en place.

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"
Sébastien
la source