Como personalizar o arquivo de configuração da imagem oficial do PostgreSQL Docker?

102

Estou usando a imagem oficial do Postgres Docker tentando personalizar sua configuração. Para isso, utilizo o comando sedpara alterar, max_connectionspor exemplo:

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

Tentei dois métodos para aplicar esta configuração. A primeira é adicionando os comandos a um script e copiando-o dentro da pasta init "/docker-entrypoint-initdb.d". O segundo método é executá-los diretamente em meu Dockerfile com o comando "RUN" (esse método funcionou bem com uma imagem Postgresql não oficial com um caminho diferente para o arquivo de configuração "/ etc / postgres / ..."). Em ambos os casos as alterações falham porque o arquivo de configuração está faltando (acho que ainda não foi criado).

Como devo alterar a configuração?

Editar 1:

Aqui está o Dockerfile usado para criar a imagem:

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

Com este Dockerfile, o processo de compilação mostra o erro: sed: can't read /var/lib/postgresql/data/postgresql.conf: No such file or directory

Sakr
fonte
1
um método é usar a imagem oficial, iniciá-la, conectá-la internamente com, em docker exec -it container_id bashseguida, fazer suas modificações e, em seguida, docker commit container_id myuser/myimage_myPostegresql:myversionconsulte o documento docs.docker.com/reference/commandline/cli/#commit
user2915097 de
2
Acho que uma das vantagens do paradigma docker é automatizar todo o processo de construção. Conforme mencionado em outra imagem, paintedfox/postgresqlé possível alterar a configuração diretamente no Dockerfile. Acho que isso também deveria ser possível com a imagem oficial.
Sakr
o método sed deve funcionar, você pode postar seu Dcokerfile ou um reprodutor completo?
user2915097

Respostas:

54

A postgres:9.4imagem da qual você herdou declara um volume em /var/lib/postgresql/data. Isso significa essencialmente que você não pode copiar nenhum arquivo para esse caminho na imagem; as alterações serão descartadas.

Você tem poucas escolhas:

  • Você pode simplesmente adicionar seus próprios arquivos de configuração como um volume em tempo de execução com docker run -v postgresql.conf:/var/lib/postgresql/data/postgresql.conf .... No entanto, não tenho certeza de como isso irá interagir com o volume existente.

  • Você pode copiar o arquivo quando o contêiner for iniciado. Para fazer isso, copie seu arquivo para o build em um local que não esteja abaixo do volume e, em seguida, chame um script do entrypoint ou cmd que copiará o arquivo para corrigir o local e iniciará o postgres.

  • Clone o projeto por trás da imagem oficial do Postgres e edite o Dockerfile para adicionar seu próprio arquivo de configuração antes que o VOLUME seja declarado (qualquer coisa adicionada antes da instrução VOLUME é automaticamente copiada no tempo de execução).

  • Passe todas as mudanças de configuração na opção de comando no arquivo docker-compose

gostar:

services:
  postgres:
    ...  
    command:
      - "postgres"
      - "-c"
      - "max_connections=1000"
      - "-c"
      - "shared_buffers=3GB"
      - "-c"
      ...
Adrian Mouat
fonte
3
Era isso, as alterações não deveriam estar dentro do Dockerfile. Mudei-os para um script e chamei-o do ponto de entrada e funcionou bem agora. Obrigado pela resposta.
Sakr de
5
Acabei de copiar o script dentro da pasta init "/docker-entrypoint-initdb.d/" e também funcionou bem desta vez. Isso é estranho, mas parece que estava tão focado em definir a imagem com o Dockerfile, como estou acostumado a fazer com a maioria das imagens, que perdi algo nas minhas primeiras tentativas de usar o script de inicialização.
Sakr de
"Basicamente, isso significa que você não pode copiar nenhum arquivo para esse caminho na imagem; as alterações serão descartadas." Você poderia explicar por que é esse o caso?
isco
@isco procure vários volumes na documentação oficial. Basicamente, os volumes não são armazenados na imagem, mas no host, portanto, os dados serão salvos no host, não na imagem. Você precisaria iniciar o contêiner com o mesmo volume anexado para manter os dados.
Adrian Mouat,
eu mudo em /var/lib/postgres/data/pg_hba.conf para aceitar apenas a conexão é host all all 192.168.0.0/0 md5 e host de comentário all all all md5 (é o padrão). Mas não mude o efeito
Lucas Resende
83

