sábado, 28 de julio de 2018

Usando Jenkins como gestor de eventos

Hay ocasiones en las que ciertas herramientas pueden usarse para resolver problemas de administración, aunque sus funcionalidades estén enfocadas a otros ámbitos.

Imaginemos que al terminar la instalación de un sistema, es necesario realizar ciertas tareas adicionales que requieren acceso a una red aislada, pero el equipo en cuestión no tiene permisos de acceso a dicha red. Por ejemplo pensemos en la instalación y configuración de un equipo de usuario que, en su paso final debe acceder a la red de administración para lanzar un script que realizará unas tareas de configuración adicionales.

Para casos similares a este y muchos otros más, podemos usar Jenkins configurando un job parametrizable que podremos lanzar mediante una simple petición HTTP POST.

La idea es usar Jenkins como gestor de eventos, siendo el evento generado por nosotros mediante la petición HTTP la cual, al corresponder a un job configurado, ejecutará un script con los parámetros que pasemos en la petición.

Lo primero es crear un usuario que será el que utilicemos para todas las tareas de gestión de eventos y darle los permisos necesarios que, si estamos usando el modo de seguridad basado en proyecto, deben ser al menos de lectura global, de lectura y ejecución de jobs y de update de ejecuciones. Para diferenciar este usuario del resto lo mejor es darle un nombre distintivo, en nuestro caso creamos el usuario Event Manager (eventmgr).

Ahora, para definir el job solo tenemos que asegurarnos de marcar la opción Esta ejecución debe parametrizarse y Lanzar ejecuciones remotas. En resumen, la forma de configurarlo es la siguiente:

Creación inicial del job y asignación de seguridad.

Configuración de parametrización y especificación de los parámetros.
Marcamos el job como ejecutable remotamente y generamos un token de seguridad.
Especificamos que se ejecutará, en este caso de ejemplo un simple echo.
Con el job ya configurado, lo único que es necesario hacer ya es lanzar una petición HTTP a nuestro servidor Jenkins con los parámetros necesario, en nuestro ejemplo solo nos va a generar un fichero con los valores de ambos parámetros. La URL a la que debemos realizar la petición HTTP será:

Acceso a la URL especificando los parámetros para nuestro job.
Y podemos comprobar que el job se ha ejecutado correctamente y ha generado el fichero con los valores especificados en los parámetros pasados al job:

Resultado de la ejecución del job.
Por tanto con Jenkins podremos realizar acciones basándonos en eventos que nosotros mismos generemos, lo cual nos facilitará bastante ciertas tareas administrativas.

domingo, 22 de julio de 2018

Cluster ONTAP - Acceso multiprotocolo

Hoy continuamos la entrada anterior, en la que trabajamos con SVMs básicas, con una nueva entrada en la que vamos a seguir trabajando con SVMs pero en este caso, configuraremos una SVM multiprotocolo.

¿Que nos permite una SVM multiprotocolo? Poder acceder a nuestros datos en un entorno NAS usando NFS y CIFS, algo que con sistemas ONTAP es posible y simple de configurar.

El acceso multiprotocolo está indicado para entornos heterogéneos, donde tenemos clientes Unix, Linux y Windows que necesitan acceder a los mismos datos simultáneamente.

Ya vimos en la anterior entrada como crear una SVM, concretamente una NFS para clientes Unix y Linux. Lo que haremos ahora es añadir a dicha SVM el protocolo CIFS y configurarla para unirla a un dominio Windows para nuestras pruebas.

Para empezar necesitamos añadir el protocolo CIFS a la SVM ya existente, para esto solo tenemos que abrir OnCommand System Manager y en el apartado SVMs seleccionamos la que vamos a editar y añadimos el protocolo CIFS a la misma:

Añadimos el protocolo CIFS a la SVM existente.

