Jak dostosować plik konfiguracyjny oficjalnego obrazu PostgreSQL Docker?

102

Używam oficjalnego obrazu Postgres Docker, próbując dostosować jego konfigurację. W tym celu używam polecenia seddo zmiany max_connectionsnp .:

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

Wypróbowałem dwie metody, aby zastosować tę konfigurację. Pierwsza polega na dodaniu poleceń do skryptu i skopiowaniu go w folderze init „/docker-entrypoint-initdb.d”. Druga metoda polega na uruchomieniu ich bezpośrednio w moim pliku Dockerfile za pomocą polecenia „RUN” (ta metoda działała dobrze z nieoficjalnym obrazem Postgresql z inną ścieżką do pliku konfiguracyjnego „/ etc / postgres / ...”). W obu przypadkach zmiany kończą się niepowodzeniem, ponieważ brakuje pliku konfiguracyjnego (myślę, że nie został jeszcze utworzony).

Jak zmienić konfigurację?

Edycja 1:

Oto plik Dockerfile użyty do utworzenia obrazu:

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

W tym pliku Dockerfile proces kompilacji pokazuje błąd: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

Sakr
źródło
1
jedną z metod jest użycie oficjalnego obrazu, uruchomienie go, połączenie się z nim, docker exec -it container_id basha następnie wprowadzenie zmian, a następnie docker commit container_id myuser/myimage_myPostegresql:myversionzobacz docs.docker.com/reference/commandline/cli/#commit
user2915097
2
Myślę, że jedną z zalet paradygmatu dockera jest automatyzacja całego procesu budowania. Jak wspomniano w innym obrazie, paintedfox/postgresqlmożliwa jest zmiana konfiguracji bezpośrednio w pliku Dockerfile. Myślę, że powinno to być również możliwe z oficjalnym wizerunkiem.
Sakr
metoda sed powinna zadziałać, czy możesz wysłać swój plik Dcokerfile lub kompletny reproduktor?
user2915097

Odpowiedzi:

54

postgres:9.4Obraz masz odziedziczone deklaruje głośność na /var/lib/postgresql/data. Zasadniczo oznacza to, że nie możesz kopiować żadnych plików do tej ścieżki w obrazie; zmiany zostaną odrzucone.

Masz kilka możliwości:

  • Możesz po prostu dodać własne pliki konfiguracyjne jako wolumin w czasie wykonywania z docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... Nie jestem jednak pewien, jak to wpłynie na istniejący wolumen.

  • Możesz skopiować plik po uruchomieniu kontenera. Aby to zrobić, skopiuj plik do kompilacji w lokalizacji, która nie znajduje się pod woluminem, a następnie wywołaj skrypt z punktu wejścia lub cmd, który skopiuje plik do właściwej lokalizacji i uruchomi postgres.

  • Sklonuj projekt za oficjalnym obrazem Postgres i edytuj plik Dockerfile, aby dodać własny plik konfiguracyjny przed zadeklarowaniem VOLUME (wszystko, co zostało dodane przed instrukcją VOLUME, jest automatycznie kopiowane w czasie wykonywania).

  • Przekaż wszystkie zmiany konfiguracji w opcji polecenia w pliku docker-compose

lubić:

services:
  postgres:
    ...  
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...
Adrian Mouat
źródło
3
To wszystko, zmiany nie powinny znajdować się w pliku Dockerfile. Przeniosłem je do skryptu i wywołałem go z punktu wejścia i teraz działało dobrze. Dziękuję za Twoją odpowiedź.
Sakr
5
Właśnie skopiowałem skrypt w folderze init „/docker-entrypoint-initdb.d/” i tym razem również działał dobrze. To dziwne, ale wygląda na to, że byłem tak skupiony na ustawianiu obrazu za pomocą pliku Dockerfile, jak robiłem to z większością obrazów, że przegapiłem coś przy moich pierwszych próbach użycia skryptu init.
Sakr
„Zasadniczo oznacza to, że nie możesz kopiować żadnych plików do tej ścieżki w obrazie; zmiany zostaną odrzucone”. Czy mógłbyś wyjaśnić, dlaczego tak jest?
isco
@isco wyszukuje tomy w oficjalnej dokumentacji. Zasadniczo woluminy nie są przechowywane w obrazie, ale na hoście, więc dane zostaną zapisane na hoście, a nie w obrazie. Aby zachować dane, musisz uruchomić kontener z tym samym woluminem.
Adrian Mouat
zmieniam w /var/lib/postgres/data/pg_hba.conf na akceptację tylko połączenie jest hostem wszystkie 192.168.0.0/0 md5 i komentarz host wszystkie wszystkie md5 (jest to ustawienie domyślne). Ale nie zmieniaj efektu
Lucas Resende
83

Z Docker Compose

Podczas pracy z Docker Compose możesz użyć command: postgres -c option=valuew swoim, docker-compose.ymlaby skonfigurować Postgres.

Na przykład, to sprawia, że ​​Postgres loguje się do pliku:

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

