Gestione dei Nodi

Aggiunta di nodi worker

Un nodo aggiuntivo deve

  • essere creato come contenitore docker
  • dare il comando di join allo swarm

Creazione di nodo

Per esempio, per aggiungere il nodo worker-7, col comando

docker run -d --privileged \
  --name worker-7 --hostname worker-7 --net swarmnet \
  -v $PWD/worker-7:/var/lib/docker \
  doker

Occorre l'opzione --privileged affinchè il nodo possa settare le regole di iptables.

E' una buona idea lo host mapping della directory di docker sul nodo ad una directory sulla macchina locale: il pull di immagini già esistenti non viene effettuato.

Join allo swarm

Il token di join può essere chiesto al manager:

docker exec -ti manager docker swarm join-token -q worker

Attenzione che il risultato è una stringa in formato MSDOS, quindi terminata da CR+NL anzichè da solo NL come in Unix.

Per rimuovere il CR e trasformare la stringa in formato Unix:

docker exec -ti manager docker swarm join-token -q worker |tr -d "\r" 

Quindi per aggiungere il nodo, p.es. worker-7 allo swarm, nella nostra configurazione:

SWARM_TOKEN=$(docker exec -ti manager docker swarm join-token -q worker)
SWARM_TOKEN=$(echo $SWARM_TOKEN | tr -d "\r")
SWARM_MASTER_IP=$(docker exec -ti manager docker info \
  | grep -w "Node Address" | awk '{print $3}')
SWARM_MASTER_IP=$(echo $SWARM_MASTER_IP |tr -d "\r")
docker exec -ti worker-7 docker swarm join \
  --token $SWARM_TOKEN $SWARM_MASTER_IP:2377

Procedura shell di aggiunta nodi

Aggiunta di un singolo nodo

Aggiungere un singolo nodo con nome.

vi addnode.sh
# Controllare l'esistenza del manager
if docker ps | grep manager; then
  :
else
  echo "Node 'manager' does not exist"
  echo "Create swarm cluster first"
  exit 1
fi

