Mostrando entradas con la etiqueta Docker. Mostrar todas las entradas
Mostrando entradas con la etiqueta Docker. Mostrar todas las entradas

sábado, 23 de febrero de 2019

Administración básica de Docker swarm - Parte II

Hoy continuamos con la administración de Docker swarm y en concreto, vamos a repasar como usar volúmenes con los servicios que desplegamos en nuestros clusters de dockerhosts.

Originalmente, como ya vimos en su momento, se usaba la opción -v o --volume, para montar volúmenes con nuestros contenedores standalone y, para el despliegue de servicios, se usaba la opción -m o --mount. Desde la versión 17.06 de Docker lo recomendado es usar --mount en ambos casos, aunque se sigue soportando el uso de --volume con contenedores standalone.
Recordando un poco lo que ya sabemos de Docker, hay dos tipos de montajes o volúmenes que podemos usar. Los dos tipos de montajes o volúmenes disponibles son:
  • Volúmenes de datos (volume mounts). Estos son los volúmenes independientes de nuestros dockerhosts y que deben ser gestionados de manera separada. Lo lógico es que estos volúmenes los proporcionen sistemas de almacenamiento específicos y que, mediante un driver determinado, podamos interactuar con el proveedor del almacenamiento y administrar los volúmenes.
  • Volúmenes de tipo bind. De forma muy simple estos son volúmenes que están en cada dockerhost del swarm, es decir son rutas dentro del sistema de archivos de nuestros dockerhosts.
Como ya he comentado, aunque se sigue soportando la opción -v o --volume, lo recomendado es usar siempre la opción -m o --mount, independientemente del tipo de volumen a usar. Al montar nuestros volúmenes con --mount podremos especificar diferentes opciones, como vimos en el post sobre Trident.

Para especificar los volúmenes de nuestros servicios o contenedores, la sintaxis de la opción --mount utiliza determinadas claves, mediante las cuales podemos especificar las siguientes opciones:
  • Tipo de montaje, con la opción type. Esta opción nos permite especificar si el montaje será de tipo bind, volume o tmpfs. El tipo tmpfs nos permite crear un volumen en la memoria asignada al contenedor, lo cual está indicado para aquellos datos temporales que no queremos o no es necesario que tengan persistencia. 
  • Origen del montaje, con la opción source. Para volúmenes con un nombre determinado, este campo contendrá el nombre del volumen. Si no especificamos un nombre se creará un volumen anónimo.
  • Ruta o punto de montaje, con la opción destination. Con esta opción especificaremos el punto de montaje dentro del contenedor.
  • Resto de opciones, especificadas como volume-opt, que nos permitirán especificar opciones adicionales de configuración.
Recordando el post sobre Trident, creamos un servicio montando un volumen y especificando un driver, del siguiente modo:

Especificamos un volumen en la creación de un servicio.
Vamos a revisarlo más detenidamente, definiendo un servicio simple que incluya volúmenes y modificando un servicio ya existente añadiendo o eliminando volúmenes.

Empezando por la parte más sencilla, con el subcomando volume de docker podemos controlar los volúmenes de nuestro cluster swarm, o de dockerhosts individuales. Las opciones disponibles del comando docker volume son las siguientes:

Opciones disponibles del comando docker volume.
Si usamos el comando docker volume sin ninguna opción, el driver utilizado será local, es decir las operaciones se realizarán sobre volúmenes locales del dockerhost sobre el que estemos operando. Por ejemplo, podemos crear un volumen en un solo dockerhost: 

Creación de un volumen local en un dockerhost.
Tambien podemos crear un volumen, con el mismo nombre, en cada uno de los dockerhost que forman parte del swarm:

Creación de un volumen local en los nodos de un swarm.
De la salida del comando docker volume ls vemos que, la primera columna indica que el driver utilizado es local. Esto indica que ese volumen solo existe en el dockerhost y por tanto, los datos que un servicio o contenedor genere y almacene en dicho volumen solo estarán disponibles en dicho dockerhost.

Los volúmenes creados con el driver local se crearán siempre en la ruta /var/lib/docker/volumes, lo cual podemos comprobar usando el comando docker volume inspect:

Obteniendo la información de un volumen.
Como es lógico, podemos cambiar esta ruta especificando la opción --data-root en el arranque del demonio dockerd.

Ahora que hemos creado un volumen común a todos los dockerhosts del swarm, podemos arrancar un servicio simple que use dicho volumen, especificándolo con --mount, mediante el comando siguiente:

Creación de un servicio con un volumen local.
De esta manera, al crear el servicio sin especificar un driver, docker usará el driver local y buscará un volumen con el nombre especificado en el dockerhost para montarlo en los contenedores. En caso de especificar un volumen que no exista, el volumen se creará con el nombre especificado o, si no especificamos un nombre, se creará un volumen anónimo:

Creación de un servicio con múltiples volúmenes.
Al listar los volúmenes disponibles en cada uno de los dockerhosts del swarm, vemos que se ha creado el volumen VOL_logs_swarm que no existía antes y dos volúmenes anónimos, uno se corresponde con el volumen para la ruta especificada /WWW_tmp y el otro volumen anónimo es para el volumen indicado en la definición de la imagen usada, que en este caso  se monta en /WWW.

Volúmenes creados para el servicio.
Por tanto, docker nos permitirá crear los volúmenes o los creará en caso de ser necesario, ya que como vemos se crea un volumen anónimo cada vez que lanzamos un contenedor a partir de una imagen que incluye volúmenes en su configuración.

Cuando queramos eliminar volúmenes que ya no se usen, podremos usar el comando docker volume prune, lo cual los eliminará. Como es lógico, al no especificar el driver, esto solo se aplicará a los volúmenes locales:

Eliminamos los volúmenes no usados. En este caso son volúmenes locales.
Ahora, usando plugins específicos para la creación de volúmenes para nuestros servicios, como por ejemplo el driver Trident para interactuar con sistemas NetApp, podemos crear un servicio que utilice volúmenes de datos comunes proporcionados por una SVM y volúmenes locales para datos temporales que no necesitamos que se mantengan:

Creación de un servicio con volúmenes desde una SVM.
En este ejemplo creamos un servicio que usa un volumen ya existente en la SVM (swarm_HTML), otro volumen que no existe y que el driver creará por nosotros (swarm_LOG) y un volumen local que tampoco existía con anterioridad (LOCAL_tmp) y que Docker creará en cada dockerhost:

El volumen VOL_swarm_LOG lo creará Trident al crear el servicio.

Lista de volúmenes existentes en nuestro swarm.
Por tanto podemos combinar volúmenes de diferentes poveedores en el mismo servicio con solo especificar el driver correcto para cada uno de ellos. Podemos comprobar los volúmenes en uso por el servicio usando el comando docker service inspect:

Lista de volúmenes en uso por el servicio.
En caso de ser necesario podemos actualizar la configuración del servicio y añadir o quitar volúmenes, mediante la opción --mount-rm del comando docker service update. Por ejemplo, si ncesitamos eliminar el volumen local, podemos hacer lo siguiente:

Eliminamos un volúmen de un servicio.
Con lo que ahora, al inspeccionar el servicio, vemos que solo está usando los volúmenes proporcionado por la SVM del sistema NetApp:

El servicio ahora usa solo dos volúmenes, dados por el driver Trident.
Para aplicar este update, como vemos en la salida siguiente, Docker ha parado cada contenedor del servicio y lo ha vuelto a arrancar con la nueva configuración:

Contenedores arrancados con la nueva configuración de volúmenes.
Por tanto y para terminar, hemos visto como Docker nos permite gestionar los volúmenes necesarios para nuestros contenedores o servicios y su integración con proveedores de almacenamiento como NetApp. Como siempre, para una información mucho más detallada, os recomiendo consultar la documentación oficial de Docker.

sábado, 5 de enero de 2019

Usando plugins en Docker - NetApp Trident

Hoy vamos a estudiar cómo podemos extender las funcionalidades de Docker mediante el uso de plugins.

