En el primer post que escribí sobre Docker, expuse los conceptos básicos, definiciones, algunas de las empresas que lo usan, y por qué nosotros deberíamos usarlo también en nuestros proyectos. Pero lo que no toqué en el anterior post fue cómo usar Docker en sí, los comandos básicos y todo lo referente al mismo. Éste es el principal objetivo de esta segunda entrega, así que espero que la disfruten.

Lo primero es lo primero: Instalación de Docker

Mi sistema es Ubuntu Gnome 14.10, por lo que la instalación se puede hacer a través del Centro de Software o desde la consola:
apt-get install docker.io

En el repositorio, la versión que tenemos disponible es la 1.2, aunque ya la 1.3 salió oficialmente, con muchas mejoras, pero eso es tema para otro post.

Comandos básicos

Siempre me gusta, cuando instalo un nuevo comando en mi sistema leer su documentación básica, buscando sus páginas del man, y Docker no es la excepción, debido a que su página del man está increíble porque de forma concisa y rápida, explica las principales opciones que tienes al usar la plataforma.

Ahora expondré algunos de los usados por Docker:

docker info

Resultado:

Containers: 0
Images: 0
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Dirs: 0
Execution Driver: native-0.2
Kernel Version: 3.16.0-26-generic
Operating System: Ubuntu 14.10
WARNING: No swap limit support

Este comando como puede apreciar es el que te permite ver cuántos contenedores tienes en tu sistema, cuantes imágenes, la dirección que estás usando para el almacenamiento de los contenedores, el sistema operativo y versión del kernel.

docker pull ubuntu

Este comando se usa para la descarga de imágenes públicas de Docker desde el Docker Hub, hosteado por la empresa. En este caso, queremos descargar la imagen de Ubuntu, la cual usaremos de forma básica para dockerizar nuestras aplicaciones. Esto es para los que pueden descargar libremente de Internet. Para los que no podemos descargar de Internet de esa forma, lo que haré entonces más adelante, será crear una imagen básica usando Ubuntu como base para poder usarla para las aplicaciones.

docker run -i -t ubuntu /bin/bash

Éste es uno de los comandos principales de Docker, en el cual le estamos diciendo al mismo que ejecute una shell interactiva en la imagen ubuntu. Así básicamente, es como Docker ejecuta procesos dentro de las imágenes.

docker -H 0.0.0.0:5555 -d