Dostosowując odpowiedź Vojtech Vitek , możesz użyć

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

aby zmienić plik konfiguracyjny, którego będzie używał Postgres. Zamontowałbyś swój niestandardowy plik konfiguracyjny z woluminem:

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

Oto docker-compose.ymlmoja aplikacja, pokazująca, jak skonfigurować 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:

Uprawnienie do zapisu w katalogu dziennika

Należy pamiętać, że w systemie Linux katalog dziennika na hoście musi mieć odpowiednie uprawnienia. W przeciwnym razie pojawi się nieco mylący błąd

KRYTYCZNY: nie można otworzyć pliku dziennika „/logs/postgresql-2017-02-04_115222.log”: Odmowa uprawnień

Mówię mylące, ponieważ komunikat o błędzie sugeruje, że katalog w kontenerze ma niewłaściwe uprawnienia, podczas gdy w rzeczywistości katalog na hoście nie pozwala na zapis.

Aby to naprawić, ustawiłem odpowiednie uprawnienia na hoście za pomocą

chgroup ./logs docker && chmod 770 ./logs
Matthias Braun
źródło
Czy poleciłbyś zrobienie dziennika postgres do pliku, zamiast stdout i używanie poleceń docker logs do radzenia sobie z tym? brawa za sieciowanie w kwestii github !
jpic
1
Nie jestem zdecydowany, czy lepiej jest logować się do pliku, czy używać dzienników Dockera, jpic.
Matthias Braun
dodałeś hasło, które prawdopodobnie będziesz chciał zamaskować tutaj
vidstige
3
@vidstige: Nie używam tego losowego ciągu jako hasła, służy on tylko do demonstracji.
Matthias Braun
1
@Gherman: Czy dodałeś to do swojego Dockerfile? Ponieważ nie powinieneś. Moja odpowiedź używa docker-compose.yml.
Matthias Braun
39

Wstrzyknij niestandardowy plik postgresql.conf do kontenera postgres Docker

Domyślny postgresql.confplik znajduje się w PGDATAdir ( /var/lib/postgresql/data), co komplikuje sprawę, szczególnie przy pierwszym uruchomieniu kontenera postgres, ponieważ docker-entrypoint.shopakowanie wywołuje initdbkrok PGDATAinicjalizacji katalogu .

Aby konsekwentnie dostosować konfigurację PostgreSQL w Dockerze, sugeruję użycie config_fileopcji postgres razem z woluminami Dockera w następujący sposób:

Produkcyjna baza danych (katalog PGDATA jako trwały wolumen)

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