Al hacer esto, OnCommand nos mostrará un mensaje de advertencia indicándonos que debemos configurar el protocolo CIFS. Para poder continuar y realizar esta configuración, debemos añadir CIFS como protocolo de datos a la LIF de esta SVM. Como de momento, oajalá NetApp cambie pronto este pequeño problema, solo puede hacerse en el momento de crear la LIF, necesitamos destruir nuestra LIF actual y crearla de nuevo con ambos protocolos:

Creamos una nueva LIF con ambos protocolos para nuestra SVM.
Ahora continuamos y, desde la sección de SVMs, seleccionamos la que estamos configurando, pinchamos sobre SVM Settings y pasaremos a las opciones de configuración generales de la SVM. Ahora desde la sección CIFS de este apartado, solo tenemos que pinchar sobre Setup para configurar el servicio CIFS:

Configuración de SVM, vamos a configurar el protocolo CIFS.

Configuración del servicio CIFS de la SVM.
Una vez configurado el servidor CIFS, podemos ver como el estado del servidor CIFS ha cambiado a iniciado y refleja el nombre del dominio al que pertenece la SVM:

Servidor CIFS de una SVM configurado y unido a un dominio.
Los puntos mas importantes a tener en cuenta para poder unir correctamente una SVM a un dominio Windows son la resolución DNS, la sincronización horaria entre el cluster y los controladores de dominio y que utilicemos un usuario del dominio con permisos para añadir máquinas.

Como podemos comprobar, una nueva cuenta de equipo correspondiente a nuestra SVM aparece en nuestro DC de laboratorio:

Cuenta de equipo correspondiente a nuestra SVM.

Antes de continuar debemos tener en cuenta un punto muy importante, el cual es imprescindible entender correctamente cuando hablamos de acceso CIFS en sistemas ONTAP. Cuando un cliente Windows se conecta a una carpeta compartida desde una SVM, esta siempre va a realizar un mapeo del usuario que realiza la petición de conexión a un usuario Unix. Este punto implica que debemos tener una forma de mapear nuestros usuarios Windows, ya sean de un dominio o un grupo de trabajo, a usuarios Unix que pueden ser locales a la SVM o proprocionados por un servicio de nombres externo. En una entrada posterior explicaré este punto más detenidamente, por ahora solo debemos tener en cuenta que, para asegurar que nuestros usuarios del dominio de laboratorio pueden acceder y escribir en nuestra carpeta compartida por CIFS, necesitamos cambiar ciertos atributos de sus entradas en Active Directory para que contengan los mismos valores que los usuarios homónimos en nuestra máquina Linux y establecer la configuración de mapeo en nuestra SVM.

Una vez configurada la SVM, vamos a compartir el qtree que creamos con anterioridad usando el protocolo CIFS, con lo que podremos acceder a la misma información desde sistemas Windows. Para compartir un qtree mediante el protocolo CIFS solo es necesario realizar la siguiente configuración desde la sección Shares del apartado Storage:

Creación de un nuevo share.
Y a continuación modificamos los permisos de acceso para que solo un grupo determinado de usuarios pueda montar dicha carpeta remotamente, por ejemplo vamos a permitirlo solo a los miembros de un determinado grupo. Para esto solo tenemos que editar nuestro share y, desde la pestaña Permissions, añadir el grupo deseado:

Modificación de los permisos de acceso al share.
Ahora solo nos queda probar el acceso desde una máquina Linux y una máquina Windows a esta carpeta con los usuarios adecuados para confirmar que se accede correctamente desde ambos y que se pueden compartir los datos sin problemas.

Montamos la carpeta por NFS y modificamos los permisos de la misma para que solo los miembros del grupo Proyecto2 puedan acceder a la misma y creamos un par de archivos de prueba con esos usuarios:

Pruebas de acceso a la carpeta desde Linux.
Ahora accedemos al share desde una sistema Windows y si hemos configurado todo adecuadamente, deberíamos ver el contenido de la carpeta:

Conexión al share CIFS creado en nuestra SVM.

La misma carpeta accediendo desde un sistema Windows.
Esto ya es un avance bastante importante, ahora solo nos queda comprobar que sucede cuando escribimos y leemos desde ambos sistemas. Si creo un archivo desde mi cliente Windows tengo que verlo con los permisos adecuados desde mi máquina Linux:

