Bienvenido docker!

Docker es una de las herramientas que está cambiando la forma de desarrollar y desplegar aplicaciones de alta disponibilidad. Docker y micro-servicios es la relación perfecta para crear aplicaciones, separando las responsabilidades y aprovechando la virtualización al máximo

Seguro que habrás visto o leído algo de docker en los últimos meses. Por si no sabes qué es Docker es un servicio de virtualización que permite levantar máquinas virtuales con muy poco esfuerzo.

Estas máquinas virtuales suelen  llevar un sistema operativo (normalmente basado en linux) y una o más aplicaciones expuestas por uno o más puertos http.

Imágenes virtualizables

Docker basa su funcionamiento en imágenes. Una imagen no es más que un archivo en forma de snapshot de un sistema operativo con aplicaciones instaladas. Desde docker podemos arrancar máquinas virtuales basadas en dicha imagen, cada instancia en ejecución se llama contenedor.

Las imágenes se pueden crear o se pueden descargar del «market» de Docker ubicado en el Docker Hub. Prácticamente casi todas las imágenes del mundo del open source están disponibles gratuitamente.

Por ejemplo, podemos ejecutar una máquina virtual con ubuntu como sistema operativo, habiendo instalado WordPress con Apache Http Server con Php y una base de datos MySql y hacer accesible dicha máquina hacia el exterior vía el puerto http 80.

Contenedores virtuales

El sistema docker se encarga de gestionar el contenedor (o máquina virtual) para dotarle, según lo configuremos, de cuánta CPU, memoria RAM, disco y red.

Concretamente será suficiente con sólo indicar a Docker configuraciones del estilo:  el puerto 3000 de la máquina que contiene docker (host) ha de hacer forwarding al puerto 80 del contenedor denominado wordpress (guest). De esta manera cualquier petición que llegue al host en el puerto 3000 será redirigido a guest puerto 80, dejando accesible al exterior el servicio de WordPress.

Cada vez que creamos un contenedor a partir de una imagen, docker le asigna un identificador hecho de letras y números, pero podemos asignarle un nombre más amistoso por el cual podemos referirnos a él posteriormente.

Por ejemplo el resultado de ejecutar la lista de contenedores activos en la máquina de pruebas para este artículo es:

# docker ps

CONTAINER ID IMAGE     PORTS                    NAMES
759c6f880486 wordpress 0.0.0.0:8000->80/tcp     wordpress_wordpress_1
5fc5392b043e mysql:5.7 3306/tcp                 wordpress_mysql_1
e35af79b36a5 mysql:5.7 0.0.0.0:3306->3306/tcp   arteco_mysql_1
5dc78ee6b2ff mongo:3.7 0.0.0.0:27017->27017/tcp arteco_mongo_1

Según la tabla en el host hay 4 contenedores o instancias de máquinas virtuales, ejecutando tres imágenes distintas:

  • 1 wordpress (con id 759c6f880486) disponible en el (host) por el puerto 8000
  • 2 mysql servers, sólo uno de ellos accesible desde el host (la identificado por e35af79b36a5) por el puerto 3306. El otro contenedor ha sido «enlazado al wordpress» y no es accesible desde otro lugar que no sea la instancia de wordpress. Y,
  • 1 mongo server, accesible por el puerto 27017.

Cada uno de los contenedores tiene su sistema operativo propio, sus dependencias, versiones y utilidades instaladas que pueden ser totalmente diferente entre ellas.

Se puede interpretar los contenedores como cajas negras en las que sólo debemos preocuparnos en sus accesos desde y hacia el exterior de dichos contenedores. Como puede ser el puerto por el cual podremos acceder a ellas – hacia adentro del contenedor- o el directorio del host donde queremos que escriba los logs -hacia afuera del contenedor.

Estas configuraciones de cómo queremos que esté compuesta la máquina virtual y cómo se relaciona con el mundo exterior, se realiza mediante la configuración que se le indica a docker en el momento de crear el contenedor.

Primeros pasos

Antes de comenzar deberás revisar los requisitos para poder instalar Docker CE (Community Edition) en tu computadora. Podrás instalarlo para los principales sistemas operativos: windows, mac, linux, etc…

Hay muchos distribuibles y es ampliamente usado en todo el mundo, así que es poco probable que tengas problemas en la instalación. Si tuvieras un contratiempo, comprueba el site de documentación del proyecto Docker Docs.

Primer contenedor

Una vez instalado docker vamos a crear nuestro primer contenedor. Por ejemplo una base de datos MySQL. Antes de ejecutar el comando que crea el contenedor, conviene buscar la imagen y leer la documentación asociada a ésta para ver qué parametros de configuración podemos utilizar.

Una búsqueda rápida por google con los términos «docker mysql» nos lleva a la página del contenedor oficial: https://hub.docker.com/_/mysql/

La opción más sencilla que nos dan para comenzar es la siguiente:

# docker run --name my-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -d mysql:latest

