Postgres y Postgis con Docker

De ChuWiki
Saltar a: navegación, buscar

Una forma rápida de tener una base de datos, digamos Postgres, es lanzarla con Docker. Veamos cómo.

Imagen de Postgres

Aquí tenemos la imagen oficial de Postgres en Docker. Desde nuestra consola de comandos, sin complicarnos la vida, sólo tenemos que arrancarla con

sudo docker run postgres

y se arranca, con todo por defecto, que no es la forma más adecuada. Ahora, desde otra ventana de comandos, podemos entrar en la base de datos para hacer "cosas"

chuidiang@javier-linux:~$ sudo docker ps
[sudo] password for chuidiang: 
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
e488def7aab4        postgres            "docker-entrypoint..."   About a minute ago   Up About a minute   5432/tcp            sharp_wiles

chuidiang@javier-linux:~$ sudo docker exec -it sharp_wiles bash

root@e488def7aab4:/# psql -U postgres
psql (10.3 (Debian 10.3-1.pgdg90+1))
Type "help" for help.

postgres=# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
   
-----------+----------+----------+------------+------------+--------------------
---
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres        
  +
           |          |          |            |            | postgres=CTc/postgr
es
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres        
  +
           |          |          |            |            | postgres=CTc/postgr
es
(3 rows)

postgres=# \q
root@e488def7aab4:/# exit
exit
chuidiang@javier-linux:~$ 

Hemos hecho un docker ps para saber el nombre de nuestro contenedor en ejecución, sharp_wiles en nuestro ejemplo. Luego con un docker exec arrancamos un bash contra esa máquina. Una vez dentro, un comando psql -U postgres nos conecta a la base de datos con el usuario postgres, que el que se crea por defecto. Una vez dentro, podemos trabajar con esa base de datos.

Sin embargo, la imagen de postgres tiene bastantes temas de configuración que deberíamos tocar. Veamos sólo un par de los más evidentes

Configurar imagen postgres

El comando más completo con algunas de las cosas más interesantes es el siguiente

sudo docker run -v/home/chuidiang/data:/var/lib/postgresql/data -e POSTGRES_USER=pepe -e POSTGRES_PASSWORD=juan -e POSTGRES_DB=prueba postgres

Veamos las opciones

  • -v/home/chuidiang/data:/var/lib/postgresql/data es para que monte un directorio del host anfitrión (/home/chuidiang/data) dentro del directorio /var/lib/postgresql/data del contenedor. Este directorio es donde postgresql guarda los datos, así que de esta forma tendremos los datos en un directorio de nuestro ordenador y no dentro del contenedor. Esto facilita hacer backups y hace que el contenedor no crezca según vamos metiendo datos en la base de datos.
  • -e POSTGRES_USER=pepe es una variable de entorno que postgres interpreta y hace que ese sea el usuario de la base de datos, en vez de el usuario por defecto postgres.
  • -e POSTGRES_PASSWORD=juan es para poner una password al usuario anterior
  • -e POSTGRES_DB=prueba es para que nos cree una base de datos prueba dentro de postgres.

Con esto tenemos nuestro contenedor de base de datos un poco más configurado.

Si entramos con un bash en el mismo contenedor de la base de datos, no veremos gran cosa, puesto que por defecto está configurado para que desde localhost se pueda acceder sin password. Arrancamos otra imagen de postgres pero solo para tener el comando psql accesible. Ahí podemos probar esto

root@791d84705258:/# psql --host 172.17.0.2 -U pepe prueba
Password for user pepe: 
psql (10.3 (Debian 10.3-1.pgdg90+1))
Type "help" for help.

prueba=# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
   
-----------+----------+----------+------------+------------+--------------------
---
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 prueba    | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres        
  +
           |          |          |            |            | postgres=CTc/postgr
es
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres        
  +
           |          |          |            |            | postgres=CTc/postgr
es
(4 rows)

Con psql --host 172.17.0.2 -U pepe prueba nos conectamos al primer contenedor (ip 172.17.0.2), con el usuario pepe a la base de datos prueba. Nos pide la password y metemos juan. Una vez dentro, el comando \l nos muestra las bases de datos y vemos que tenemos creada la base de datos prueba.

Crear tablas en el arranque

La imagen oficial de postgres para docker viene preparada para que podamos crear las tablas que queramos en el primer arranque. Para ello, debemos crearnos un docker extendiendo de esta imagen oficial. El fichero Dockerfile puede ser como este

FROM postgres