Docker y por tanto Docker Swarm, al igual que orquestadores como Kubernetes o Rancher, permite el uso de plugins o módulos adicionales que nos permitirán la integración de nuestra infraestructura de contenedores con otros servicios o añadirán funcionalidades adicionales. Estos plugins, disponibles en Docker Hub, nos permiten integrar nuestros dockerhosts con sistemas de almacenamiento, añadir funcionalidades de logging o extender las capacidades de red.

Para estudiar el funcionamiento del sistema de plugins de Docker, voy a centrarme en el plugin Trident desarrollado por NetApp, que nos permite administrar y montar volúenes alojados y servidos por sistemas NetApp en nuestros dockerhosts.

Plugin Trident de NetApp disponible en Docker Hub.
En la página del plugin en Docker Hub tenemos disponible la descripción del plugin así como las instrucciones de instalación del mismo, pero es recomendable seguir las instrucciones de configuración oficiales dadas en el siguiente enlace.

En resumen, para usar este plugin debemos realizar los siguientes pasos:
  1. Debemos crear el fichero de configuración en todos los dockerhosts que vayamos a integrar con nuestros sistemas NetApp.
  2. Crearemos una o más SVMs que proporcionarán los servicios de bloque o fichero necesarios. Es muy importante que dichas SVMs tengan asignado uno o más agregados para la creación de volúmenes.
  3. Creamos un rol y un usuario específico para el uso del plugin en cada una de las SVMs que vayan a proporcionar servicio a nuestros dockerhosts.
  4. Por último instalamos el plugin en todos nuestros dockerhosts.
Empecemos por el fichero de configuración, como indica la documentación este fichero debe estar en la ruta /etc/netappdvp y es un fichero JSON cuyo nombre por defecto será config.json. Una configuración simple del fichero, para un entorno NAS, podría ser:

Fichero de configuración de Trident.
En esta configuración estoy especificando:
  • Los parámetros managementLIF y dataLIF contienen el nombre DNS o dirección IP de las LIF de gestión y datos de la SVM para esta instanacia de configuración.
  • El parámetro svm indica el nombre de la SVM que estamos usando, siendo username y password las credenciales del usuario que usaremos para interactuar con dicha SVM.
  • La sección default establece una serie de valores por defecto para la creación de nuestros volúmenes desde los dockerhosts. En este ejemplo establecemos la política de snapshots así como la política de exportación de volúmenes, el tamaño de los volúmenes creados, el tipo de seguridad y la reserva de espacio para snapshots.
En caso de cambiar la configuración de Trident, será necesario reiniciar el plugin con los comandos docker plugin disable y docker plugin enable.
 
Creamos una SVM con el mismo nombre que el que indicamos en el fichero de configuración, así como el rol con los permisos adecuados que luego asignaremos al usuario que tabién vamos a crear. Los permisos necesarios para el rol son los siguientes:

Creación del rol necesario para el plugin.
Creamos el usuario y le asignamos el rol que acabamos de crear, es importante que establezcamos como tipo de aplicación a usar por el usuario ontapi:

Creación del usuario y asignación del rol.
Ahora ya podemos instalar el plugin en todos nuestros dockerhosts, siendo la salida de la instalación como la siguiente:

Instalación del plugin Trident en los dockerhosts.
El plugin ya instalado y disponible.
Una vez instalado el plugin, al estar habilitado, el demonio docker se encargará de arrancarlo cada vez que iniciemos el sistema. Podemos comprobarlo viendo los procesos de cada uno de nuestros dockerhosts:
Procesos del plugin Trident.
En caso de ser necesario, podemos parar el plugin usando el comando docker plugin del siguiente modo:

Parando el plugin Trident en un dockerhost.

Como ya he comentado la SVM debe tener agregados asignados a ella para permitir la creación de volúmenes desde el plugin. En caso de no ser así recibiríamos un error como el siguiente:

Error cuando la SVM no tiene agregados asignados.
Desde OnCommand System Manager podemos asignar de forma muy rápida y simple los agregados a la SVM con solo editarla desde el apartado SVMs:

Asignamos un agregado a nuestra SVM para el usuao de Trident.
Lo primero que podemos hacer es crear los volúmenes que vayamos a necesitar usando el comando docker volume. Como es lógico esto solo lo haremos desde uno de nuestros dockerhosts, así que como ejemplo creamos varios volúmenes desde diferentes dockerhosts:

Creamos varios volúmenes usando el plugin Trident.
Comprobamos que los nuevos volúmenes existen en el agregado.
Es muy importante que nos demos cuenta que al delegar un agregado a la SVM como hemos hecho, el usuario que utilicemos tiene control total sobre los volúmenes que existan en dicho agregado. Por tanto, si el agregado está compartido con más clientes, es posible borrar el resto de volúmenes con los comandos de gestión de volúmenes de Docker a través de Trident, siempre y cuando todos los volúmenes de dicho agregado contengan el mismo prefijo que hemos establecido en la configuación del plugin. Por ejemplo, si listamos los volúmenes disponibles vemos que aparece uno que no hemos creado con Trident:

Listado de volúmenes disponibles.
Para evitar problemas, si es necesario que diferentes cliente compartan el mismo agregado, lo mejor es que los volúmenes controlados por Trident utilicen un prefijo distinto al del resto de volúmenes del agregado.
 
Una vez creados los volúmenes, podemos pasar a usarlos montándolos cuando despleguemos un contenedor o un servicio en nuestro swarm:

Creación de un servicio replicado con un volumen.
El comando anterior utiliza la sintaxis mount para el montaje de volúmenes, esta sintaxis está disponible desde la versión 17.06 de Docker para contenedores standalone y no solo para swarm. En próximas entradas explicaré más detalladamente como utilizarla y sus diversas opciones, por ahora quedémonos en que vamos a montar un volumen controlado por el plugin Trident.
 
Al ejecutar el comando anterior, swarm orquesta el montaje del volúmen especificado en los hosts en los que se despliegue un contenedor que lo necesite, con lo que, de forma automática montará por NFS el volumen swarm_HTML que hemos creado anteriormente y que está sirviendo nuestra SVM. Esto lo podemos comprobar del siguiente modo:

Escalamos el servicio a 3 réplicas.
Ahora el contenedor solo está corriendo en tres de los dockerhosts que forman el swarm, con lo que el volumen necesario solo está montado en dichos hosts como podemos ver:

Docker Swarm ha montado el volumen en los hoosts necesarios.
Si ahora escalamos de nuevo el servicio, comprobaremos que se montará el volumen en el nodo swarm-nodo2 para poder levantar correctamente el contenedor con el volumen requerido:

Docker Swarm monta el volumen en el nodo restante.
Como es lógico, al borrar el servicio, el volumen se desmontará de todos los nodos si ningún otro servicio lo está utilizando.

Por tanto, y en resumen, hemos visto como Docker Swarm es capaz de orquestar perfectamente el montaje de volúmenes externos, en este caso controlados por el plugin Trident de NetApp y como este plugin nos permite integrar nuestra infraestructura de contenedores basada en Docker con los sistemas de almacenamiento NetApp. Además hemos podido comprobar como expandir las funcionalidades de Docker mediante el uso de plugins.

Como es lógico este plugin también está disponible para Kubernetes, el cual espero poder estudiar dentro de un tiempo y repasar su funcionamiento.

En próximas entradas, repasaré las opciones disponibles para la gestión y uso de volúmenes en servicios implementados en Docker Swarm con la opción mount.

viernes, 7 de diciembre de 2018

Administración de Docker swarm con Rancher

Hoy continuamos explorando Docker swarm pero, para variar un poco, vamos a instalar Rancher para crear y administrar un swarm de dockerhosts así como para explorar las funcionalidades que puede aportar a nuestros despliegues de Docker swarm.

¿Que es Rancher? es una plataforma de gestión de contenedores que nos permite su despliegue y control en cualquier entorno, desde nuestros propios servidores, ya sean físicos o virtuales o en entornos cloud. Además proporciona una gran cantidad de funcionalidades adicionales que pueden ser desplegadas desde diferentes catálogos, lo que permite añadir nuevas herramientas a nuestros despliegues de forma rápida y sencilla.

De forma muy resumida, la unidad de trabajo básica de Rancher es el entorno, cada uno de los cuales puede utilizar un tipo de orquestación y que contendrá los hosts asociados a dicho entorno. Como siempre, para una información más detallada y mucho mejor que esta, os recomiendo visitar la página oficial de Rancher.

Después de un poco de rollo teórico vamos a instalar Rancher, para lo cual he seguido las instrucciones de instalación dadas en esta página para un entorno multinodo, en el cual he desplegado cuatro máquinas virtuales, siendo una de ellas el servidor de base de datos y las otras tres los nodos donde he instalado Docker.

Para comenzar la instalación, solo necesitamos lanzar el siguiente comando en al menos uno de los hosts:
Instalación del nodo servidor de Rancher.
Como es lógico este comando descargará la imagen de correspondiente de Docker Hub y creará un contenedor para nuestro servidor Rancher, el cual conectará con el servidor de base de datos indicado en los parámetros del comando docker run. Tras ejecutar el comando anterior podemos comprobar que hay un contenedor en nuestro host que se corresponde con el servidor Rancher:

Host con el contenedor del servidor Rancher.






A continuación ya podremos acceder a la consola de administración de Rancher, con lo que solo necesitamos lanzar un navegador y acceder al puerto 8080 del host donde hemos lanzado el contenedor del servidor Rancher. Al acceder por primera vez a la consola nos encontraremos con una imagen como la siguiente:

Conosla de administración de Rancher.
En este punto, lo primero es configurar el control de acceso a la consola y configurar el método de autenticación que vayamos a utilizar. En nuestro ejemplo, usaremos autenticación local por sencillez. Para configurar el control de acceso solo tenemos que acceder a la sección Access Control dentro del menú ADMIN y crear la cuenta de usuario con derechos de administración que vayamos a utilizar:

Configuración del control de acceso a la consola de Rancher.
A continuación debemos crear un nuevo entorno usando la plantilla disponible para Docker swarm. Para crearlo solo es necesario pinchar sobre el botón Add Environment desde la sección Manage Environments del menú Default, que nos indica cual es el entorno que estamos gestionando:

Ventana para la gestión de entornos en Rancher.
Creación de un entorno Docker Swarm
Tras crearlo, ahora veremos nuestros dos entornos disponibles en la ventana de gestión de entornos y que el entorno por defecto es el entorno llamado Default:

Entornos disponibles tras la creación del entorno para Swarm.
Ambos entornos se encuentran en estado Unhealthy ya que no hemos añadido hosts a ninguno de ellos. Por tanto, el siguiente paso consiste en añadir hosts a la infraestructura de nuestro nuevo entorno, para ello solo tenemos que cambiar al entorno Swarm test lab y acceder a la sección Hosts del menú INFRASTRUCTURE para añadir nuestros dockerhosts. El proceso, muy resumido, podemos verlo en las siguientes imágenes:


Definición de la infraestructura para establecer nuestro Swarm. Rancher indica que debemos añadir hosts.
Añadimos un dockerhost a la infraestructura de nuestro entorno Docker Swarm.
En la pantalla para añadir un nuevo host a la infraestructura, es recomendable incluir la dirección IP del host para asegurar que no haya problemas de comunicación, sobre todo al registrar el dockerhost que contiene el propio servidor de Rancher.

Es muy importante recordar que estamos creando un swarm con varios dockerhosts, con lo que es necesario que creemos las reglas necesarias en los firewalls de cada nodo para asegurar el correcto funcionamiento del swarm. Relacionado con esta correcta configuración del cortafuegos de los dockerhosts, un punto importante a tener en cuenta para registrar correctamente el dockerhost donde se está ejecutando el contenedor con el servidor Rancher, es que debemos añadir el interfaz docker0 a la zona trusted del firewall o bien definir las reglas correspondientes para permitir las conexiones a la dirección IP física del host teniendo en cuenta el interfaz docker0 y las conexiones salientes desde el contenedor agente.

Una vez que hayamos realizado los pasos anteriores para todos nuestros nodos virtuales, incluyendo el dockerhost en el que se encuentra el propio servidor de Rancher, la infraestructura de nuestro entorno será similar a la siguiente:

Infraestructura de nuestro entorno Docker swarm con tres dockerhosts.

Revisando la imagen anterior, ¿que es lo que ha hecho Rancher? Pues como vemos ha creado un swarm en el que todos los hosts tiene el rol de manager y ha desplegado en ellos una serie de contenedores que implementan los servicios de infraestructura necesarios. Desde el menú SWARM podremos comprobar que el estado de toda la infraestructura del entorno es correcta:

Infraestructura del entorno swarm.
Servicios de infraestructura desplegado por Rancher en el swarm.
Como veremos en entradas futuras sobre Rancher, cada uno de estos servicios de infraestructura desempeñan una función determinada para el correcto funcionamiento de nuestro entorno y Rancher los implementa mediante un contenedor dedicado en cada dockehost.

En este punto tenemos un swarm el cual está controlado por Rancher, con lo que el siguiente paso es desplegar un servicio simple. Para esto, basta con acceder a la sección Containers del menú INFRASTRUCTURE y pinchar sobre Add Container:

Apartado contenedores del entorno docker swarm.
Al crear un contenedor a partir de una imagen, nos encontramos con todas las opciones disponibles en línea de comandos cuando estamos administrando Docker. Así, para nuestro ejemplo tenemos lo siguiente:

Definición de parámetros de configuración de un contenedor.
Como vemos, en las diferentes pestañas tenemos las opciones de configuración disponibles para nuestro contenedor. Estableciendo una configuración básica para nuestro ejemplo y pinchando sobre el botón Create se seguirá el proceso de descargar la imagen de Docker Hub y crear el contenedor con la configuración que hemos especificado. Una vez creado Rancher nos mostrará las estadísticas de rendimiento del contenedor así como sus parámetros de configuración:

Estadísticas de uso de nuestro contenedor.
Este contenedor no lo hemos definido como un servicio y por tanto, solo será accesible desde el nodo en el cual se esté ejecutando. Para crear un servicio debemos crear un stack, para lo cual debemos definir un archivo docker-compose.yaml que contenga la descripción de nuestro servicio o bien, usar uno de los servicios de infraestructura que Rancher ha desplegado al crear nuestro swarm. Este servicio de infraestructura se llama Portainer y se encuentra disponible en el menú SWARM:

Acceso a Portainer desde el menú SWARM.
Pantalla de acceso al interfaz de administración Portainer.
Portainer es un interfaz gráfico que nos permite administrar entornos Docker y está incluido como uno de los servicios de infraestructura desplegados por Rancher. Una vez que accedemos al interfaz de portainer, la consola de administración es como podemos ver en la siguiente imagen:
Interfaz de administración de Portainer.
Usando Portainer, podemos desplegar un servicio de forma muy sencilla desde el apartado Services con solo especificar los parámetros de configuración necesarios para nuestro servicio:

Creación de un servicio desde Portainer.
Panel de control de los servicios desplegados.
Ahora desde el interfaz de Rancher, en la sección Containers de nuestra infraestructura vemos los contenedores que están ejecutándose:

Los contenedores de nuestro servicio vistos desde Rancher.
Por tanto, y en resumen, podemos crear y gestionar nuestros entornos Docker Swarm desde Rancher y lo más importante es que añade nuevas funcionalidades gracias a los servicios de infraestructura que despliega. 

Adicionalment nos permite tener un análisis de uso de los contenedores de nuestros servicios y controlarlos directamente, aunque desde mi punto de vista lo recomendable es que usemos Portainer directamente ya que nos da acceso a las acciones de servicio.

En las próximas entradas sobre Docker Swarm y Rancher desplegaremos servicios, describiéndolos con los ficheros compose correspondientes e investigaremos los servicios de infraestructura disponibles y como podemos utilizarlos.

NOTA IMPORTANTE: Es necesario establecer el parámetro de configuración max_allowed_packet de nuestra base de datos, si usamos MySQL o MariaDB, en al menos 32M para que Rancher pueda refrescar correctamente el catálogo de plugins y plantillas de los repositorios de Rancher.