Creo un archivo desde el sistema Windows.
Y puedo verlo desde la máquina Linux.
Es importante darse cuenta que, aunque he creado el fichero desde un sistema Windows, el propietario del mismo es el usuario usrprj2.

Ahora puedo editar ese fichero desde mi sistema Linux y añadir datos que luego podré ver desde el cliente Windows y modificarlos:

Añadimos datos desde el sistema Linux.
Comprobamos desde el cliente Windows que podemos modificar los datos.
Y volvemos a comporbar que nuestro sistema Linux accede a los datos.
Una última comprobación que es recomendable realizar es comprobar que la sesión CIFS muestra un mapeo correcto entre el usuario Windows de dominio y el usuario Unix con el que se mapea. Para esto necesitamos lanzar el comando siguiente:

Comprobación de sesion CIFS.
Como podemos ver en la salida anterior, el usuario del dominio LAB\usrprj2 se ha mapeado correctamente con el usuario UNIX usrprj2 lo que nos permite acceder sin problemas al share y mantener los permisos que hacen posible el acceso desde un sistema Unix o Linux.

En resumen, los sistemas  ONTAP nos permiten compartir sin problemas en entornos heterogéneos siendo los puntos más importantes a tener en cuenta una correcta configuración de red y resolución DNS, la sincronización horaria entre todos los sistemas involucrados, principalmente el cluster  y los DCs y la correcta configuración del sistema de mapeo de usuarios en la SVM multiprotocolo.

En las próximas entradas comentaré más en detalle como funciona el mapeo entre usuario y como configurarlo, ya que es fundamental para este tipo de entornos.

miércoles, 11 de julio de 2018

Cluster ONTAP - Trabajando con SVMs

Hola de nuevo, en esta entrada vamos a seguir trabajando con cluster ONTAP definiendo máquinas virtuales de almacenamiento (SVMs) para proporcionar servicios de fichero o bloque a nuestros clientes.

Como ya vimos en las entradas anteriores, una SVM es una instancia de uno o más protocolos de acceso proporcionados por ONTAP. Es decir, una SVM proporcionará servicios de acceso a fichero (NFS, CIFS) o bloque (FCP, iSCSI, FCoE) de forma aislada al resto de SVMs del cluster.

Cada SVM tendrá sus volúmenes propios y separados del resto, aunque dentro de los mismos agregados que el resto de posibles SVMs del cluster.

Por último, una SVM tendrá una o más interfaces lógicas de red (LIFs) para permitir el acceso a los datos, ya sea mediante protocolos como NFS, CIFS o iSCSI o interfaces de fibra dedicadas para una SAN y acceso mediante FCP.

Teniendo todo esto en cuenta pasemos a crear una SVM básica. Para ello vamos a usar la interfaz gráfica y luego crearemos otra mediante el interfaz de línea de comandos.

Gran parte de la administración puede realizarse desde el OnCommand System Manager que está incluido en el sistema y que es accesible desde la dirección de administración del cluster. Con lo que nos conectamos y encontraremos el siguiente dashboard de inicio:

Pantalla de login a OnCommand System Manager.

Dashboard principal de OnCommand System Manager.
Para aquellos acostumbrados a utilizar OnCommand Unified Manager, el dashboard de OnCommand System Manager incluido en las recientes versiones de ONTAP 9.3 y 9.4, les será muy familiar.

Para crear una SVM desde OnCommand System Manager solo tenemos que navegar hasta el apartado SVMs dentro de la sección Storage:

Creación de SVMs desde OnCommand System Manager.
Como es lógico, desde aquí veremos que el proceso es muy simple y solo necesitamos seguir el asistente de creación que aparece al pinchar sobre Create. De forma resumida, la creación de una SVM podemos verla en las imágenes siguientes:

