Docker Swarm: Crear Cluster Debian
Hoy os voy a enseñar a montar un clúster con Docker Swarm en servidores Debian. Personalmente, si os queréis introducir en los clústeres de contenedores o containers, lo recomiendo para empezar antes que Kubernetes, por su facilidad de creación.
¿Qué es Docker Swarm?
Para los que no conocéis este proyecto, sería algo así como la equivalencia de Kubernetes creada por los desarrolladores de Docker. De forma que puedas gestionar varios hosts de Docker sobre una gestión centralizada.
En un principio, se instalaba como un componente a parte, pero desde la versión 1.11 de Docker ya se dispone de un modo nativo Swarm (también conocido como modo enjambre), simplemente instalando Docker Engine.
Al final es una arquitectura como Kubernetes, maestro-esclavo. Con un nodo maestro o máster como mínimo. Como en Kubernetes, el maestro es responsable de la gestión del propio clúster y repartir las tareas, y el resto de nodos, llamados esclavos o workers, ejecutan las tareas.
Instalación Docker Swarm sobre Debian 10.8
Lo voy a crear bajo la plataforma de Proxmox, sobre 3 máquinas virtuales. Una máquina se comportará de master y las otras dos de workers sobre Debian 10.8, que es la última versión disponible.
Nos conectamos al master por SSH y cambiamos a root, lanzaremos un upgrade de los paquetes. Repetimos esto en los workers:
1 2 3 |
raulunzue@swarm00:~$ su - Contraseña: root@swarm00:~# apt-get update -y && apt-get upgrade -y |
Instalamos las dependencias en cada nodo(master y workers):
1 |
apt-get install apt-transport-https ca-certificates curl gnupg lsb-release -y |
Añadimos la GPG key de Docker (master y workers):
1 |
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg |
Agregamos los repositorios de Docker (master y workers):
1 2 3 4 |
echo \ "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update |
Instalamos Docker engine (master y workers):
1 |
apt-get install docker-ce docker-ce-cli containerd.io |
Probamos que funciona correctamente creando contenedor (master y workers):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
root@swarm00:~# docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world b8dfde127a29: Pull complete Digest: sha256:308866a43596e83578c7dfa15e27a73011bdd402185a84c5cd7f32a88b501a24 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/ |
Como hemos dicho, podéis comprobar que swarm viene integrado en las nuevas versiones:
1 2 |
root@swarm00:~# docker s save search secret service stack start stats stop <strong>swarm</strong> system |
Nos aseguramos que el servicio de docker está corriendo y que cuando reinicie el sistema lo siga estando (master y workers):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
root@swarm00:~# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2021-03-20 11:56:10 CET; 10min ago Docs: https://docs.docker.com Main PID: 4951 (dockerd) Tasks: 14 Memory: 61.2M CGroup: /system.slice/docker.service └─4951 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock mar 20 11:56:09 swarm00 dockerd[4951]: time="2021-03-20T11:56:09.215190563+01:00" level=warning mar 20 11:56:09 swarm00 dockerd[4951]: time="2021-03-20T11:56:09.215226627+01:00" level=warning mar 20 11:56:09 swarm00 dockerd[4951]: time="2021-03-20T11:56:09.215386567+01:00" level=info ms mar 20 11:56:09 swarm00 dockerd[4951]: time="2021-03-20T11:56:09.804289464+01:00" level=info ms mar 20 11:56:10 swarm00 dockerd[4951]: time="2021-03-20T11:56:10.012816787+01:00" level=info ms mar 20 11:56:10 swarm00 dockerd[4951]: time="2021-03-20T11:56:10.102558629+01:00" level=info ms mar 20 11:56:10 swarm00 dockerd[4951]: time="2021-03-20T11:56:10.102680285+01:00" level=info ms mar 20 11:56:10 swarm00 systemd[1]: Started Docker Application Container Engine. mar 20 11:56:10 swarm00 dockerd[4951]: time="2021-03-20T11:56:10.192073309+01:00" level=info ms mar 20 11:57:57 swarm00 dockerd[4951]: time="2021-03-20T11:57:57.242753638+01:00" level=info ms lines 1-20/20 (END) root@swarm00:~# systemctl enable docker Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable docker |
Nos aseguramos que el grupo de docker existe y agregamos el usuario docker (master y workers):
1 |
groupadd docker && usermod -aG docker dockeruser |
Voy a instalar ufw para gestionar el firewall (master y workers):
1 |
apt install ufw |
Y modificamos los puertos de firewall necesarios para docker swarm (master y workers):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
ufw allow 2376/tcp && ufw allow 7946/udp && ufw allow 7946/tcp && ufw allow 80/tcp && ufw allow 2377/tcp && ufw allow 4789/udp Rules updated Rules updated (v6) Rules updated Rules updated (v6) Rules updated Rules updated (v6) Rules updated Rules updated (v6) Rules updated Rules updated (v6) Rules updated Rules updated (v6) |
Reiniciamos el servicio del firewall y habilitamos el servicio para que arranque en el inicio (master y workers):
1 2 3 4 |
ufw reload && ufw enable Firewall not enabled (skipping reload) Command may disrupt existing ssh connections. Proceed with operation (y|n)? y Firewall is active and enabled on system startup |
Reiniciamos el servicio de Docker (master y workers):
1 |
systemctl restart docker |
Crear cluster de Docker Swarm
Una vez preparado el sistema, ahora vamos al master para inicializar el clúster con el comando que representa a su IP y que pasaremos a los workers:
1 2 3 4 5 6 7 8 |
docker swarm init --advertise-addr 192.168.2.193 Swarm initialized: current node (wtxqaii96t7ofy2d6ep9wnf4l) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-69yuduvfy4iu4hjyk0k1r88mklfa7pqnebl7lsvvbkj36em256-d31jmz2tohlx4w9gl7jqor2gr 192.168.2.193:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. |
Y repetimos en los workers el comando que nos ha generado:
1 2 |
docker swarm join --token SWMTKN-1-69yuduvfy4iu4hjyk0k1r88mklfa7pqnebl7lsvvbkj36em256-d31jmz2tohlx4w9gl7jqor2gr 192.168.2.193:2377 This node joined a swarm as a worker. |
Ahora validamos en el master el estado:
1 2 3 4 5 |
root@swarm00:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION wtxqaii96t7ofy2d6ep9wnf4l * swarm00 Ready Active Leader 20.10.5 g2plw1serfi4psvls8szdofo0 swarmn01 Ready Active 20.10.5 1iy0jshekp2qgepehkn10r3rh swarmn02 Ready Active 20.10.5 |
Extraer info de cluster Docker Swarm
Ahora si queremos sacar la info del clúster simplemente podremos ver:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
docker info Client: Context: default Debug Mode: false Plugins: app: Docker App (Docker Inc., v0.9.1-beta3) buildx: Build with BuildKit (Docker Inc., v0.5.1-docker) Server: Containers: 1 Running: 0 Paused: 0 Stopped: 1 Images: 1 Server Version: 20.10.5 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Cgroup Version: 1 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: active NodeID: wtxqaii96t7ofy2d6ep9wnf4l Is Manager: true ClusterID: ol8ljnh62do5sbfxif56qej7b Managers: 1 Nodes: 3 Default Address Pool: 10.0.0.0/8 SubnetSize: 24 Data Path Port: 4789 Orchestration: Task History Retention Limit: 5 Raft: Snapshot Interval: 10000 Number of Old Snapshots to Retain: 0 Heartbeat Tick: 1 Election Tick: 10 Dispatcher: Heartbeat Period: 5 seconds CA Configuration: Expiry Duration: 3 months Force Rotate: 0 Autolock Managers: false Root Rotation In Progress: false Node Address: 192.168.2.193 Manager Addresses: 192.168.2.193:2377 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc Default Runtime: runc Init Binary: docker-init containerd version: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e runc version: 12644e614e25b05da6fd08a38ffa0cfe1903fdec init version: de40ad0 Security Options: apparmor seccomp Profile: default Kernel Version: 4.19.0-14-amd64 Operating System: Debian GNU/Linux 10 (buster) OSType: linux Architecture: x86_64 CPUs: 4 Total Memory: 3.854GiB Name: swarm00 ID: 3LU3:PAHA:NECV:MXXS:WKCD:UB3F:GCMP:YPV6:IKR3:76TL:LIWA:F26X Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false WARNING: No swap limit support |
Agregar o quitar workers y masters a Cluster Docker Swarm
Si el día de mañana tiene que crecer el clúster podéis utilizar este comando para agregar workers:
1 2 3 4 |
docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-69yuduvfy4iu4hjyk0k1r88mklfa7pqnebl7lsvvbkj36em256-d31jmz2tohlx4w9gl7jqor2gr 192.168.2.193:2377 |
Para agregar masters adicionales:
1 2 3 4 |
docker swarm join-token manager To add a manager to this swarm, run the following command: docker swarm join --token SWMTKN-1-69yuduvfy4iu4hjyk0k1r88mklfa7pqnebl7lsvvbkj36em256-7tghdbme2w6s4memljt18aquk 192.168.2.193:2377 |
Ejemplo web apache en cluster Docker Swarm
Para validar del todo el clúster haremos dos pruebas. Lanzar un apache como servicio:
1 2 3 4 5 |
docker service create --name appweb -p 80:80 httpd faz3ae23p4bns8de6r55k5jou overall progress: 1 out of 1 tasks 1/1: running verify: Service converged |
Y luego haremos un escalado:
1 2 3 4 5 6 7 8 |
docker service scale appweb=4 appweb scaled to 4 overall progress: 4 out of 4 tasks 1/4: running 2/4: running 3/4: running 4/4: running verify: Service converged |
Revisamos los servicios generados:
1 2 3 4 5 6 |
docker service ps appweb ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 0gi6faa0qfmk appweb.1 httpd:latest swarm00 Running Running 2 minutes ago o0217965pe9h appweb.2 httpd:latest swarmn02 Running Running 55 seconds ago w4wxt9v6jf82 appweb.3 httpd:latest swarmn01 Running Running 55 seconds ago zdngp998mfty appweb.4 httpd:latest swarmn01 Running Running 55 seconds ago |
Si vais a la URL de cualquiera de los nodos donde se está ejecutando, veréis un bonito:
Y una prueba final, sería parar el servicio docker de uno de los workers y ver el resultado:
1 2 3 |
systemctl stop docker Warning: Stopping docker.service, but it can still be activated by: docker.socket |
Y validamos que el servicio que ha caído se levanta en otro nodo disponible:
1 2 3 4 5 6 7 |
docker service ps appweb ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 0gi6faa0qfmk appweb.1 httpd:latest swarm00 Running Running 5 minutes ago 4n1lecxpf05z appweb.2 httpd:latest swarm00 Running Running 7 seconds ago o0217965pe9h \_ appweb.2 httpd:latest swarmn02 Shutdown Running 4 minutes ago w4wxt9v6jf82 appweb.3 httpd:latest swarmn01 Running Running 4 minutes ago zdngp998mfty appweb.4 httpd:latest swarmn01 Running Running 4 minutes ago |
Simplemente, genial…
Borráis los rastros:
1 2 3 4 |
docker service rm appweb appweb docker service ps appweb no such service: appweb |
Te ha gustado la entrada SGUENOS EN TWITTER O INVITANOS A UN CAFE?
Una duda,
¿Por qué has usado máquinas virtuales en lugar de contenedores?
Hola! No hay un motivo especial, tenía máquinas virtuales Debian 11 para ello. Aunque es verdad que cuando hay que instalar un host para contenedores Docker, un contenedor LXC (que entiendo es a lo que te refieres), necesita alguna parametrización adicional para la virtualización anidada. Pero no hay un motivo especial…Un saludo