if [ $# -lt 1 ]; then
  echo "Must provide name of worker"
  echo "Syntax: $0 worker"
  exit 2
fi

WORKER=$1

# Il token di join
SWARM_TOKEN=$(docker exec -ti manager docker swarm join-token -q worker)
# I messaggi di Swarm sono in formato MSDOS
# E' necessario togliere il Carriage Return
SWARM_TOKEN=$(echo $SWARM_TOKEN | tr -d "\r")
echo Swarm token is $SWARM_TOKEN

# IP del master
SWARM_MASTER_IP=$(docker exec -ti manager docker info \
  | grep -w "Node Address" | awk '{print $3}')
SWARM_MASTER_IP=$(echo $SWARM_MASTER_IP |tr -d "\r")
echo Swarm master IP is $SWARM_MASTER_IP

# Generare il workers e aggiungerlo allo swarm
echo "Starting $WORKER"
docker run -d --privileged \
  --name $WORKER --hostname $WORKER --net swarmnet \
  -v $PWD/$WORKER:/var/lib/docker \
  -v ~/data:/data \
  doker
  echo "Joining $WORKER"
sleep 5
docker exec -ti $WORKER docker swarm join \
  --token $SWARM_TOKEN $SWARM_MASTER_IP:2377

docker exec -ti manager docker node ls
chmode +x addnode.sh

Aggiunta di più nodi

La seguente procedura shell permette di aggiungere un numero di nodi allo swarm:

vi newnodes.sh
# Controllare l'esistenza del manager
if docker ps | grep manager; then
  :
else
  echo "Node 'manager' does not exist"
  echo "Create swarm cluster first"
  exit 1
fi

# Il token di join
SWARM_TOKEN=$(docker exec -ti manager docker swarm join-token -q worker)
# I messaggi di Swarm sono in formato MSDOS
# E' necessario togliere il Carriage Return
SWARM_TOKEN=$(echo $SWARM_TOKEN | tr -d "\r")
echo Swarm token is $SWARM_TOKEN

# IP del master
SWARM_MASTER_IP=$(docker exec -ti manager docker info \
  | grep -w "Node Address" | awk '{print $3}')
SWARM_MASTER_IP=$(echo $SWARM_MASTER_IP |tr -d "\r")
echo Swarm master IP is $SWARM_MASTER_IP

# Numero di workers
if  (($# < 1)) ; then
  echo "Must provide number of nodes to add"
  echo "Syntax: $0 numnodes"
  exit 2
fi
NUM_WORKERS=$1
LAST_WORKER=$(docker ps | grep worker | awk '{n=NF; print $n}' \
  | sort | tail -1 | cut -d- -f2)
NEXT_WORKER=$( expr $LAST_WORKER + 1 )
LAST_ADDED=$( expr $NEXT_WORKER + $NUM_WORKERS - 1 )
echo $NUM_WORKERS workers will be added, from $NEXT_WORKER to $LAST_ADDED

# Generare i workers e aggiungerli allo swarm
for i in $(seq "$NEXT_WORKER" "$LAST_ADDED"); do
  echo "Starting worker-${i}"
  docker run -d --privileged \
    --name worker-${i} --hostname worker-${i} --net swarmnet \
    -v $PWD/worker-${i}:/var/lib/docker \
    -v ~/data:/data \
    doker
  echo "Joining worker-${i}"
  sleep 3
  docker exec -ti worker-${i} docker swarm join \
    --token $SWARM_TOKEN $SWARM_MASTER_IP:2377
done

docker exec -ti manager docker node ls

Renderla eseguibile:

chmod +x newnodes.sh

Eseguirla col comando, per esempio per aggiungere 3 nodi:

./newnodes.sh 3

Rimozione di nodo

Il nodo da il comando per lasciare lo swarm.

Per esempio per worker-7:

docker exec -ti worker-7 docker swarm leave

Il nodo lascia lo swarm.

Attenzione che il nodo rimane però nella tabella dei nodi del manager. Infatti:

dk docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
.....
aj0ope2gl1u90dptwv71fo7ta     worker-7   Down      Active                          26.1.5

Lo STATUS del nodo è marcato come Down.

Per evitare eccessiva digitazione è stato creato l'alias:

alias dk='docker exec -ti manager'

Il contenitore docker worker-7 naturalmente continua ad esistere.

Per rimuoverlo dalla tabella del manager occorre dare il comando:

dk docker node rm worker-7

Se si compie un nuovo join del nodo worker-7 allo swarm senza averlo rimosso dalla tabella dei nodi del manager:

SWARM_TOKEN=$(docker exec -ti manager docker swarm join-token -q worker)
SWARM_TOKEN=$(echo $SWARM_TOKEN | tr -d "\r")
SWARM_MASTER_IP=$(docker exec -ti manager docker info \
  | grep -w "Node Address" | awk '{print $3}')
SWARM_MASTER_IP=$(echo $SWARM_MASTER_IP |tr -d "\r")
docker exec -ti worker-7 docker swarm join \
  --token $SWARM_TOKEN $SWARM_MASTER_IP:2377

La procedura funziona ma viene creata un'altra istanza di nodo in tabella, e quella vecchia, Down, continua ad esistere.

dk docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
.....
8m9lhsotqmb2wn84m1t21k1qr     worker-7   Ready     Active                          26.1.5
aj0ope2gl1u90dptwv71fo7ta     worker-7   Down      Active                          26.1.5

A questo punto non si può rimuoverla col nome, ma solo tramite l'identificativo:

dk docker node rm aj0ope2gl1u90dptwv71fo7ta

Procedura di rimozione

Rimuovere un nodo e rimuovere il contenitore docker dalla macchina ospite:

vi rmnode.sh
# Controllare la sintassi, un argomento è necessario
if [ $# -lt 1 ]; then
  echo "Must indicate node to remove"
  echo "Syntax: $0 node"
  exit 1
fi
NODE=$1

# Controllare che il nodo esista
if docker exec -ti manager docker node ls | grep $NODE > /dev/null 2>&1
then
  :
else
  echo "Node $NODE does not exist in cluster"
  exit 2
fi

# Il nodo lascia lo swarm
docker exec -ti $NODE docker swarm leave
# Attendere la rimozione dalla tabella dei nodi
echo "Waiting for $NODE to be down"
while true; do
  if docker exec -ti manager docker node ls | grep $NODE | grep Down ; then
    break
  else
    sleep 1
    continue
  fi
done
echo "Node $NODE is down"

# Il nodo è cancellato dalla tabella del manager
echo "Removing $NODE from manager table"""
docker exec -ti manager docker node rm $NODE

# Rimuovere il contenitore dalla macchina ospite
docker rm -f $NODE
echo "Node $NODE removed from host docker"

Renderla eseguibile:

chmod +x rmnode.sh

Promozione e demozione di nodo

Promuovere nodi a manager, esempi:

dk docker node promote worker-1
dk docker node promote worker-2
dk docker node promote worker-3

Per degradare (demuovere) un nodo da manager a worker il comando è, p-es.:

dk docker node demote worker-3

Lo stato dello swarm è ora:

dk docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
q2v80vqnl99wmuom4z784gvvs *   manager    Ready     Active         Leader           26.1.5
iggo7d5z82jb8zohjoxl093fq     worker-1   Ready     Active         Reachable        26.1.5
fcj1b9vc16z2corput5ly0d1t     worker-2   Ready     Active         Reachable        26.1.5
jexh3jjpysvs7fz0h8k93n7db     worker-3   Ready     Active                          26.1.5
kn7q5tcb7b0844613xhwb30hi     worker-4   Ready     
.....

Ora un manager può lasciare lo swarm:

dk docker swarm leave -f

Il nodo manager ha lasciato lo swarm. L'opzione -f è indispensabile per forzare l'uscita di un nodo manager.

Il cluster elegge un nuovo leader. Si possono ora indirizzare comandi di gestione del cluster ad un manager qualsiasi, per esempio worker-1.

La nuova tabella del cluster è:

docker exec -ti worker-1 docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
q2v80vqnl99wmuom4z784gvvs     manager    Down      Active         Unreachable      26.1.5
iggo7d5z82jb8zohjoxl093fq *   worker-1   Ready     Active         Reachable        26.1.5
fcj1b9vc16z2corput5ly0d1t     worker-2   Ready     Active         Leader           26.1.5
jexh3jjpysvs7fz0h8k93n7db     worker-3   Ready     Active                          26.1.5
kn7q5tcb7b0844613xhwb30hi     worker-4   Ready     Active                          26.1.5
.....

Si nota che worker-2 è stato eletto nuovo leader del cluster.

I vecchi manager nello stato di Down devono essere degradati a worker prima di essere rimossi dalla tabella del cluster:

docker exec -ti worker-1  docker node demote manager
docker exec -ti worker-1  docker node rm manager

Se vi sono duplicazioni usare lo ID anzichè lo HOSTNAME.

L'elezione di un nuovo leader avviene con il protocollo di consenso RAFT.

Il leader è il manager primario, che compie tutte le decisioni di amministrazione del cluster e di orchestrazione dei task.

Per avere un cluster stabile è necessario avere un numero dispari di manager: 1 (minimo), 3, 5 o 7 (massimo raccomandato).

Quando viene meno un manager, si raccomanda di portare al più presto il numero dei manager al prossimo numero dispari.

Questo si può fare:

  • promuovendo un worker a manager
  • istanziando un nuovo nodo con il token di join dei master

Per conoscere il token di join come manager, chiedere ad un maneger corrente qualsiasi:

SWARM_TOKEN=$(docker exec -ti worker-1 docker swarm join-token -q manager)
SWARM_TOKEN=$(echo $SWARM_TOKEN | tr -d "\r")
echo "Swarm Token is $SWARM_TOKEN"

Occorre anche l'indirizzo IP di uno dei manager attivi.

SWARM_MASTER_IP=$(docker exec -ti worker-1 docker info \
  | grep -w "Node Address" | awk '{print $3}')
SWARM_MASTER_IP=$(echo $SWARM_MASTER_IP |tr -d "\r")
echo "Swarm Master IP is $SWARM_MASTER_IP"

Ora possiamo reinstanziare manager come nodo manager del cluster:

docker exec -ti manager docker swarm join \
  --token $SWARM_TOKEN $SWARM_MASTER_IP:2377

Non sarà il leader, ma vi si possono inviare comandi di amministrazione, e saranno ridiretti al leader.

Etichette ad un nodo

Eì possibile aggiungere una label ad un nodo. p.es.:

dk docker node update --label-add function=production worker-5

Una label è una coppia chiave=valore.

Una label può essere usata per restringere l'assegnazione di servizi a determinati nodi, per esempio con l'opzione --constraint node.labels.function=production.

Per vedere le label del nodo worker-5 in formato YAML:

dk docker node inspect worker-5 --pretty

Per rimuovere una label, p.es.:

dk docker node update --label-rm function worker-5

Le label sono maps in linguaggio Go, su cui Docker è costruito.

Per vedere tutte le label di ogni nodo manca un comando specifico, ma si può estrarre l'informazione con:

dk bash -c "docker node ls -q | xargs docker node inspect \
  -f '{{ .Description.Hostname }}: {{ .Spec.Labels }}'"

Disponibilità un nodo

Vi sono tre stati di disponibilità di un nodo:

  • active
  • pause
  • drain

Si può mettere un nodo in pausa con:

dk docker node update --availability pause worker-4

Non verranno schedulati nuovi task al nodo, ma quelli presenti continuano a funzionare.

Per toglierlo dalla pausa:

dk docker node update --availability active worker-4

Possono venire schedulati nuovi task al nodo.

Si può mettere un nodo nello stato di drain con:

dk docker node update --availability drain worker-4

Non vengono schedulati nuovi task al nodo, e quelli presenti sono gradualmente migrati ad altri nodi.