COPY docker-entrypoint-initdb.d /docker-entrypoint-initdb.d
RUN chmod +r /docker-entrypoint-initdb.d/*

Junto al fichero Dockerfile creamos una carpeta (le he puesto nombre docker-entrypoint-initdb.d) y dentro he puesto un fichero de extensión sql con el siguiente contenido

CREATE TABLE distributors (
     did    integer PRIMARY KEY,
     name   varchar(40) NOT NULL CHECK (name <> '')
);

Este fichero, en el Dockerfile, indicamos que lo copie dentro de la imagen en la carpeta /docker-entrypoint-initdb.d . La imagen de Docker ejecuta, por orden alfabético, todos los ficheros .sh y .sql que haya ahí dentro.

Si el fichero es de extensión .sql, lo ejecuta como un script de sql en la base de datos creada con la variable POSTGRES_DB, usando el usuario definido en la variable POSTGRES_USER.

Si el fichero es de extensión .sh, lo ejecuta como un script normal.

En el fichero Dockerfile, después de hacer la copia, le damos permisos de lectura, puesto que este fichero se ejecutará con el usuario correspondiente de la imagen y tenemos que asegurarnos de que se puede leer. Si fuera un .sh, habría incluso que darle permisos de ejecución.

Es importante lo que hemos comentado antes, se ejecutan "en orden alfabético". Si ponemos varios y el orden en que se ejecutan es importante, debemos asegurarnos de que pongamos los nombres de los ficheros de forma que su orden alfabético sea también el de ejecución.

Ahora construimos nuestra imagen. Nos situamos en el directorio donde está el fichero Dockerfile y el subdirectorio y ejecutamos

sudo docker build -tmipostgrescontablas .

donde la opción -tmipostgrescontablas es para darle a nuestra imagen un nombre mipostgrescontablas

Una vez hecho esto, arrancamos la máquina docker por primera vez con el comando run y toda la paramétrica que queramos. Suele ser intersante darle un nombre que nos diga algo a la máquina que estamos arrancando. Y también debemos asegurarnos que en este primer arranque ponemos todos los parámetros que queramos bien, puesto que en los siguientes arranques no se ponen los parámetros otra vez, los recuerda de la vez anterior. Puede ser algo como esto

sudo docker run -v/home/chuidiang/data:/var/lib/postgresql/data -e POSTGRES_USER=pepe -e POSTGRES_PASSWORD=juan -e POSTGRES_DB=prueba --name MyDataBase mipostgrescontablas

Es igual que el que hemos usado antes, pero añadido la opción --name MyDataBase, que es el nombre que queremos dar a la máquina. Y listo, a partir de ahora, para que no recree cada vez las tablas y borre los datos que hayamos insertado, debemos acordarnos de pararla y arrancarla con stop y start

sudo docker stop MyDataBase
sudo docker start MyDataBase

Postgis

No hay una imagen oficial de Postigs, pero la más usada es esta https://hub.docker.com/r/mdillon/postgis/

Esta imagen extiende la oficial de Postgres, añadiendo Postgis. En el directorio /docker-entrypoint-initdb.d tiene un script postgis.sh que se encarga de:

  • Crea una base de datos template_postgis con la extensión Postgis
  • Si existe la variable POSTGRES_DB, crea también la extensión Postgis en esa base de datos.

Aquí es donde es importante el orden alfabético de los scripts. Si en la base de datos que indica la variable POSTGRES_DB queremos crear nuestras tablas como vimos antes y esas tablas usan columnas Geometry o usa cualquier otra cosa propia de postgis, nuestro script debe ejecutarse DESPUËS del postgis.sh, así que el nombre de nuestro script debe ser alfabéticamente posterior a postgis.sh

Así que el procedimiento es el mismo. Un fichero Dockerfile igual al anterior, pero que parte de la imagen de postgis

FROM mdillon/postgis

COPY docker-entrypoint-initdb.d /docker-entrypoint-initdb.d
RUN chmod +r /docker-entrypoint-initdb.d/*

Dentro del directorio docker-entrypoint-initdb.d ponemos un fichero para crear las tablas y nombre z-init.sql por aquello de asegurarnos que va por detrás alfabéticamente de postgis.sh y cuyo contenido puede ser

CREATE TABLE distributors (
     did    integer PRIMARY KEY,
     name   varchar(40) NOT NULL CHECK (name <> ''),
     theGeometry Geometry
);

Es igual que el anterior, pero hemos añadido una columna de tipo Geometry propia de postgis. Construimos la imagen

sudo docker build -tmypostgis .

y la arrancamos por primera vez con run

sudo docker run -v$(pwd)/data:/var/lib/postgresql/data -e POSTGRES_USER=pepe -e POSTGRES_PASSWORD=juan -e POSTGRES_DB=prueba --name MyPostgisConTablas mypostgis

y a partir de ahora, las siguientes veces

sudo docker stop MyPostgisConTablas
sudo docker start MyPostgisConTablas