Lanzamos el asistente de creación de una SVM.
Configuramos la red de la nueva SVM.
Fijamos la contraseña del usuario vsadmin de la SVM.
Con esto ya tenemos nuestra nueva SVM que, de momento, solo tiene su volumen root de configuración, con lo que añadimos un nuevo volumen donde crearemos los qtrees que luego exportaremos por NFS. Para esto, desde la sección Storage solo es necesario que dentro de Volumes escojamos nuestra SVM para añadir un volumen de datos a la misma. Realizamos la configuración básica del volumen y el resto de opciones, las configuraremos más tarde:

Creación básica de un volumen.
Una de las primeras opciones que vamos a cambiar es la política de snapshots, es decir, cuando vamos a hacer un snapshot de un volumen y cuantos snapshots vamos a mantener de cada tipo. Para esto solo es necesario que seleccionemos Snapshot Policies dentro de la sección Protection y creemos una nueva política de snapshots en la que podemos usar una programación ya definidia o una creada por nosotros:

Creación de una política de snapshots.
De esta manera establecemos una política de snapshots en la cual, usando una programación específica, se crearán tres snapshtos diarios a las 8:00, a las 14:00 y a las 18:00 y queremos que se mantengan 21 de esos snapsots, lo que nos da un total de 7 días con lo que, cuando se lance el snapshot de las 8:00 horas el octavo día, se borrará automáticamente el snapshot de las 8:00 horas del día 1.

Ahora solo tenemos que modificar el volumen que hemos creado para nuestra SVM y cambiar la política de snapshots del volumen:

Configurando la política de snapshots de un volumen.

Seleccionamos la política que hemos creado antes.
Adicionalmente podemos configurar las opciones de deduplicación del volumen y asignar una programación para dichas tareas, así como las opciones de autosize del volumen si es necesario.

Para terminar solo nos falta crear un qtree y compartirlo por NFS con el resto de nuestras máquinas, para esto solo tenemos que crear una polítca de exports NFS, para especificar que permisos damos en función de las direcciones IP de los clientes, crear el qtree y aplicar la política de exportación que hemos creado. De forma resumida podemos verlo del siguiente modo:

Creación y exportación de un qtree.
Editando el qtree podremos fijar una cuota en el mismo para evitar que el cliente o clientes que monten dicho recurso por NFS, no consuman todo el espacio disponible en el volumen.

Por último desde nuestro cliente, montamos el recurso NFS para comprobar que la configuración es correcta y que la cuota se está aplicando correctamente:

Montando el qtree exportado por NFS en el cliente.
Como vemos en la salida anterio, nuestro volumen es de 1 GB pero, al aplicar una cuota de 200 MB al qtree, el espacio disponible en el cliente es de tan solo 200 MB.

Ahora que hemos visto como hacerlo graficamente, pasemos a crear una SVM por línea de comandos lo cual veremos que es igual de sencillo aunque más largo. Para ello lo primero que debemos hacer es conectarnos al cluster por ssh y una vez iniciada la sesión, solo tenemos que usar el comando vserver con unas cuantas opciones, como podemos ver en la siguiente imagen:

Creación de una nueva SVM.
A continuación tenemos que configurar los protocolos que queremos que la nueva SVM uilice para servir datos, darle una nueva interfaz lógica con una dirección IP, ya que se trata de una SVM que dará servicio NAS y crear un nuevo volumen de datos para la misma. Todo esto podemos verlo en las siguientes imágenes:

Seleccionamos que protocolos usará la nueva SVM.
Creamos una nueva LIF y la asignamos a la SVM recien creada.
Creamos un nuevo volumen de datos para la nueva SVM.
Para terminar, asignamos la política de snapshots que hemos creado antes a este nuevo volumen. Adicionalmente crearemos una política de export NFS que aplicaremos al volumen y crearemos un qtree que exportaremos a nuestras máquinas cliente:

Asignamos la política de snapshots al nuevo volumen. El warning indica el cambio de política.
Creación de una política de export y un qtree que se comparte por NFS.
Ya solo nos falta aplicar una cuota a dicho volumen, como hemos hecho en el caso anterior y montar el recurso NFS en nuestra máquina cliente:

Creación y aplicación de la cuota.
Tras montar el directorio en el cliente veremos que el espacio disponible es de 200 MB, como en el caso anterior.

Como es lógico, el proceso de crear una SVM por línea de comandos es algo más largo pero, teniendo claro todas las partes que la forman y los requisitos necesarios, solo es cuestión de usar los comandos adecuados.

En caso de crear una SVM que sirviese datos a clientes Windows, o una SVM multiprotocolo para clientes Windows y Linux, podremos unir la SVM a un dominio Windows sin problemas, pero ese ejemplo lo dejaremos para otro día.

En las próximas entradas, además de revisar las SVMs con acceso CIFS o multiprotocolo, también veremos como funcionan las relaciones de protección SnapMirror y SnapVault en las nuevas versiones y como crearlas.

sábado, 7 de julio de 2018

Nuevas características de ONTAP 9.4

Hola de nuevo, casi sin tiempo para nada más ya nos encontramos con la nueva versión de ONTAP disponible para poder desplegarla en nuestros sistemas. La nueva versión 9.4 de ONTAP tiene características tan interesantes como las siguientes:
  • Un volumen puede contener hasta 1023 snapshots. Esto nos permitirá ampliar la retención de aquellos volúmenes protegidos con SnapVault con lo que, para entornos en los que todavía necesitamos cintas, es una gran noticia que nos acerca a poder eliminar una buena cantidad de ellas, aunque solo sea para los backups incrementales diarios. Esta nueva característica se aplica a los volúmenes destino de una relación de SnapMirror, que ahora podrán mantener hasta 1019 snapshots.
  • Desde ONTAP 9.3 ya existe la opción de crear un relación de protección con un solo comando. Usando el comando snapmirror protect podemos establecer dicha relación en un solo paso.
  • Simplificación en el proceso de peering entre clusters y SVMs. Ahora, usando la opción generate-passphrase en el cluster de destino, podemos generar una contraseña válida solamente durante un tiempo determinado y para un solo cluster que, usada en el clsuter origen nos permitirá establecer la relación de peering entre ambos cluster mucho más rápidamente.
  • Aunque es una funcionalidad existente desde la versión 9 de ONTAP, es importante recordar la posibilidad de utilizar RAID de triple paridad, o RAID-TEC, en nuestros aregados para asegurar que aquellos más grandes puedan soportar el fallo simultaneo de hasta tres discos.
  • Se ha incluido soporte para CIFS multicanal, lo que permite un rendimiento mayor y tolerancia a fallos entre los clientes CIFS y nuestras SVMs.
  • Esta nueva versión incluye soporte para NVMe sobre Fibre Channel (NVMe/FC) con lo que, con una conectividad completa NVMe/FC de un extremo a otro, las mejoras en rendimiento al sustituir nuestro viejo protocolo SCSI por el nuevo protocolo NVMe son enormes. Es importante tener en cuenta que la especificación para multipath del protocolo NVMe, llamada Asymmetric Namespace Access (ANA), está todavía en desarrollo.
Estas son solo algunas de las características que me han parecido más importantes así que, si queréis saber más, os recomiendo visitar la página de NetApp para obtener una lista de todas las nuevas funcionalidades en las release notes de la versión 9.4.

Creo que ya es hora de bajar la última versión del simulador de ONTAP para empezar a probar algunas de esas nuevas características en acción.

La importancia de las directivas en NetWorker

Hoy vamos a recordar algo que no suele suceder muy a menudo, el fallo de un backup causado por determinados ficheros. Vamos a revisar como podemos analizarlo y solucionarlo de manera muy sencilla.

En ocasiones se produce un fallo realizando un backup en algún save set que antes no fallaba. De repente las notificaciones de un cliente que lleva mucho tiempo configurado comienzan a informar de fallos en el proceso de backup, pero solamente en algunos de los directorios o save sets de los configurados para ese cliente. Cuando esto sucede suele producirse en servidores de ficheros a los que acceden usuarios mediante el protocolo CIFS, por ejemplo servidores Unix o Linux compartiendo su almacenamiento interno mediante samba con equipos Windows.

