/ HOWTO

Docker Cluster - Swarm Parte II, Laboratorio.


Continuando con el tema de Clusters en Docker, ahora montaremos un entorno de pruebas con varios servidores.

Montaremos 4 servidores corriendo Docker, con distintos S.operativos y nos permitirá probar despliegue de contenedores entre ellos simulando una configuración real de un gran proyecto.

Los 5 Servidores corriendo son:

  1. Debian
  2. Centos 7
  3. Mac con OSX
  4. FreeBSD - GhostBSD
  5. Manager - Manajaro

DEBIAN - Xubuntu

Quitar versiones viejas

#apt-get remove docker docker-engine docker.io

Instalar con Repositorios

# apt-get install apt-transport-https ca-certificates curl software-properties-common

# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# sudo apt-key fingerprint 0EBFCD88

# sudo add-apt-repository  "deb [arch=amd64] https://download.docker.com/linux/ubuntu  $(lsb_release -cs)    stable"

# apt update

# apt-get install docker-ce

# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            966M     0  966M   0% /dev
tmpfs           198M  8,6M  189M   5% /run
/dev/sda1        18G   11G  5,8G  66% /
tmpfs           987M  164K  987M   1% /dev/shm
tmpfs           5,0M  4,0K  5,0M   1% /run/lock
tmpfs           987M     0  987M   0% /sys/fs/cgroup
tmpfs           198M   44K  198M   1% /run/user/1000

# uname -a
Linux xubu 4.10.0-38-generic #42~16.04.1-Ubuntu SMP Tue Oct 10 16:32:20 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


# docker version
Client:
 Version:      17.10.0-ce
 API version:  1.33
 Go version:   go1.9.1
 Git commit:   f4ffd2511c
 Built:        Wed Oct 18 23:08:56 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.10.0-ce
 API version:  1.33 (minimum version 1.12)
 Go version:   go1.9.1
 Git commit:   f4ffd2511c
 Built:        Wed Oct 18 23:09:11 2017
 OS/Arch:      linux/amd64
 Experimental: false

CENTOS 7

# yum remove docker  docker-common docker-selinux docker-engine
# yum install -y yum-utils device-mapper-persistent-data lvm2
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# yum install docker-ce


# docker run hello-world

# systemctl enable docker
# systemctl start docker


# df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   16G  1.3G   14G   9% /
devtmpfs                 486M     0  486M   0% /dev
tmpfs                    497M     0  497M   0% /dev/shm
tmpfs                    497M  6.7M  490M   2% /run
tmpfs                    497M     0  497M   0% /sys/fs/cgroup
/dev/sda1               1014M  181M  834M  18% /boot
tmpfs                    100M     0  100M   0% /run/user/0
tmpfs                    100M     0  100M   0% /run/user/1000

# uname -a
Linux localhost.localdomain 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


# docker version
Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:42:18 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:40:56 2017
 OS/Arch:      linux/amd64
 Experimental: false

MAC OSX

Obtener el fichero DMG a instalarlo como siempre.

https://download.docker.com/mac/stable/Docker.dmg

FreeBSD - GhostBSD

# pkg install docker
Updating GhostBSD repository catalogue...
GhostBSD repository is up to date.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
	docker: 17.06.1

Manjaro/Arch

# pacman -S docker-machine

# df -h
Filesystem      Size  Used Avail Use% Mounted on
dev             3,9G     0  3,9G   0% /dev
run             3,9G  1,6M  3,9G   1% /run
/dev/sdb2       229G   95G  123G  44% /
tmpfs           3,9G  154M  3,7G   4% /dev/shm
tmpfs           3,9G     0  3,9G   0% /sys/fs/cgroup
tmpfs           3,9G  144M  3,8G   4% /tmp
/dev/sda1       220G  189G   20G  91% /extras
/dev/sdb3      1022M  256K 1022M   1% /boot/efi
tmpfs           787M   36K  787M   1% /run/user/1000