Aquí le estamos diciendo a docker que se ejecute como demonio escuchando por el puerto 5555. Por defecto, docker se ejecuta como un socker de Unix (específicamente en unix:///var/run/docker.sock) por lo cual permite sólo conexiones a nivel local como root, lo cual es la práctica recomendada por el hecho de que pudiera ser trivial que alguien podría tener acceso de root donde el demonio se estuviera ejecutando.

docker ps

Aquí le estamos diciendo a docker que liste sólo los contenedores que están ejecutándose. Si se quiere listar todos los contenedores que están en el host, entonces se debe usar:

docker ps -a

Creando una imagen básica de Ubuntu

Para la creación de imágenes, como dice la documentación, depende mucho de la distribución de Linux que estés usando, y por el hecho de que estoy usando Ubuntu Gnome 14.10, entonces me centraré en una imagen básica de Ubuntu. Para ello usaré, la herramienta Debootstrap (no viene por defecto en Ubuntu, por lo que hay que instalarla) de la siguiente forma:

sudo debootstrap utopic utopic http://ubuntu.uci.cu/ubuntu

Esto quiere decir que se hará una imagen base de Ubuntu Utopic Unicorn con el nombre “utopic” a partir del mirror de acá de la UCI. Siempre hay que especificarle el mirror, porque de ahí es donde se descargarán los paquetes para formar la imagen básica. Este proceso demora alrededor de unos 10 minutos, en dependencia de su sistema. El resultado que debe arrojar es algo como esto:

: Configuring libgnutls-openssl27:i386...
I: Configuring iputils-ping...
I: Configuring apt-utils...
I: Configuring ureadahead...
I: Configuring logrotate...
I: Configuring dh-python...
I: Configuring python3...
I: Configuring lsb-release...
I: Configuring console-setup...
I: Configuring dmsetup...
I: Configuring eject...
I: Configuring ureadahead...
I: Configuring kbd...
I: Configuring ubuntu-minimal...
I: Configuring libc-bin...
I: Configuring initramfs-tools...
I: Base system installed successfully.

Luego se ejecuta:

sudo tar -C utopic -c . | sudo docker import - utopic

Acá lo que se hace es comprimir con tar la imagen que se generó con debootstrap, y luego se le pasa a docker import, que lo hace es crear una imagen con el sistema de archivos vacío e importa el contenido del tarball hacia ella.

Luego ya se puede ejecutar un comando en la imagen recién creada:

sudo docker run utopic cat /etc/lsb-release

que debe arrojar algo como esto:

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.10
DISTRIB_CODENAME=utopic
DISTRIB_DESCRIPTION="Ubuntu 14.10"

Dockerizando PostgreSQL

Ahora para hacer algo más real, me apoyaré en el ejemplo que viene en la documentación oficial de “dockerizar” PostgreSQL, creando una imagen para el mismo usando como base la que ya creamos, pero en vez de usar el método que ya vimos arriba, ahora crearemos un Dockerfile para ello. Tengan en cuenta que esto es sólo para aprender, por el hecho de que en el Docker Hub hay una gran cantidad de Dockefiles preparados para ser descargados y usados al instante. Ahora el archivo se define como sigue:


#
# El ejemplo fue descargado de http://docs.docker.com/examples/postgresql_service/
#
# Usando la imagen que ya creamos como base
FROM utopic
MAINTAINER mlortiz@uci.cu

# Luego se agrega el repositorio de aca de la UCI para poder instalar PostgreSQL ``9.3``.
RUN echo "deb http://ubuntu.uci.cu/ubuntu utopic main restricted universe multiverse
" > /etc/apt/sources.list

# Luego se debe instalar PostgreSQL
RUN apt-get update && apt-get install -y python-software-properties software-properties-common postgresql-9.3 postgresql-client-9.3 postgresql-contrib-9.3

USER postgres

# Luego se debe crear un role de PostgreSQL llamado ``docker`` con ``docker`` como password
# y entonces se debe crear una base de datos llamada ``docker`` usando como propietario al usuario
# ``docker``.
RUN /etc/init.d/postgresql start &&\
psql --command "CREATE USER docker WITH SUPERUSER PASSWORD 'docker';" &&\
createdb -O docker docker

# Se debe ajustar la configuracion de PostgreSQL para que acepte conexiones remotas
RUN echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/9.3/main/pg_hba.conf

# Y cambiar el parametro ``listen_addresses``
RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf

# Exponer el puerto de PostgreSQL
EXPOSE 5432

# Se deben agregar los volumenes para permitir backups de la configuracion, logs y bases de datos
VOLUME ["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]

# Por ultimo, dejo el comando a ejecutar cuando se inicie el contenedor
CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]

Para tener una referencia completa de cómo se debe escribir un Dockerfile, pueden usar la documentación oficial del Builder y de las mejores prácticas para escribir Dockerfiles.

Luego entonces, ya se puede crear la imagen para PostgreSQL:

sudo docker build -t postgresql_ex .

Luego ya podemos ejecutar el contenedor con el servidor de PostgreSQL:

sudo docker run --rm -P --name pg_test postgresql_ex

Ahora, para conectarse al servidor de PostgreSQL, debes ver por qué puerto tu sistema ha mapeado el puerto 5432 de PostgreSQL en tu host. Para conocer esto, puedes usar el comando docker ps que ya hablamos antes. El resultado puede ser algo como esto:

$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e24362f27f6 postgresql_ex:latest /usr/lib/postgresql/ About an hour ago Up About an hour 0.0.0.0:49153->5432/tcp pg_test

Se puede ver que para conectarte al sistema, hay que usar el puerto 49153 para poder conectarte al servidor:

$ psql -h localhost -p 49153 -d docker -U docker --password

y ya a partir de aquí podemos hacer todas las operaciones que hacemos normalmente en PostgreSQL.

Conclusiones

Como pueden ver, iniciarse con Docker puede ser relativamente fácil, y pueden ver por qué tantas empresas han cambiado su proceso de desarrollo generando contenedores de sus aplicaciones en minutos listas para ser desplegadas. Muchos me han pedido que hable sobre cómo dockerizar una aplicación de PHP creada con Symfony 2, así que en próximas entregas, trataré de complacerlos. Recuerden, si tienen alguna duda, toda la documentación de Docker está disponible acá.