Llegados este punto, la forma más correcta de analizar el fallo es lanzar el comando save directamente desde el cliente sobre esa ruta y analizar la salida del mismo. Lanzariamos el comando save del siguiente modo:

Comando save con mucho log para analizar el fallo.
Podríamos añadir la opción -D9 para que se lance en modo debug, lo cual genera mucha más salida, pero en general suele bastar con la sintaxis anterior, que ya genera bastante información.

Quitando toda la información intermedia de salida del comando, la parte importante es justo el final del mismo que tendrá una pinta como la siguiente:

Salida del comando save.
La salida nos muestra que, cuando el comando save lanza el módulo uasm para hacer el backup del fichero /Ruta/Thumbs.db, se produce un core y el comando save sale de forma un poco fea.

Recordemos que NetWorker tiene diferentes módulos para realizar las operaciones de backup y recuperación de diferentes tipos de sistemas de archivos, siendo el módulo uasm el empleado para los sistemas de ficheros Unix y Linux y que en nuestro caso al intentar hacer backup del fichero Thumbs.db, falla generando la salida anterior.

Como uasm es un módulo que puede llamarse por separado, es decir podemos ejecutarlo directamente desde línea de comandos, vamos a obtener una traza del mismo para intentar determinar más en profundidad cual es el fallo que se está produciendo.

En este punto, es muy importante que conozcamos que herramientas proporcionan los diferentes sistema operativos de forma nativa para poder obtener la traza de un comando y analizar las llamadas al sistema que realiza. En concreto en sistemas Solaris el comando que usaremos será truss y en sistemas Linux strace. Estos comandos generan muchísima salida, con lo que es recomendable utilizar la opción para volcar la traza del comando a un fichero para analizarla posteriormente.

Para el caso que nos ocupa, lanzamos el siguiente comando truss por tratarse de un sistema Solaris 11.3:
Generamos la traza del comando uasm
Y la salida que tenemos del comando anterior es la siguiente:

Salida del comando truss para analizar el comando de backup.
Esta salida, que en principio parece que no dice nada, realmente nos está indicando que el binario uasm, al procesar ese fichero Thumbs.db, ha intentado acceder a una dirección de memoria no válida, lo que nos hace pensar que puede haber un bug en el comando que provoca que, en determinados casos ciertos ficheros provocan este tipo de fallos.

Como está claro que este fallo implica abrir un caso de soporte pero necesitamos realizar el backup de la ruta afectada, lo mejor es establecer una directiva para ese cliente o todos aquellos clientes que puedan contener ese tipo de ficheros, indicando que deben ser ignorados al hacer backup.

Los ficheros Thumbs.db de Windows son pequeñas cachés utilizadas para hacer la visualización de miniaturas en directorios más rápida con lo que, sin ninguna duda, podemos ignorar estos archivos en nuestros backups sin problemas.

Por tanto para solucionar el problema, la directiva que debemos especificar es tan sencilla como la siguiente:
Directiva básica de exclusión de archivos.
Con esta directiva básica, que deberíamos usar para cualquier cliente de backup que contenga datos generados en sistemas Windows de usuario, nos aseguramos de excluir los ficheros Thumbs.db así como cualquier fichero temporal generado por el paquete Office. La última directiva indica que se comprimirán el resto de ficheros de esa ruta. Al especificar el carácter + delante de cada directiva, le estamos indicado a NetWorker que es necesario aplicar la operación a la ruta y todos sus subdirectorios.

Lo expuesto aquí, por mi experiencia, es algo que no suele producirse muy a menudo, con lo que no estaremos generando trazas de procesos de backup habitualmente. Sin embargo estas herramientas suelen ser muy útiles en general para detectar fallos y problemas de todo tipo de aplicaciones que, quizás de otro modo, nos costaría mucho más analizar y solucionar.

Como nota adicional, cuando se trata de sistemas Linux, el comando strace que suelo utilizar es el siguiente:

Comando strace equivalente en sistemas Linux.
 

sábado, 30 de junio de 2018

Almacenamiento hiperescalable con Ceph

Hola a todos, hoy voy a empezar una nueva sección para el estudio de Ceph y sus características. Recientemente hemos comenzado a trabajar en un proyecto de almacenamiento distribuido e hiperescalable y la primera parada es el estudio de Ceph.

De momento hemos comenzado leyendo la tonelada de documentación existente pero, como puntos importantes a tener en cuenta durante el estudio y posible despliegue del sistema tenemos lo siguiente:
  • Como cluster hiperescalable de almacenamiento, el sistema se basa en bloques de construcción formados por nodos que se van añadiendo al cluster con lo que, cuantos más nodos añadamos más almacenamiento y más rendimiento deberíamos obtener, siempre y cuando escalemos la red adecuadamente.
  • Es muy importante que estos bloques de construcción de los que hablamos sean idénticos para asegurar el mismo rendimiento en todos los casos y un adecuado balanceo de la carga entre todos.
  • De forma muy simple un cluster Ceph tiene dos tipos de demonios, los OSDs que permiten a los clientes leer o escribir los datos y los monitor, encargados de mantener la información actualizada del estado del cluster y el mapa de distribución de los datos.
  • Los hosts se comunicarán con los monitor y los OSDs directamente usando un cliente específico que, usando el algoritmo CRUSH, permitirá determinar donde se encuentran los datos. Esto implica que los hosts que accedan al cluster Ceph deben tener instalado un cliente específico.
  • El cliente Ceph no está disponible para sistemas Windows, con lo que será necesario usar gateways para dichos casos.
Estos son algunos de los puntos que, con lo poco que hemos leido, hemos encontrado importantes y que debemos tener muy en cuenta.

Según avancemos iré añadiendo entradas con más información sobre este sistema de almacenamiento y sus características.

Conceptos avanzados de imágenes Docker - Parte II

Hola, en la entrada anterior vimos como complicarnos un poco a la hora de construir imágenes. Hoy toca complicarnos un poco más y estudiar algunas de las opciones disponibles para la construcción de imágenes.

Hasta ahora hemos construido imágenes que nos permiten crear contenedores que ejecutarán una aplicación dererminada. La pregunta es ¿como le hemos indicado a docker qué debe ejecutar?¿cómo se ejecuta? y más importante todavía ¿que opciones tenemos?

Evidentemente la primera pregunta es la más sencilla. Si recordamos el dockerfile para nuestra imagen de un servidor ldap, teníamos lo siguiente:

Dockerfile de imagen ldap.
Como ya sabemos, mediante la instrucción ENTRYPOINT le estamos indicando a docker que programa o comando de nuestra imagen ejecutar al crear un contenedor basado en ella.

Ahora nos queda responder a las otras dos preguntas, las cuales están muy relacionadas entre si así que, como diría Groucho, respondamos primero a la segunda pregunta.

Ya sabemos que al crear una imagen es necesario que indiquemos en el dockerfile que la describe que se ejecutará dentro del contenedor. Para esto hay disponibles dos instrucciones que podemos usar en nuestros dockerfiles, estas instrucciones son CMD y ENTRYPOINT y en ambos casos el resultado al usar una u otra es muy similar, salvo por los siguientes puntos que debemos tener en cuenta:
  • El objetivo al usar CMD es el de especificar parámetros por defecto para nuestros contenedores. En este caso, siempre es necesario especificar un ENTRYPOINT junto con la instrucción CMD, la cual no contendrá ningún ejecutable.
  • Al usar ENTRYPOINT definiremos siempre un ejecutable que se lanzará al arrancar un contenedor. Esta definición siempre debe contener la ruta al ejecutable que queremos lanzar al crear nuestros contenedores. 