# uname -a
Linux xxxx 4.9.60-1-MANJARO #1 SMP PREEMPT Thu Nov 2 13:08:20 UTC 2017 x86_64 GNU/Linux


# docker version
Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:41:23 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:42:49 2017
 OS/Arch:      linux/amd64
 Experimental: false

Poniendo a funcionar nuestro cluster

Usaremos tres equipos, Xubuntu, Centos y Manjaro. Todos deben estar en la misma red, IPs locales, se deben ver sin bloqueos de puertos y para facilitar el laboratorio creamos 3 sesiones bash contra cada uno de ellos.

Cluster: SwarnII

En el nodo manager, creamos el cluster (Swarm) y nos indica que deben hacer los demas servidores para asociarse a él.

# docker swarm init

Swarm initialized: current node (wo3mvfeprxtpvl04jbjllithc) is now a manager.

To add a worker to this swarm, run the following command:

   docker swarm join --token SWMTKN-1-1mmvuqqg5yxkx1d97r6c9 192.168.0.200:2377

To add a manager to this swarm, run ‘docker swarm join-token manager’ and follow the instructions.

En uno de los nodos (Xubu), nos asociamos al cluster.

# docker swarm join --token SWMTKN-1-1mmvuqqg5yxkx1d97r6c9 192.168.0.200:2377
This node joined a swarm as a worker.

Por ahora nuestro cluster está formado por un nodo Manager y un nodo Worker. Recordemos que los nodos Manager también son clusters y pueden correr contenedores/Servicios.

Desde el nodo Manager podemos ver información del cluster creado.

# docker info
# ....
Swarm: active
 NodeID: 7a2dnxwcnv7qjjpif5pktzzxx
 Is Manager: true
 ClusterID: mxar9yxib306voil6wu3vyopa
 Managers: 1
 Nodes: 2
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 3
 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.0.220
 Manager Addresses:
  192.168.0.220:2377
# ....

Desde el nodo manager, también podemos ver información de todos los nodos.

# docker  node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
7a2dnxwcnv7qjjpif5pktzzxx *   xxxx                Ready               Active              Leader
vdor4zhtg9fmplim3bxcu3g7w     xubu                Ready               Active
mxar9yxib306voil6wu3vyopa     centos              Ready               Active

Ahora crearemos un servicio sencillo, que únicamente hará ping al sitio web de docker.com. Indicamos que solo requeremos una réplica, que representa tener un solo contenedor corriendo el ping.

# docker service create --replicas 1 --name helloworld alpine ping docker.com
i8ogtiui90csqddhybcmlmu6c
overall progress: 1 out of 1 tasks
1/1: running
verify: Service converged

Con el comando “service” podemos interactuar con los servicios. Veremos los que están corriendo. En este ejemplo solo uno llamado “helloworld”.

# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
i8ogtiui90cs        helloworld          replicated          1/1                 alpine:latest

Se puede ver la información del servicoi de una manera detallada en modo texto.

# docker service inspect --pretty helloworld
ID:		i8ogtiui90csqddhybcmlmu6c
Name:		helloworld
Service Mode:	Replicated
 Replicas:	1
Placement:
UpdateConfig:
 Parallelism:	1
 On failure:	pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:	1
 On failure:	pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:		alpine:latest@sha256:d6bfc3baf615dc9618209a8d607ba2a8103d9c8a405b3bd8741d88b4bef36478
 Args:		ping docker.com
Resources:
Endpoint Mode:	vip

O obtener los mismos datos pero en formato JSON.

