Conteinerização de PostgreSQL com Docker
18/10/2014Este post é uma continuação da saga sobre Docker ;) Se você ainda não leu os posts anteriores:
Gerando a imagem
Assumindo que você já deu uma olhada nos outros posts e entende o básico sobre como trabalhar com o Docker vamos ao que interessa, o primeiro passo aqui será construir nossa imagem Docker para trabalhar com o PostgreSQL, vamos analisar o Dockerfile:
FROM ubuntu:trusty
RUN locale-gen en_US.UTF-8
RUN update-locale LANG=en_US.UTF-8
RUN apt-key adv --keyserver keyserver.ubuntu.com \
--recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive \
apt-get install -y -q postgresql-9.3 postgresql-contrib-9.3 \
libpq-dev python-software-properties software-properties-common \
postgresql-client-9.3
ADD postgresql.conf /etc/postgresql/9.3/main/postgresql.conf
ADD pg_hba.conf /etc/postgresql/9.3/main/pg_hba.conf
RUN chown -R postgres:postgres /etc/postgresql/9.3/main/
ADD run /usr/local/bin/run
RUN chmod +x /usr/local/bin/run
VOLUME ["/var/lib/postgresql"]
EXPOSE 5432
CMD ["/usr/local/bin/run"]
A novidade aqui é o VOLUME
que é um recurso do Docker para especificar
um diretório que pode ser persistido ou compartilhado dentro do container.
As alterações em um volume não serão persistidas quando você fizer atualizações
em uma imagem, veremos mais adiante detalhes de como trabalhar com volumes.
Para gerar a imagem estou informando no Dockerfile que ele deve copiar alguns arquivos de configuração do Postgresql durante a instalação. Vamos conferir o script de inicialização do postgres:
#!/bin/bash
set -e
POSTGRESQL_USER=${POSTGRESQL_USER:-"docker"}
POSTGRESQL_PASS=${POSTGRESQL_PASS:-"docker"}
POSTGRESQL_DB=${POSTGRESQL_DB:-"docker"}
POSTGRESQL_TEMPLATE=${POSTGRESQL_TEMPLATE:-"DEFAULT"}
POSTGRESQL_BIN=/usr/lib/postgresql/9.3/bin/postgres
POSTGRESQL_CONFIG_FILE=/etc/postgresql/9.3/main/postgresql.conf
POSTGRESQL_DATA=/var/lib/postgresql/9.3/main
POSTGRESQL_SINGLE="sudo -u postgres $POSTGRESQL_BIN --single \
--config-file=$POSTGRESQL_CONFIG_FILE"
if [ ! -d $POSTGRESQL_DATA ]; then
mkdir -p $POSTGRESQL_DATA
chown -R postgres:postgres $POSTGRESQL_DATA
sudo -u postgres /usr/lib/postgresql/9.3/bin/initdb \
-D $POSTGRESQL_DATA -E 'UTF-8'
fi
$POSTGRESQL_SINGLE <<< "CREATE USER $POSTGRESQL_USER WITH SUPERUSER;" \
> /dev/null
$POSTGRESQL_SINGLE <<< "ALTER USER $POSTGRESQL_USER WITH PASSWORD
'$POSTGRESQL_PASS';" > /dev/null
$POSTGRESQL_SINGLE <<< "CREATE DATABASE $POSTGRESQL_DB OWNER
$POSTGRESQL_USER TEMPLATE
$POSTGRESQL_TEMPLATE;" > /dev/null
exec sudo -u postgres $POSTGRESQL_BIN \
--config-file=$POSTGRESQL_CONFIG_FILE
No script temos algumas variáveis ambiente para criar um banco, usuário e
senha default, caso essas informações não sejam passadas na criação do
container, então POSTGRESQL_DB
cria um banco de dados automaticamente
caso não exista, POSTGRESQL_USER
cria um usuário com acesso ao banco
especificado em POSTGRESQL_DB
e em POSTGRESQL_PASS
teremos a senha
para este usuário. Todos recebem o nome docker por padrão.
Criando a imagem utilizando o Dockerfile:
$ docker build -t ex_postgresql .
Criando e acessando o container
Agora que a imagem foi gerada, podemos criar o nosso container e acessar o PostgreSQL pelo host:
$ docker run -d -p 5432:5432 \
-e POSTGRESQL_USER=test \
-e POSTGRESQL_PASS=test123 \
-e POSTGRESQL_DB=test \
ex_postgresql
Durante a criação do container estou passando valores as variáveis do script de inicialização, agora poderei ter acesso ao postgres que está em execução no container partindo do host:
$ psql -h localhost -U test test
Password for user test:
psql (9.3.3, server 9.3.5)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
test=#
Claro que o acesso pode ser feito utilizando o ip privado do container, neste caso:
$ docker ps -q
1b8f91a297a8
$ docker inspect 1b8f91a297a8 | grep IPAddress
"IPAddress": "172.17.0.9"
$ psql -h 172.17.0.9 -U test test
Password for user test:
psql (9.3.3, server 9.3.5)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
test=#
No post sobre gerar uma imagem docker para um projeto rails, eu havia
criado um container para executar a aplicação, agora podemos fazer uma
pequena integração entre os containers, neste caso basta alterar o database.yml
do projeto e passar o ip do nosso container postgres:
production:
adapter: postgresql
encoding: unicode
pool: 5
username: test
password: test123
host: 172.17.0.9
port: 5432
database: test
Além dos containers manterem uma comunicação entre si, estão liberando
acesso pelas portas definidas na criação, no caso a 80
no container onde
a aplicação existe e a 5432
no container do postgresql.
Manipulando volumes
Durante a criação do container o volume /var/lib/postgresql
foi exposto,
isso significa que os dados do postgresql serão persistidos nesse diretório
dentro do container, podemos ter acesso a esses dados utilizando a opção
--volumes-from
:
$ docker run -d --volumes-from 340c8f4450a0 --name db-test ex_postgresql
Desta forma estaremos criando um novo container mapeando o acesso ao volume do container onde o postgresql está rodando, podemos verificar se os arquivos realmente estão sendo persistidos no novo container:
$ docker run -it --volumes-from 340c8f4450a0 \
--name db-test ex_postgresql /bin/bash
root@4a691f90f11a:/# ll /var/lib/postgresql/9.3/main/
total 68
drwx------ 15 postgres postgres 4096 Oct 18 15:48 ./
drwxr-xr-x 3 postgres postgres 4096 Oct 18 13:37 ../
-rw------- 1 postgres postgres 4 Oct 18 13:37 PG_VERSION
drwx------ 7 postgres postgres 4096 Oct 18 15:48 base/
drwx------ 2 postgres postgres 4096 Oct 18 15:49 global/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_clog/
drwx------ 4 postgres postgres 4096 Oct 18 13:37 pg_multixact/
drwx------ 2 postgres postgres 4096 Oct 18 15:48 pg_notify/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_serial/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_snapshots/
drwx------ 2 postgres postgres 4096 Oct 18 15:48 pg_stat/
drwx------ 2 postgres postgres 4096 Oct 18 15:52 pg_stat_tmp/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_subtrans/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_tblspc/
drwx------ 2 postgres postgres 4096 Oct 18 13:37 pg_twophase/
drwx------ 3 postgres postgres 4096 Oct 18 13:37 pg_xlog/
-rw------- 1 postgres postgres 94 Oct 18 15:48 postmaster.opts
root@4a691f90f11a:/#
Agora que temos acesso ao volume do container postgresql, podemos trabalhar com backups:
$ docker run --volumes-from 340c8f4450a0 -v $(pwd):/backup ex_postgresql \
tar cvf /backup/backup.tar /var/lib/postgresql
Com isso estamos criando um novo container que terá acesso ao volume do
postgresql e executará uma instrução copiando os arquivos para o diretório
/backup
, em seguida irá compactar no formato tar
e por último o arquivo
backup.tar
será disponibilizado no host.
Para executar um restore do backup feito em um novo container, podemos
primeiro criar um novo container com base na imagem do postgresql,
opcionalmente, podemos informar o novo volume com -v
:
$ docker run -v /var/lib/postgresql --name test2 ex_postgresql /bin/bash
Em seguida podemos restaurar o backup no container test2
que foi criado:
$ docker run --volumes-from test2 -v $(pwd):/backup busybox \
tar xvf /backup/backup.tar
Se preferir confira o projeto docker-backup para automatizar esse processo.
Finalizando
Continuarei explorando o Docker tanto no ambiente de desenvolvimento quanto em produção, em futuros posts trarei mais novidades.
Estou disponibilizando o Dockerfile criado neste post aqui: https://github.com/infoslack/docker-postgresql
Happy Hacking ;)