Es decir, aunque con ambas instrucciones podemos especificar el programa a ejecutar, lo ideal es siempre usar ENTRYPOINT para especificar el ejecutable y CMD para establecer los parámetros por defecto del mismo. Al especificarlo de esta manera, permitimos que cualquier parámetro que pasemos al comando docker run sustituya a los definidos en la instrucción CMD. Teniendo todo esto en cuenta, nuestro dockerfile para la imagen ldap quedaría del siguiente modo:

Nuevo dockerfile con parámetros por defecto.

Con esta nueva definición contruimos de nuevo nuestra imagen y ahora, al crear un contenedor, se ejecutará el servidor ldap indicado en ENTRYPOINT con los parámetros por defecto especificados en CMD. Si al crearlo pasamos otros parámetros al comando docker run, estos nuevos parámetros sustituirán a los que hemos especificado en el dockerfile. Veamoslo con un pequeño ejemplo:

Contenedor creado a partir de la imagen ldap.
Como podemos ver. nuestro conetendor está ejecutando el servidor ldap con los parámetros por defecto indicados en la instrucción CMD de nuestro nuevo dockerfile.

Si ahora creo otro contenedor y especifico otros parámetros el resultado será el siguiente:

Cambiando los parámetros en tiempo de creación del contenedor.
Es importante tener en cuenta que también podemos usar CMD para especificar el ejecutable, es decir, podemos usar ENTRYPOINT o CMD para especificar que ejecutar al crear un contenedor, incluso los dos a la vez si queremos y, como siempre, todo dependerá de nuestras necesidades y entorno.

Desde mi punto de vista, creo que lo mejor es usar la combinación de ENTRYPOINT, para el ejecutable y CMD, para los parámetros por defecto, cuando pueda ser necesario cambiar estos últimos al crear un contenedor. Cuando lo que buscamos es asegurarnos de que no se pueden alterar los parámetros por defecto, lo mejor será que nuestro dockerfile solo contenga una entrada ENTRYPOINT que especifique tanto el ejecutable como los parámetros necesarios. En este último caso cualquier parámetro que se añada en el momento de crear el contenedor se añadirá a los parámetros por defecto sin sustituirlos, con lo que nos aseguramos que el servicio arrancará con los parámetros deseados.

Otro punto importante que debemos tener en cuenta al utilizar ENTRYPOINT es el formato que utilizamos. Según la documentación, tenemos dos opciones al especificar la instrucción ENTRYPOINT:
  • Formato shell, que es más o menos: ENTRYPOINT comando param1 param2 ...
  • Formato exec, que es más o menos: ENTRYPOINY ["ejecutable", "param1", "param2", ... ]
Bueno y ¿cual es la diferencia y por qué es importante? La diferencia y por tanto su importancia, viene derivada de como se ejecuta el servicio en un caso y en el otro.

Hasta ahora siempre hemos usado el segundo formato en nuestros dockerfile, el denominado formato exec, en el cual especificamos el ejecutable y sus parámetros como un array JSON. Cuando hemos creado contenedores e inspeccionado los procesos corriendo en los mismos, hemos visto que nuestro ejecutable era siempre el PID número 1. Si usamos el formato shell, ¿que es lo que sucede? Como siempre veamoslo con un ejemplo muy sencillo:

Contenedor creado usando el formato shell de ENTRYPOINT.
Como podemos ver en la salida anterior, nuestro comando no es el PID 1 dentro del contenedor y esto es importante si queremos que nuestros servicios se paren ordenadamente. Cuando paramos un contenedor con el comando docker stop, en estos caso, el contenedor no parará de forma limpia ya que solo la shell usada para arrancar nuestro comando recibirá la señal, pero nuestro servicio no con lo que, en algunos casos, puede que tras un timeout docker deba enviar una señal SIGKILL al proceso, lo que puede provocar que el servicio no se pare adecuadamente. Teniendo esto en cuenta lo mejor será siempre usar la forma exec de ENTRYPOINT, como recomienda la documentación de Docker.

Hasta aquí un poco más de información sobre Docker y como trabajar con imágenes. En la siguiente entrada veremos como personalizar en el momento de crear un contenedor la configuración de nuestro servicio ldap.