miércoles, 29 de agosto de 2018

Conceptos avanzados de imágenes Docker - Parte III

Hola de nuevo, hoy seguimos trabajando con la construcción de imágenes para Docker. En este caso veremos como añadir opciones que nos permitan configurar los servicios que despliegan, según nuestras necesidades.

Siguiendo con nuestra imagen de un servicio de directorio basado en OpenLDAP,  vamos a ver como podemos especificar las opciones de configuración del mismo.

Con la imagen realizada hasta ahora se incluye el fichero de configuracion de OpenLDAP, que se encuentra en la ruta /ldap/etc/openldap/slapd.conf y que tiene una configuración por defecto.

Como es lógico, esta configuración no nos será de gran utilidad y necesitaremos cambiarla en función de nuestro servicio.

Para poder configurar adecuadamente el servidor OpenLDAP de nuestra imagen tenemos dos opciones, aunque en general podemos optar por estas dos aproximaciones para cualquier software contenido en una imagen cuya configuración dependa de un fichero o ficheros de texto.

La primera es, sabiendo donde está el fichero de configuración dentro de la imagen, montar un volumen que contenga un fichero slapd.conf que establezca la configuración deseada en el momento de crear un contenedor, por ejemplo:

Establecemos la configuración del servidor OpenLDAP con un volumen que contiene la configuración.

La otra opción consiste en complicar un poco nuestra imagen, usando un script de arranque que utilice los valores de variables de entorno que pasaremos a nuestro contenedor en el momento de su creación. Aunque puede sonar un poco complicado, vamos a ver que es muy sencillo.

Vamos a empezar con un ejemplo muy simple, para ello vamos a crear un contenedor en el que vamos a inyectar unas variables de entorno y vamos a comprobar como estas variables pasan a estar disponibles dentro del contenedor. Para inyectar variables en un contenedor solo tenemos que usar la opción --env en el momento de su creación es decir, solo tenemos que hacer algo como lo siguiente:

Inyección de variables de entorno en un contenedor.
Como es lógico podemos pasar tantas variables de entorno como necesitemos y, como vemos, conservarán el nombre y valor asignado. Por tanto, teniendo esto en cuenta, podemos hacer un script que recoja dichas variables de entorno y sustituya los valores de las mismas en el fichero de configuración de nuestro servicio, que en nuestro ejemplo es un servidor OpenLDAP.

Como el punto importante en este caso es el script que debemos crear, vamos a empezar por hacer una prueba sencilla con una imagen diferente. Este script debe comprobar si existen las variables de entorno, usarlas para cambiar el contenido del fichero de configuración slapd.conf y arrancar el demonio slapd. Adicionalmente debería mostrar un mensaje en stderr si falta alguna de las variables de configuración necesarias.

Como ejemplo de lo que podemos hacer en función de nuestras necesidades, esta sería la salida de una imagen de test generada a partir de la imagen ldap original. En ella hemos cambiado el ENTRYPOINT por nuestro nuevo script el cual, de momento, solo comprueba las variables pasadas y las registra en STDOUT y STDERR:

Creación del contenedor sin las variables requeridas.
En el caso de arrancar un contenedor con las variables requeridas por el servicio, la salida mostrada será la siguiente:

Creación del contenedor con todas las variables necesarias para la configuración del servicio OpenLDAP.
Por tanto, ya solo nos queda modificar el script para incluir una linea que arranque el servidor OpenLDAP, para lo cual lo mejor es incluir una llamada como la siguiente:

Arranque del servicio en nuestro script de inicio de la imagen ldap.
De este modo nos aseguramos que las señales enviadas al contenedor llegan de manera correcta al demonio slapd y que este se cierra ordenadamente cuando lo paremos.

Ahora podemos o bien crear una nueva imagen, cambiando el ENTRYPOINT para que use nuestro nuevo script o bien generar una imagen a partir de la original. En mi opinión, siempre dependiendo del servicio y teniendo bien documentadas las diferencias entre nuestras imágenes, creo que lo mejor es mantener ambas imágenes y usar una u otra en función de las necesidades que tengamos en cada momento.

El script creado para este caso está disponible via git en https://github.com/locurastecnicas/DOCKER_scripts. Este script es muy mejorable ya que, al menos, debería generar la password de forma aleatoria en caso de no proporcionarla mediante una variable.

martes, 28 de agosto de 2018

Trabajando con Jenkins en contenedores

Supongamos que tenemos un contenedor generado a partir de una imagen de Jenkins con el que queremos trabajar en nuestro entorno de CI/CD. Si creamos el contenedor de manera que sea efímero, al pararlo perderemos toda nuestra configuración salvo que seamos capaces de mantener el directorio que contiene toda la configuración del servicio Jenkins.

Para poder mantener dicha configuración, primero acudimos a la documentación de Jenkins la cual, en la URL https://wiki.jenkins.io/display/JENKINS/Administering+Jenkins, nos indica que toda la información de configuración utilizada por Jenkins se almacena en la ruta dada por la variable JENKINS_HOME. Si inspeccionamos la imagen podremos ver lo siguiente:

Variables de entorno de la imagen de Jenkins.
Adicionalmente veremos una referencia a un volumen en la definición de dicha imagen:

Declaración de volumen en la imagen de Jenkins.
Por tanto queda claro que necesitamos mantener el contenido de dicha ruta, si queremos mantener la configuración de nuestro servicio jenkins.

Ahora bien, ya tenemos un contenedor corriendo y hemos generado cierta configuración que no queremos perder, con lo que necesitamos saber donde está almacenada localmente dicha información para poder copiarla. Si inspeccionamos el contendor que está corriendo en nuestro sistema veremos lo siguiente:

Definición de montaje del volumen local para JENKINS_HOME.

Y al inspeccionar esta ruta tenemos lo siguiente, que veremos que coincide con el directorio de configuración de Jenkins:

El directorio de configuración del contenedor de Jenkins en nuestro disco local.
Por tanto copiamos todos esos ficheros a otra ruta local, que será la que utilizaremos como volumen para nuestro servicio Jenkins y volvemos a crear un nuevo contenedor efímero, pero esta vez mapeamos un volumen que apunte a esta nueva ruta que acabamos de crear:

Creación de nuevo contenedor con mapeo de volumen a la configuración de Jenkins.
Y como podemos comprobar, el servicio Jenkins vuelve a estar disponible con la configuración que hubiésemos realizado hasta ese momento:

Servicio Jenkins disponible con configuración existente.
A partir de este punto podemos seguir configurando y utilizando el servicio sin problemas. Siguiente parada, ejecución de compiladores mediante contenedores específicos para cada job.