Testowanie bazy danych (katalog PGDATA zostanie usunięty po 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

Debugowanie

  1. Usunąć -d opcję (odłącz opcję) z docker runpolecenia, aby bezpośrednio wyświetlić dzienniki serwera.
  2. Połącz się z serwerem postgres za pomocą klienta psql i zapytaj o konfigurację:

    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
źródło
30

Po uruchomieniu oficjalnego punktu wejścia (AKA po uruchomieniu pojemnik), uruchamia initdbsię $PGDATA( /var/lib/postgresql/datadomyślnie), a następnie przechowuje w tym katalogu te 2 pliki:

  • postgresql.conf z domyślnymi ustawieniami ręcznymi.
  • postgresql.auto.confz ustawieniami zastępowanymi automatycznie za pomocą ALTER SYSTEMpoleceń.

Punkt wejścia wykonuje również dowolne /docker-entrypoint-initdb.d/*.{sh,sql}pliki.

Wszystko to oznacza, że ​​możesz dostarczyć skrypt powłoki / SQL w tym folderze, który konfiguruje serwer do następnego rozruchu (który nastąpi natychmiast po inicjalizacji bazy danych lub następnym uruchomieniu kontenera).

Przykład:

conf.sql plik:

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

Dockerfile plik:

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

A następnie będziesz musiał wykonać conf.sqlręcznie w już istniejących bazach danych. Ponieważ konfiguracja jest przechowywana w woluminie, przetrwa ona przebudowę.


Inną alternatywą jest przekazywanie -cflagi tyle razy, ile chcesz:

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

W ten sposób nie musisz budować nowego obrazu i nie musisz martwić się o już istniejące lub nie bazy danych; wszystko będzie miało wpływ.

Yajo
źródło
2
Ten ostatni, przechodzący -c, jest moim ulubionym. Jest to tak czyste i proste do wygenerowania dla różnych środowisk.
epic_fil
10

Możesz umieścić swój niestandardowy postgresql.confplik w pliku tymczasowym wewnątrz kontenera i nadpisać domyślną konfigurację w czasie wykonywania.

Aby to zrobić :

  • Skopiuj swoje zamówienie postgresql.confwewnątrz kontenera
  • Skopiuj updateConfig.shplik w formacie/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

W czasie wykonywania kontener wykona skrypt wewnątrz /docker-entrypoint-initdb.d/i nadpisze domyślną konfigurację konfiguracją niestandardową.

alphayax
źródło
dlaczego „_” w drugim poleceniu kopiowania? nie powinno to być: /docker-entrypoint-initdb.d/updateConfig.sh?
Fernando Castilla Ospina
3
Dzieje się tak, ponieważ folder docker-entrypoint-initdb.d / wykonuje skrypty w kolejności alfabetycznej. I chcę zastosować ten skrypt przed innymi.
alphayax
tnx zapomniałem, że kopia zmieniła nazwę pliku, aby używać podkreślenia
Fernando Castilla Ospina
9

Przejrzałem wszystkie odpowiedzi i została inna opcja. Możesz zmienić swoją wartość CMD w pliku docker (nie jest to najlepsza, ale wciąż możliwa droga do osiągnięcia celu).

Zasadniczo musimy

  • Skopiuj plik konfiguracyjny do kontenera Dockera
  • Zastąp opcje startowe postgres

Przykład pliku 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"]

Chociaż myślę, że użycie command: postgres -c config_file=/etc/postgresql/postgresql.confw twoim docker-compose.ymlpliku zaproponowanego przez Matthiasa Brauna jest najlepszą opcją.

Dr Botwing
źródło
2

Wydaje się, że dość mało technicznym rozwiązaniem tego problemu jest zadeklarowanie usługi (używam roju na AWS i pliku yaml) z plikami bazy danych zamontowanymi na trwałym woluminie (tutaj AWS EFS, co jest oznaczone przez sterownik cloudstor: aws specyfikacja).

  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. Baza danych pojawi się po zainicjowaniu z domyślnymi ustawieniami obrazu.
  2. Edytujesz ustawienia conf wewnątrz kontenera, np. Jeśli chcesz zwiększyć maksymalną liczbę równoczesnych połączeń, które wymagają ponownego uruchomienia
  3. zatrzymaj działający kontener (lub zmniejsz usługę do zera, a następnie z powrotem do jednego)
  4. rój tworzy nowy kontener, który tym razem zbiera twoje utrwalone ustawienia konfiguracyjne i wesoło je stosuje.

Przyjemnym efektem ubocznym utrzymywania konfiguracji jest to, że utrzymuje się ona również w twoich bazach danych (lub było odwrotnie) ;-)

Eoan
źródło
2

Moje rozwiązanie jest dla kolegów, którzy muszą wprowadzić zmiany w konfiguracji przed uruchomieniem docker-entrypoint-initdb.d

Musiałem zmienić ustawienie `` shared_preload_libraries '', więc podczas pracy postgres ma już wstępnie załadowaną nową bibliotekę i kod w docker-entrypoint-initdb.d może z niej korzystać.

Więc właśnie załatałem plik postgresql.conf.sample w 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

Dzięki tej poprawce stało się możliwe dodanie rozszerzenia w pliku .sql w docker-entrypoint-initdb.d /:

CREATE EXTENSION pg_cron;
40min
źródło
1

To działa dla mnie:

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
źródło
Dlaczego to nie otrzymało żadnych głosów za? To najrozsądniejsza propozycja… Dziękuję.
Paflow
0

Używając docker compose, możesz zamontować wolumin za pomocą postgresql.auto.conf. Przykład:

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
Łysy
źródło
Nie powinieneś edytować, postgresql.auto.confponieważ został nadpisany. Użyj postgresql.confw tej samej lokalizacji.
Baschdl
0

Używałem również oficjalnego image ( FROM postgres) i mogłem zmienić konfigurację, wykonując następujące polecenia.

Pierwszą rzeczą jest zlokalizowanie pliku konfiguracyjnego PostgreSQL. Można to zrobić, wykonując to polecenie w uruchomionej bazie danych.

SHOW config_file;

W moim przypadku wraca /data/postgres/postgresql.conf .

Następnym krokiem jest ustalenie, jaki jest skrót twojego działającego kontenera dockera PostgreSQL.

docker ps -a

Powinno to zwrócić listę wszystkich uruchomionych kontenerów. W moim przypadku wygląda to tak.

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

Teraz musisz przejść do bash w swoim kontenerze, wykonując:

docker exec -it 0ba35e5427d9 /bin/bash

Wewnątrz kontenera sprawdź, czy konfiguracja znajduje się we właściwej ścieżce i wyświetl ją.

cat /data/postgres/postgresql.conf

Chciałem zmienić maksymalne połączenia ze 100 na 1000 i współdzielony bufor ze 128 MB na 3 GB. Za pomocą polecenia sed mogę przeprowadzić wyszukiwanie i zastąpić odpowiednimi zmiennymi w pliku 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

Ostatnią rzeczą, jaką musimy zrobić, jest ponowne uruchomienie bazy danych w kontenerze. Dowiedz się, której wersji PostGres używasz.

cd /usr/lib/postgresql/
ls 

W moim przypadku 12 możesz więc teraz zrestartować bazę danych, wykonując następujące polecenie z poprawną wersją.

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"
Sebastian
źródło