El comando tiene los siguientes parámetros:

  • –name my-mysql fija el nombre amigable del contenedor.
  • -e MYSQL_ROOT_PASSWORD=my-secret-pw indica el password que usara el script de inicialización de mysql para asignar el password del usuario root. El «-e» crea una variable de entorno (bash/cmd) disponible en los scripts del contenedor.
  • -p 3306:3306 indica el puerto del host que hará redirección al puerto del guest (del container).
  • -d indica en modo detached (o daemon), es decir el STDOUT no se redirige al STDOUT de la consola donde lanzamos el docker run.
  • mysql:latest, por último, indican qué imagen y versión de la imagen queremos usar.

La ejecución del comando nos creará nuestra primera instancia. Al ser la primera vez que lanzamos el comando docker run, la imagen de mysql no estará disponible en local, así que deberá descargar el fichero de hub.docker.com antes de poder crear el contenedor.

Acto seguido, se creará el contenedor con el nombre my-mysql y estará disponible vía el puerto tcp 3306 listo para recibir peticiones SQL.

Podemos comprobar la ejecución del container con

# docker ps

Otros comandos útiles

  • Parar el contenedor: docker stop <CONTAINER_ID>
  • Listar todos los contenedores (incluso los parados): docker ps -a
  • Eliminar un contenedor: docker rm <CONTAINER_ID>
  • Eliminar una imagen no usada por ningún contenedor (nótese la i después de rm) docker rmi <CONTAINER_ID>
  • Conectar por ssh a un contenedor: sudo docker exec -i -t<CONTAINER_ID> /bin/bash

Packs de contenedores

Como se puede intuir por el primer ejemplo del comando docker ps, unas instancias pueden estar vinculadas a otras instancias. Como en el caso de mysql para wordpress, la instancia de mysql sólo está accesible para el contenedor de wordpress.

Estos enlaces pueden hacerse con el argumento –link en docker run. Pero existe otra forma más fácil de lanzar grupos de instancias en donde unas accedan a las otras.  Para ello usaremos docker-compose.

Docker Compose no es más que una capa de abstracción por encima de docker run para simplificar el arranque de grupos de máquinas. Requiere instalar algunas librerías y nos habilitará el consumo del comando docker-compose desde el cli.

Por ejemplo, lanzar dos contenedores, uno con mysql y el otro con wordpress podemos hacerlo de la siguiente manera:

Creamos el fichero docker-compose.yml con el siguiente contenido:

version: '3.1'services:  wordpress:    image: wordpress    restart: always    ports:      - 8080:80    environment:      WORDPRESS_DB_PASSWORD: example  mysql:    image: mysql:5.7    restart: always    environment:      MYSQL_ROOT_PASSWORD: example

En el mismo directorio donde está este fichero Yml ejecutamos

# docker-compose up -d

Por defecto, si a docker-compose no se le indica otro fichero de configuración, irá a buscar en el directorio de trabajo el fichero docker-compose.yml. Según el ejemplo encontrará dos servicios (contenedores) que levantar. Uno de ellos accesible por el puerto 8080 y el otro no. El argumento «-d» es igual que en docker run, para el modo detached.

Si ejecutamos de nuevo docker ps veremos las instancias creadas por docker-compose como instancias normales de docker.

Para parar las instancias podemos hacerlo a mano con docker stop <CONTAINER_ID> o ejecutando docker-compose stop en el directorio del fichero Yml.

# docker-compose stop

De esta manera podemos levantar grupos de servicios cómodamente sin tener que escribir largos comandos en el cli.

Conclusión

La ventaja principal de los contenedores son muchas. Primero es que elimina el problema de incompatibilidades entre versiones de librerías. Muchas veces un sistema funciona con Python 2 y otras con Python 3, o otros con Java 7 y otros con Java 8, etc…

También nos permite lanzar y parar contenedores sólo con comandos, pudiendo instalar fácilmente en nuestra organización despliegues continuos.

No menos importante es poder aislar unos servicios de otros, asignar cuotas de CPU, acceso a disco, etc.. dotando de mayor seguridad y aislamiento a los procesos, evitando la escalada de privilegios.

Y por último la virtualización tiene la gran ventaja de la escalabilidad. Creando una imagen de nuestro aplicativo o servicio, podemos lanzar tantos contenedores como sean necesarios a medida que la utilización de éstos sube, o eliminando instancias que están ociosas.

A día de hoy se pueden encontrar muchas herramientas open source que permiten la orquestación de containerized services como Kubernetes de Google o Swarm de Docker. El uso de los orquestadores requiere su curva de aprendizaje considerable y las aplicaciones deben estar desarrolladas para que sean compatibles con cambios dinámicos, como IPs o DNS. Pero en definitiva permiten realizar proyectos que escalen tan bien como la utilización requiera.

Esperamos que esta pequeña guía haya servido de utilidad. Siéntete libre de hacernos llegar cualquier comentario.

¿Ya tienes la idea de tu nuevo gran proyecto?

Autor: Ramón Arnau

Director de Arteco Consulting sl. Ingeniero Informático. Máster en Administración y Dirección de Empresas. Máster en Tecnologías de la Información. Auditor ISO 27001. ITIL.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *