En la Parte 1, puse en práctica servicios en mi clúster ODROID-C2 utilizando la línea de comando Docker. Funciona, pero debería haber una mejor forma de llevar a cabo la implementación, especialmente cuando una aplicación necesita varios componentes que trabajen conjuntamente. Docker 1.13.x ha introducido la nueva función de implementación de pila Docker que permite la utilización de una pila completa de aplicaciones en el Swarm. Una pila es un conjunto de servicios que componen una aplicación. Esta nueva función implementa automáticamente múltiples servicios que están vinculados entre sí, eliminando así la necesidad de definir cada uno por separado. En otras palabras, esto es docker-componer en modo swarm. Para hacer esto, tengo que actualizar mi Docker Engine V1.12.6 que instalé usando apt-get desde el repositorio de software de Ubuntu a la V1.13.x. Teniendo ya compilado la V1.13.1 en mi ODROID-C2 cuando experimentaba sin éxito con el modo swarm hace algunos meses, tal y como comenté en mi anterior artículo, sólo es cuestión de actualizar todos mis nodos ODROID-C2 a la V1.13.1 y estaré listo para trabajar.
La pila httpd-visualizer
Lo primero que hice fue utilizar las mismas aplicaciones (httpd y Visualizer) que en mi anterior artículo usando 'docker stack deploy’. Para hacer esto, necesitaba crear un archivo yaml. En realidad esta es la versión “3” del archivo yaml de docker-compose. Esto era relativamente fácil de hacer ya que no es necesaria la persistencia de datos. Aquí tienes el archivo yaml:
version: "3" services: httpd: # simple httpd demo image: mrdreambot/arm64-busybox-httpd deploy: replicas: 3 restart_policy: condition: on-failure resources: limits: cpus: "0.1" memory: 20M ports: - "80:80" networks: - httpd-net visualizer: image: mrdreambot/arm64-docker-swarm-visualizer ports: - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock" deploy: placement: constraints: [node.role == manager] networks: - httpd-net networks: httpd-net:Ten en cuenta que el uso de "Networks" en el archivo yaml no es estrictamente necesario. Si lo omitimos, dDocker creará una red de superposición por defecto como verás en una sección más adelante. ¡Las 2 aplicaciones, en este caso, no necesitan hablar entre ellas de todos modos! Para implementarlo, simplemente cambia al directorio donde se encuentra el archivo yaml y ejecuta el comando:
$ docker stack deploy -c simple-stacks.yml httpd-dsvEsto crea una pila llamada httpd-dsv. Puedes conocer el estado de la pila usando varios comandos de pila, tal y como se muestra en la Figura 1.
Puedes apuntar tu navegador al nodo gestor swarm o a cualquier otro nodo del swarm en el puerto 8080 para visualizar la implementación utilizando el Visualizer. La figura 2 muestra un pantallazo de la pantalla de VuShell con la visualización tomada de una implementación de pila anterior:
Para desmontar la pila, introduce el siguiente comando:
$ docker stack rm httpd-dsv
Migrando mi blog de WordPress a swarm
Para hacer un ejemplo más realista de una implementación de pila, he decidido realizar una prueba migrando mi blog al swarm. Esto es muy útil para mí, ya que me permite iniciar mi blog fácilmente en otro entorno cuando ocurre un desastre. Para hacer esto, tenía que preparar unas cuantas cosas:
- Crear una copia de la base de datos de WordPress usando mysqldump para crear: mysql.dmp.
- Utilizar un editor de texto para reemplazar todas las referencias de mi dominio (mrdreambot.ddns.net) en el archivo .dmp por la dirección IP del gestor swarm que es 192.168.1.100.
- Hacer una copia (comandos Tar) del directorio /var/www/html que contiene scripts y recursos cargados
- Elegir las imágenes de docker a utilizar: mrdreambot/arm64-mysql y arm64v8/wordpress.
- Con todo lo anterior, podía crear una implementación de pila docker para mi blog de WordPress.
Estado de persistencia utilizando volúmenes
bind-mount
El primer método por el que opte fue el de usar directorios del host como volúmenes de datos (también llamados volúmenes bind-mount) para la persistencia de datos. El contenido del archivo yaml se muestra a continuación:
version: '3' services: db: image: mrdreambot/arm64-mysql volumes: - /nfs/common/services/wordpress/db_data:/u01/my3306/data - /nfs/common/services/wordpress/db_root:/root environment: MYSQL_ROOT_PASSWORD: Password456 MYSQL_DATABASE: wordpress MYSQL_USER: wordpressuser MYSQL_PASSWORD: Password456 deploy: restart_policy: condition: on-failure placement: constraints: [node.role == manager] wordpress: depends_on: - db image: arm64v8/wordpress volumes: - /nfs/common/services/wordpress/www_src/html:/usr/src/wordpress - /nfs/common/services/wordpress/www_data:/var/www/html ports: - 80:80 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpressuser WORDPRESS_DB_PASSWORD: Password456 WORDPRESS_DB_NAME: wordpress deploy: replicas: 3 restart_policy: condition: on-failure placement: constraints: [node.role == manager]Las figuras 3 y 4 muestran las capturas de pantalla para la implementación de la pila.
Posiblemente habrás notado que el sitio de WordPress ha perdido parte de su apariencia personalizada, ya que la imagen del docker arm64v8/wordpress no ofrece ninguna librería o personalización PHP. Como he comentado anteriormente, si no defines las Redes en tu archivo yaml, docker crea automáticamente una red de superposición 'wordpress_default' para la puesta en funcionamiento automática. La red de superposición es necesaria para que WordPress pueda hacer referencia a la base de datos MySQL utilizando su nombre "db" tal y como se define en el archivo yaml:
WORDPRESS_DB_HOST: db: 3306Los volúmenes de datos justifican ciertas explicaciones. Lo primero a tener en cuenta es que todos los directorios de host utilizados como volúmenes de datos están montados en NFS y accesibles a todos los nodos del swarm.
/nfs/common/services/wordpress/db_data:/u01/my3306/data
El directorio de host /nfs/common/services/wordpress/db_data es un directorio vacío. Es el equivalente al directorio del contenedor /u01/my3306/data donde se encuentra la base de datos MySQL. A continuación, se describe como se crea su contenido.
/nfs/common/services/wordpress/db_root:/root
He completado previamente el directorio del host /nfs/common/services/wordpress/db_root con 2 archivos:
- run.sh: el script de inicio de MySQL que reemplaza al que se encuentra en el directorio /root del contenedor. Este script es el punto de entrada al contenedor MySQL. Cambié el script para buscar el archivo mysql.dmp ubicado también en /root. Si está, importa el archivo de copia en MySQL que completará el directorio /u01/my3306/data con los datos. Si no hay un archivo mysql.dmp, no se hace nada adicional al proceso habitual.
- mysql.dmp: el archivo de volcado de la base de datos MySQL de mi blog
Los cambios en el archivo run.sh en comparación con el que viene con la imagen docker MySQL se muestran a continuación:
... DMP_FILE=/root/mysql.dmp ... if [ "$MYSQL_DATABASE" ]; then mysql -uroot -e "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\`" if [ -f "$DMP_FILE" ]; then mysql -uroot $MYSQL_DATABASE < $DMP_FILE fi fi ...Ten en cuenta que esto sólo es necesario cuando ejecutas el contenedor por primera vez. La implementación posterior no requerirá de esta distribución de volúmenes ya que la base de datos ha sido configurada durante la primera ejecución. Esto significa que puede comentar esta línea en el archivo yaml tras haber implementado correctamente una vez esta pila:
# - /nfs/common/services/wordpress/db_root:/root
/nfs/common/services/wordpress/www_src/html:/usr/src/wordpress
arm64v8/wordpress activa WordPress copiando los contenidos en su directorio /usr/src/wordpress al directorio /var/www/html en el arranque si /var/www/html no tiene contenido. Al rellenar previamente el directorio del host /nfs/common/services/wordpress/www_src /html con el contenido del archivo tar creado anteriormente, arm64v8/wordpress iniciará WordPress con el contenido de mi blog. Esto solo es necesario cuando ejecutes el contenedor por primera vez. Esto significa que puede comentar esta línea en el archivo yaml tras haber implementado correctamente esta pila una vez:
# - /nfs/common/services/wordpress/www_src/html:/usr/src/wordpress
/nfs/common/services/wordpress/www_data:/var/www/html
El directorio de host /nfs/common/services/wordpress/www_data es un directorio vacío cuyo contenido se activará mediante el script arm64v8/wordpress tal y como se ha descrito anteriormente.
¿Por qué no usar docker-componer?
Es posible que te pregunte por qué no utilice docker-compose para ejecutar el archivo yaml, por ejemplo, usando comandos de una sola vez como sugiere la documentación de docker. La razón es que el docker-compose que instalé usando apt-get es la versión 1.8.0, que no entiende la versión 3 del archivo yaml del docker-compose, que es necesario para "docker stack deploy". Intenté compilar la última versión de docker-compose desde la fuente pero no tuve éxito. Esta es la razón por la que no estoy usando docker-componer.
Persistencia del estado usando volúmenes de almacenamiento compartido
El uso de volúmenes bind-mount depende del host. El uso de volúmenes compartidos tiene la ventaja de ser independientes del host. Puede haber un volumen compartido disponible en cualquier host en el que se inicie un contenedor siempre que tenga acceso al back-end del almacenamiento compartido y tenga instalado el plugin (controlador) del volumen adecuado, el cual te permita usar diferentes back-end de almacenamiento, como, por ejemplo: Amazon EC2, GCE, Isilon, ScaleIO, Glusterfs, solo por nombrar unos cuantos. Existes muchos drivers o plugins de volumen disponibles como Flocker, Rex-Ray, etc. Desafortunadamente, no hay binarios para esos complementos disponibles para máquinas ARM64 como ODROID-C2. Afortunadamente, el driver 'local' integrado soporta NFS. Es el driver que yo estoy usando para la implementación de volumen compartido. El archivo yaml para esto es el siguiente:
version: '3' services: db: image: mrdreambot/arm64-mysql volumes: - db_data:/u01/my3306/data # - /nfs/common/services/wordpress/db_root:/root environment: MYSQL_ROOT_PASSWORD: Password456 MYSQL_DATABASE: wordpress MYSQL_USER: wordpressuser MYSQL_PASSWORD: Password456 deploy: placement: constraints: [node.role == manager] replicas: 1 restart_policy: condition: on-failure wordpress: depends_on: - db image: arm64v8/wordpress volumes: # - /nfs/common/services/wordpress/www_src/html:/usr/src/wordpress - www_html:/var/www/html ports: - "80:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpressuser WORDPRESS_DB_PASSWORD: Password456 WORDPRESS_DB_NAME: wordpress deploy: # placement: # constraints: [node.role == manager] replicas: 3 restart_policy: condition: on-failure volumes: db_data: external: name: db_data www_html: external: name: www_htmlUna vez más, los volúmenes justifican alguna explicación:
/nfs/common/services/wordpress/db_root:/root
Sirve para el mismo propósito que en el caso del volumen bind-mount. Solo es necesario cuando ejecutas la pila por primera vez para iniciar la base de datos MySQL.
/nfs/common/services/wordpress/www_src/html:/usr/src/wordpress
Sirve para el mismo propósito que en el caso del volumen bind-mount. Solo es necesario cuando ejecutas la pila por primera vez para iniciar el contenido de WordPress.
db_data:/u01/my3306/data
db_data es un volumen compartido creado fuera de la implementación de la pila, lo que significa que es creado antes de que llegue a usarse el archivo yaml. Se utiliza para almacenar el contenido de la base de datos MySQL y no se activa en la creación.
www_html:/var/www/html
www_html es un volumen compartido creado fuera de la implementación de la pila, lo que significa que es creado antes de que llegue a utilizarse el archivo yaml. Se utiliza para almacenar el contenido de WordPress y no se activa en la creación.
Creando los volúmenes compartidos
Probablemente hayas observado una sección en el archivo yaml que dice:
volumes: db_data: external: name: db_data www_html: external: name: www_htmlLos volúmenes compartidos db_data y www_html se crean utilizando los siguientes comandos:
docker volume create --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.100,rw \ --opt device=:/media/sata/nfsshare/www_html \ www_html docker volume create --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.100,rw \ --opt device=:/media/sata/nfsshare/db_data \ db_dataLos directorios /media/sata/nfsshare/db_data y /media/sata/nfsshare/www_htm deben existir antes de crear los volúmenes. Mi archivo /etc/exports tiene una entrada:
/media/sata/nfsshare 192.168.1.0/255.255.255.0(rw,sync,no_root_squash,no_subtree_check,fsid=0)Para probar que los volúmenes compartidos funcionan, inicialmente implementé solo 1 réplica de mySQL y 1 de WordPress en el gestor de Docker y les permití iniciar los volúmenes compartidos.
Luego comenté las 2 líneas de la ubicación del WordPress:
# placement: # constraints: [node.role == manager]y los 2 volúmenes bind-mount
# - /nfs/common/services/wordpress/db_root:/root # - /nfs/common/services/wordpress/www_src/html:/usr/src/wordpressDespués, quise implementar 3 réplicas de WordPress en varios nodos. Como estamos usando el driver "local", debemos crear los volúmenes en cada nodo. Tal y como se muestra en la Figura 5, usé "parallel ssh" para crearlos en todos los nodos usando solo 2 comandos. La figura 5 muestra el volumen y la implementación de la pila:
Verifiqué que todas las réplicas estuvieran usando los volúmenes compartidos utilizando "docker exec -it" para acceder a los contenedores de WordPress en los nodos en los que se estaban ejecutando y examiné el contenido del directorio /var/www/html para verificar que todo funcionaba correctamente.
En el fondo, ambos planteamientos usan NFS para compartir entre los nodos. Sin embargo, los volúmenes compartidos proporcionan una abstracción independiente del host de mayor nivel que los volúmenes bind-mount. Potencialmente, puedes volver a crear los volúmenes compartidos utilizando backends de almacenamiento distintos de NFS, como AWS EC2 y Glusterfs. Bind-mount, por otro lado, está vinculado a tu sistema de archivos del host, que puede ser difícil de migrar a otro entorno.
Conclusion
Aprendí algo nuevo explorando el uso de la denominada "implementación de pila docker". Espero que encuentres útil e informativo este artículo. Todavía hay muchas características, como las actualizaciones sucesivas, la Implementación continua/Integración continua (CI / CD), las implementaciones A/B y azul/verde, solo por nombrar unas cuantas, que aún no he explorado con mi clúster ODROID-C2 Swarm. Además, existen otros entornos de trabajo de planificación de servicios como Kubernetes y Openshift que son más frecuentes en el entorno empresarial que en el modo Docker Swarm. Exploraré otros usos del modo Swarm de Docker y alternativas al modo Swarm e informaré de mis hallazgos en el futuro cuando surja la oportunidad.
Be the first to comment