Com Docker Compose

Ao trabalhar com o Docker Compose, você pode usar command: postgres -c option=valueem seu docker-compose.ymlpara configurar o Postgres.

Por exemplo, isso faz com que o Postgres registre em um arquivo:

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

Adaptando a resposta da Vojtech Vitek , você pode usar

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

para alterar o arquivo de configuração que o Postgres usará. Você montaria seu arquivo de configuração personalizado com um volume:

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

Aqui está o docker-compose.ymldo meu aplicativo, mostrando como configurar o 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:

Permissão para escrever no diretório de log

Observe que, no Linux, o diretório de log no host deve ter as permissões corretas. Caso contrário, você obterá o erro um pouco enganador

FATAL: não foi possível abrir o arquivo de log "/logs/postgresql-2017-02-04_115222.log": permissão negada

Digo enganoso, pois a mensagem de erro sugere que o diretório no contêiner tem a permissão errada, quando na realidade o diretório no host não permite a gravação.

Para corrigir isso, defino as permissões corretas no host usando

chgroup ./logs docker && chmod 770 ./logs
Matthias Braun
fonte
Você recomendaria fazer o log do postgres em um arquivo, em vez de stdout e usar comandos docker logs para lidar com isso? parabéns pelo crosslinking na questão do github !
jpic
1
Não estou decidido se logar em arquivo ou usar logs do Docker é preferível, jpic.
Matthias Braun
você adicionou a senha, que provavelmente vai querer mascarar aqui
vidstige
3
@vidstige: Não uso essa string aleatória como senha, é apenas para demonstração.
Matthias Braun
1
@Gherman: Você adicionou isso ao seu Dockerfile? Porque você não deveria. Minha resposta usa docker-compose.yml.
Matthias Braun
39

Injetar postgresql.conf personalizado no contêiner Docker do postgres

O postgresql.confarquivo padrão fica dentro de PGDATAdir ( /var/lib/postgresql/data), o que torna as coisas mais complicadas, especialmente ao executar o contêiner postgres pela primeira vez, já que o docker-entrypoint.shwrapper invoca a initdbetapa de PGDATAinicialização do dir.

Para personalizar a configuração do PostgreSQL no Docker de forma consistente, sugiro usar a config_fileopção postgres junto com os volumes do Docker como este:

Banco de dados de produção (diretório PGDATA como volume 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

Banco de dados de teste (diretório PGDATA será descartado depois 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

Depurando

  1. Remova -d(opção de desanexar) do docker runcomando para ver os logs do servidor diretamente.
  2. Conecte-se ao servidor postgres com o cliente psql e consulte a configuração:

    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
fonte
30

Quando você executar o ponto de entrada oficial (AKA quando você iniciar o container), ele é executado initdbem $PGDATA( /var/lib/postgresql/datapor padrão), e, em seguida, ele armazena no diretório estes 2 arquivos:

  • postgresql.conf com configurações manuais padrão.
  • postgresql.auto.confcom as configurações substituídas automaticamente com ALTER SYSTEMcomandos.

O entrypoint também executa quaisquer /docker-entrypoint-initdb.d/*.{sh,sql}arquivos.

Tudo isso significa que você pode fornecer um script shell / SQL nessa pasta que configura o servidor para a próxima inicialização (que será imediatamente após a inicialização do banco de dados ou nas próximas vezes que você inicializar o contêiner).

Exemplo:

conf.sql Arquivo:

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

Dockerfile Arquivo:

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

E então você terá que executar conf.sqlmanualmente em bancos de dados já existentes. Como a configuração é armazenada no volume, ela sobreviverá às reconstruções.


Outra alternativa é passar a -cbandeira quantas vezes desejar:

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

Dessa forma, você não precisa construir uma nova imagem e não precisa se preocupar com bancos de dados já existentes ou não; todos serão afetados.

Yajo
fonte
2
Este último, passando -c, é meu favorito. Isso é tão limpo e simples de gerar para diferentes ambientes.
epic_fil
10

Você pode colocar seu personalizado postgresql.confem um arquivo temporário dentro do contêiner e sobrescrever a configuração padrão em tempo de execução.

Fazer isso :

  • Copie seu personalizado postgresql.confdentro de seu contêiner
  • Copie o updateConfig.sharquivo em/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

No tempo de execução, o contêiner executará o script interno /docker-entrypoint-initdb.d/e sobrescreverá a configuração padrão com sua configuração personalizada.

alphayax
fonte
por que o "_" no segundo comando de cópia? não deveria ser /docker-entrypoint-initdb.d/updateConfig.sh:?
Fernando Castilla Ospina
3
É porque a pasta docker-entrypoint-initdb.d / executa scripts em ordem alfabética. E quero aplicar esse script antes dos outros.
alphayax de
tnx esqueci que a cópia renomeou o arquivo para usar o sublinhado
Fernando Castilla Ospina
9

Verifiquei todas as respostas e ainda há outra opção. Você pode alterar seu valor CMD no arquivo docker (não é o melhor, mas ainda é a maneira possível de atingir seu objetivo).

Basicamente, precisamos

  • Copie o arquivo de configuração no contêiner do docker
  • Substituir opções de início do postgres

Exemplo de arquivo 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"]

Embora eu ache que usar command: postgres -c config_file=/etc/postgresql/postgresql.confem seu docker-compose.ymlarquivo proposto por Matthias Braun seja a melhor opção.

Dr. Botwing
fonte
2

Uma solução bastante de baixa tecnologia para este problema parece ser declarar o serviço (estou usando swarm no AWS e um arquivo yaml) com seus arquivos de banco de dados montados em um volume persistente (aqui AWS EFS conforme indicado pelo cloudstor: driver aws especificação).

  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. O db é inicializado com as configurações padrão da imagem.
  2. Você edita as configurações de configuração dentro do contêiner, por exemplo, se deseja aumentar o número máximo de conexões simultâneas que requerem uma reinicialização
  3. pare o contêiner em execução (ou reduza o serviço a zero e depois volte a um)
  4. o enxame gera um novo contêiner, que desta vez pega suas configurações persistentes e as aplica alegremente.

Um efeito colateral agradável de persistir sua configuração é que também persiste seus bancos de dados (ou era o contrário) ;-)

Eoan
fonte
2

Minha solução é para colegas que precisam fazer alterações na configuração antes de iniciar docker-entrypoint-initdb.d

Fui necessário alterar a configuração de 'shared_preload_libraries' para que durante seu trabalho o postgres já tenha uma nova biblioteca pré-carregada e o código em docker-entrypoint-initdb.d possa usá-la.

Então, acabei de corrigir o arquivo postgresql.conf.sample no 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 com este patch tornou-se possível adicionar extensão no arquivo .sql em docker-entrypoint-initdb.d /:

CREATE EXTENSION pg_cron;
40min
fonte
1

Isso funciona para mim:

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
fonte
Por que isso não recebeu nenhum voto positivo? É a proposição mais sensata aqui ... Obrigado.
Paflow
0

Usando o docker compose, você pode montar um volume com postgresql.auto.conf. Exemplo:

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
Careca
fonte
Você não deve editar o postgresql.auto.confcomo ele é sobrescrito. Use postgresql.confno mesmo local.
Baschdl
0

Eu também estava usando a imagem oficial ( FROM postgres) e consegui mudar a configuração executando os seguintes comandos.

A primeira coisa é localizar o arquivo de configuração do PostgreSQL. Isso pode ser feito executando este comando no banco de dados em execução.

SHOW config_file;

Eu meu caso ele retorna /data/postgres/postgresql.conf.

A próxima etapa é descobrir qual é o hash do contêiner docker do PostgreSQL em execução.

docker ps -a

Isso deve retornar uma lista de todos os contêineres em execução. No meu caso é assim.

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

Agora você precisa alternar para o bash dentro de seu contêiner executando:

docker exec -it 0ba35e5427d9 /bin/bash

Dentro do contêiner, verifique se a configuração está no caminho correto e exiba-o.

cat /data/postgres/postgresql.conf

Eu queria alterar as conexões máximas de 100 para 1000 e o buffer compartilhado de 128 MB para 3 GB. Com o comando sed posso fazer uma pesquisa e substituir pelas variáveis ​​correspondentes na configuração.

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

A última coisa que precisamos fazer é reiniciar o banco de dados dentro do contêiner. Descubra qual versão de PostGres você está usando.

cd /usr/lib/postgresql/
ls 

No meu caso, é 12 Portanto, agora você pode reiniciar o banco de dados executando o seguinte comando com a versão correta.

su - postgres -c "PGDATA=$PGDATA /usr/lib/postgresql/12/bin/pg_ctl -w restart"
Sebastian
fonte