# docker service inspect helloworld
 [
    {
        "ID": "i8ogtiui90csqddhybcmlmu6c",
        "Version": {
            "Index": 16
        },
        "CreatedAt": "2017-11-08T09:57:23.361027551Z",
        "UpdatedAt": "2017-11-08T09:57:23.361027551Z",
 ]

El comando “ps” nos mostrará los procesos corriendo en el servicio “helloworld”, veremos que el nombre es “helloworld.1”, veremos mas adelante que al agregar mas contenedores incrementará ese número.

Este comando lo probamos en el nodo Manager, y como habíamos indicado que solo queríamos una intancia del servicio “ping”, el contenedor creado está corriendo en ese mismo nodo (Manager).

# docker service ps helloworld
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
ktbmgf618475        helloworld.1        alpine:latest       manager          Running             Running about a minute ago

En uno nodo worker no hay actividad, no hay contenedores corriendo.

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Pasaremos de 1 a 5 instancias de ese servicio, con el comando “scale”.

# docker service scale helloworld=5
helloworld scaled to 5
overall progress: 5 out of 5 tasks
1/5: running
2/5: running
3/5: running
4/5: running
5/5: running
verify: Service converged

Ahora en el nodo Manager veremos que hay 2 instancias corriendo.

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ad95a5fe459e        alpine:latest       "ping docker.com"   43 seconds ago      Up 42 seconds                           helloworld.4.iwdgown6x41kvhc5beqqckypx
b0f565aa0937        alpine:latest       "ping docker.com"   3 minutes ago       Up 3 minutes                            helloworld.1.ktbmgf618475evjynopvfn64y

Y en el nodo worker adicional, veremos que estás las otras 3.

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
8de17f7ee5fc        alpine:latest       "ping docker.com"   55 seconds ago      Up 54 seconds                           helloworld.3.s77fgqan7n4giqafa43p1c58w
104f694db485        alpine:latest       "ping docker.com"   55 seconds ago      Up 54 seconds                           helloworld.2.mgtoebrd1buo0tip4df9odnsq
de1b481c0105        alpine:latest       "ping docker.com"   55 seconds ago      Up 54 seconds                           helloworld.5.s6jare34i637orand4bjvtb8p

En el nodo manager, nos dice en donde están corriendo cada instancia (.1 al .5). El proceso de despliegue de instancias demora unos segundos aún en el caso de una red óptima y sin problemas de recursos.

# docker service ps helloworld
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
ktbmgf618475        helloworld.1        alpine:latest       xxxx                Running             Running 3 minutes ago
mgtoebrd1buo        helloworld.2        alpine:latest       xubu                Running             Running about a minute ago
s77fgqan7n4g        helloworld.3        alpine:latest       xubu                Running             Running about a minute ago
iwdgown6x41k        helloworld.4        alpine:latest       xxxx                Running             Running about a minute ago
s6jare34i637        helloworld.5        alpine:latest       xubu                Running             Running about a minute ago

Si voy al nodo Worker y quiero matar el servicio llamado helloworld en un worker, me dice que está siendo manejado por un manager.

# docker service rm helloworld
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

Al correr el “RM” (remove) en el nodo Manager, unos segundos despues todos los contenedores (locales y en nodos worker) se matan y desaparecen, también es un proceso que demora varios segundos.

# docker service rm helloworld

Hemos matado ese servicio y ahora volveremos a hacer una prueba agregando otro nodo worker adicional.

Desde el manager, volvemos a crear 5 contenedores, ahora haciendo ping al IP local.

# docker service create --replicas 5 --name helloworld alpine ping 127.0.0.1
y800rpbkzms6fow2x66dkt0ob
overall progress: 5 out of 5 tasks
1/5: running
2/5: running
3/5: running
4/5: running
5/5: running
verify: Service converged

Desde el nodo manager (o equipo real donde corrimos el docker swam init) vemos esos procesos.

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fa64e5f32552        alpine:latest       "ping 127.0.0.1"    54 seconds ago      Up 52 seconds                           helloworld.4.f0bo5pasg42k4b9uukcf2bmd5
313c0ea7d8d1        alpine:latest       "ping 127.0.0.1"    54 seconds ago      Up 52 seconds                           helloworld.2.u4az3zrdhjvhe2blk32wusz0m

En el nodo worker hay 3 servicios corriendo.

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ee4aeeafb26a        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 17 seconds                           helloworld.1.ygqtf1xaaxe4jelptpfnrir4m
347a727cc143        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 17 seconds                           helloworld.5.trp457wgld4rvlcigncqbu4eg
ea6d8e609e5e        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 17 seconds                           helloworld.3.xiw1k5njk09jxmnse6g76inae

Ahora asociaremos otro servidor (Centos) como nodo worker al mismo cluster..

# docker swarm join --token SWMTKN-1-1b7mhfuqek3e0bogz5yckq42utmm52mzxt2cd49exhkiugcz9l-9z54i6yhvgghbpi524kpokax8 192.168.10.220:2377
Error response from daemon: error while validating Root CA Certificate: x509: certificate has expired or is not yet valid

Posible problema de diferencia de fechas entre nodos o causados por el Firewall de Centos, lo desactivamos.

# iptables -F
# iptables -Z

En el nodo Manager, el certificado parece valido.

# docker swarm ca | openssl x509 -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            57:ff:e6:b3:73:cf:92:49:a8:df:bf:76:e6:81:e5:60:e1:5f:14:f1
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = swarm-ca
        Validity
            Not Before: Nov  8 09:49:00 2017 GMT
            Not After : Nov  3 09:49:00 2037 GMT
        Subject: CN = swarm-ca
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:99:13:5c:40:f8:4b:9c:e0:b1:2a:25:42:bf:5b:
                    ea:92:0d:e4:ef:dc:88:bc:ab:d9:4a:35:48:a4:ff:
                    3e:6a:81:13:b9:ef:01:bb:83:a4:df:34:8b:84:59:
                    25:be:cf:dd:d6:38:bb:e1:fb:38:82:49:f5:c7:23:
                    72:a4:b2:cd:f0
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                80:B4:77:1E:0F:7B:41:CF:6D:3D:7E:5E:B7:01:FF:9C:43:69:3A:C0
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:2d:8e:b0:12:fc:64:a0:72:7c:ff:d8:d1:65:59:
         15:db:f0:00:13:3d:b2:0e:77:7e:46:14:b2:a9:8b:26:01:37:
         02:21:00:a7:91:45:b8:44:96:61:3d:e5:b2:b5:cf:8e:cd:32:
         80:e9:8f:5d:ba:cf:07:1e:25:f7:20:8e:b9:a0:92:24:f6

Desde el nodo manager, pasaremos a tener 12 instancias de ese servicio (ping 127.0.0.1)

# docker service create --replicas 12 --name helloworld alpine ping 127.0.0.1
dei77zqlcgi9slct0480dd307
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.

Veremos que Docker ha balanceado las 12 instancias entre los 3 servidores (Manager y dos Workers). En el nodo manager tendremos 4 instancias corriendo.

Y en los nodos:

NODO 1

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fa55d5b7392d        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 16 seconds                           helloworld.10.lx08pcglw101m0i4fk7xt5071
40c114da3137        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 16 seconds                           helloworld.1.efjsaifuzu3yg8z62uumramyl
a521533ffda5        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 16 seconds                           helloworld.9.q8jjrg0xx962mw9lyqg2k2jax
a7f7e961e688        alpine:latest       "ping 127.0.0.1"    19 seconds ago      Up 16 seconds                           helloworld.11.0o7trps3n5cjzxeb8jbofwy1u

NODO 2

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
4d181e795ed3        alpine:latest       "ping 127.0.0.1"    16 seconds ago      Up 14 seconds                           helloworld.3.itwd8e1f0mbutmsbt3ec0lpg6
d469d9ca613e        alpine:latest       "ping 127.0.0.1"    16 seconds ago      Up 15 seconds                           helloworld.8.nc1ic470bldl7lzyq9sthnojm
6603e22f437d        alpine:latest       "ping 127.0.0.1"    16 seconds ago      Up 15 seconds                           helloworld.6.pytiqtq7ek745b3bhzcme4vxs
f2c2c86f83b7        alpine:latest       "ping 127.0.0.1"    16 seconds ago      Up 15 seconds                           helloworld.4.d0zt4yeur3jb7sah038kz0r7h

Reducimos los servicios corriendo a solo 5 (de 12 a 5)

# docker service scale helloworld=5

Ahora la distribución será 2,2 y 1. NODO MANAGER

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
5a2e202072f6        alpine:latest       "ping 127.0.0.1"    8 minutes ago       Up 7 minutes                            helloworld.7.rmn5h3ve3wled16137j6c3xol
2e1c22009935        alpine:latest       "ping 127.0.0.1"    8 minutes ago       Up 7 minutes                            helloworld.5.bf8gov2pefhspvx7fg0ghtmxv

NODO 1

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
fa55d5b7392d        alpine:latest       "ping 127.0.0.1"    7 minutes ago       Up 6 minutes                            helloworld.10.lx08pcglw101m0i4fk7xt5071
40c114da3137        alpine:latest       "ping 127.0.0.1"    7 minutes ago       Up 6 minutes                            helloworld.1.efjsaifuzu3yg8z62uumramyl

NODO 2

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d469d9ca613e        alpine:latest       "ping 127.0.0.1"    7 minutes ago       Up 7 minutes                            helloworld.8.nc1ic470bldl7lzyq9sthnojm

Veremos que cada contenedor corriendo en un equipo real, genera dos unidades montadas (3 Contenedores = 6 unidades).

overlay         229G   97G  121G  45% /var/lib/docker/overlay2/ca4862b746a55c417d6bdcefefb92f7ef3c1c9268c6de1486b9a3ebc7a407e8b/merged
shm              64M     0   64M   0% /var/lib/docker/containers/e6585f9886c3de279cb64055b19c5808f2e0864ab1ce50c86d4c660977454795/shm

overlay         229G   97G  121G  45% /var/lib/docker/overlay2/876ab5dce32173628c090625f20e0765ed8db5b1ca24d686c106f3d5a547ed83/merged
shm              64M     0   64M   0% /var/lib/docker/containers/ebaaa12db5675495922e1b8e8018dfd188b5bda1671267a900d83c9396a0e6e5/shm

overlay         229G   97G  121G  45% /var/lib/docker/overlay2/3e2b2ef636d78b552c10274029d79fb3487bee0cb9c2263f1214724c1714fc8f/merged
shm              64M     0   64M   0% /var/lib/docker/containers/b0bd710db0843e4553407efca307dc815ac4c0e372805241e737d0bbed7be17a/shm

En los nodos no es posible pedir un “service” estan gestionados desde el manager.

# docker service ls
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

Desde el manager podemos pedir mas detalles de los servicios corriendo.

# docker service ps helloworld
ID                  NAME                IMAGE               NODE                    DESIRED STATE       CURRENT STATE                    ERROR               PORTS
efjsaifuzu3y        helloworld.1        alpine:latest       xxxxxxxxxx              Running             Running less than a second ago
bf8gov2pefhs        helloworld.5        alpine:latest       localhost.localdomain   Running             Running 9 minutes ago
rmn5h3ve3wle        helloworld.7        alpine:latest       localhost.localdomain   Running             Running 9 minutes ago
nc1ic470bldl        helloworld.8        alpine:latest       xubu                    Running             Running less than a second ago
lx08pcglw101        helloworld.10       alpine:latest       xxxxxxxxxx              Running             Running less than a second ago

Para revisar el log de un contenedor, solo se puede hacer localmente desde el propio nodo. Desde el manager no es posible ver el log de un contenedor corriendo en un Nodo worker distinto.

# docker logs d469d9ca613e
Error response from daemon: No such container: d469d9ca613e

Si un nodo deja el cluster, unos segundos despues el Manager arrancará nuevos contenedores en otros nodos, para mantener la cantidad definida.

# docker swarm leave
Node left the swarm.

Subscríbete y recibirás los últimos artículos semanalmente en tu email.