Docker Swarm Mode

From berki WIKI
Revision as of 20:32, 28 July 2018 by Adam (talk | contribs) (Traefik)

Jump to: navigation, search

<< Back to Orchestration main

Bevezető

Docker swarm mode

A docker swarm mode az 1.12-es verziótól része a docker-engine-nek, tehát már nem egy külön komponens. Az egyik leg szembeötlőbb különbség, hogy nem docker konténerekben fut, hanem része a docker-nek. ... ...

...

Fontos fogalmak

IPTV

Az IPVS (IP Virtual Server) egy szállítási rétegbeli load-balancer implementáció, amit "Layer 4 LAN switching"-nek is hívnak. Az IPVS része a Linux kernelnek. Közvetlen a Netfilter kernel szolgáltatásra épül. Az IPVS a külső kéréseket a valós belső TCP és UDP szolgáltatásokra irányítja a konfiguráció alapján, így egyetlen külső IP címmel több belső szolgáltatás is elérhető akárcsak csak az apache név alapú virtuális hosztok esetén. Azonban van egy fontos különbség a Layer 7 HTTP load balancer-ekhez képest. Mivel a szállítási rétegben fut, nem képes http session alapú node választásra. (Természetesen egy TCP kommunikáción belül ugyan az a végpont fogja megkapni a csomagokat különben semmi értelme nem lenne. )

routing mesh

A swarm -on futó szolgáltatások portjait az úgynevezett routing mesh tartja nyilván. Ha egy szolágáltatást egy adott porton el kell hogy érjünk a swarm-on kívülről, akkor be kell regisztrálni a portot a routing mesh-be.
Az alábbi portokat kell kinyitni a VM-ek között még a swarm létrehozása előtt:

  • 7946 TCP/UDP for container network discovery.
  • 4789 UDP for the container ingress network.
TipIcon.png

Tip
A docker-machine-el KVM-re létrehozott gépeken minden port nyitva van



Swarm cluster létrehozása

A docker-machine paranccsal már nem lehet közvetlen swarm-hoz kapcsolódott VM-eket létrehozni. Elsőként lére kell hozni a docker ready VM-eket, majd azokra belépve, már a dedikált swarm kezelő parancsokkal tudjuk felépíteni a cluster-t. (docker node, service és stack)


A swarm mode cluster-t egy bash szkripttel fogjuk létrehozni. 3 manager-t és 3 worker node-t. Elsőként a három manager virtuális gépet hozzuk létre. Ezután a mg0-ás gépen inicializáljuk a cluster-t, majd az m1 és m2 node-okat manager-ként beléptetjük a cluster-be. Ha ez megvan, akkor létrehozzuk a három worker node-t és azokat worker-ként léptetjük be a cluster-be.

ImportantIcon.png

Note
Mindig páratlan számú manager node-ot kell létrehozni, hogy a leader választó algoritmus nehogy zátonyra fusson

#!/bin/bash

#Create managers
for i in 0 1 2; do 
	docker-machine create -d kvm --kvm-network "docker-network" --kvm-disk-size "5000" --kvm-memory "800"  mg$i
done

#Init cluster
docker-machine ssh mg0 docker swarm init --advertise-addr $(docker-machine ip mg0)

#Join managers
MANAGER_TOKEN=`docker-machine ssh mg0 docker swarm join-token -q manager`
WORKER_TOKEN=`docker-machine ssh mg0 docker swarm join-token -q worker`

for i in 0 1 2; do
	docker-machine ssh mg$i docker swarm join --token $MANAGER_TOKEN $(docker-machine ip mg0)
done

#Create workers
for i in 0 1 2; do 
	docker-machine create -d kvm --kvm-network "docker-network" --kvm-disk-size "5000" --kvm-memory "800"  worker$i
	docker-machine ssh worker$i docker swarm join --token $WORKER_TOKEN $(docker-machine ip mg0)
done
TipIcon.png

Tip
A KVM helyett itt használhattunk volna Amzaon EC2-es driver-t is, pont ugyan így létrehozta volna az egész cluster-t pár perc alatt. Részletek itt: Docker Swarm on AWS



Ha lefutottak a script, nézzük meg a keletkezett VM-eket elsőként docker-machine szemszögből:

# docker-machine ls
NAME      ACTIVE   DRIVER   STATE     URL                         SWARM   DOCKER        ERRORS
mg0       -        kvm      Running   tcp://192.168.42.41:2376            v18.05.0-ce   
mg1       -        kvm      Running   tcp://192.168.42.79:2376            v18.05.0-ce   
mg2       -        kvm      Running   tcp://192.168.42.154:2376           v18.05.0-ce   
worker0   -        kvm      Running   tcp://192.168.42.162:2376           v18.05.0-ce   
worker1   -        kvm      Running   tcp://192.168.42.74:2376            v18.05.0-ce   
worker2   -        kvm      Running   tcp://192.168.42.136:2376           v18.05.0-ce   


Majd nézzük meg a virsh-val is.

# virsh list 
 Id    Name                           State
----------------------------------------------------
 2     mg0                            running
 3     mg1                            running
 7     mg2                            running
 8     worker0                        running
 9     worker1                        running
 10    worker2                        running
ClipCapIt-180716-232126.PNG


Most listázzuk ki a swarm cluster node-jait elsőként az mg0-án, majd az mg1-en. Mind a két esetben ugyan azt az eredményt kapjuk. Láthatjuk, hogy jelenleg az mg0 a vezető.

# docker-machine ssh mg0 docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
nl5mmm994ckimhe5vjazjjecs *   mg0                 Ready               Active              Leader              18.05.0-ce
vacts6xlgb6ufyx49vx6fxgt0     mg1                 Ready               Active              Reachable           18.05.0-ce
3llb2b0qh7oids0qhych9w73r     mg2                 Ready               Active              Reachable           18.05.0-ce
s7hp748qu6u4bb98doss31t4r     worker0             Ready               Active                                  18.05.0-ce
211o588k4qw2uymq6dl977mmt     worker1             Ready               Active                                  18.05.0-ce
hlzuosjp7wx6rxt0a66fms698     worker2             Ready               Active                                  18.05.0-ce
# docker-machine ssh mg1 docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
nl5mmm994ckimhe5vjazjjecs     mg0                 Ready               Active              Leader              18.05.0-ce
vacts6xlgb6ufyx49vx6fxgt0 *   mg1                 Ready               Active              Reachable           18.05.0-ce
3llb2b0qh7oids0qhych9w73r     mg2                 Ready               Active              Reachable           18.05.0-ce
s7hp748qu6u4bb98doss31t4r     worker0             Ready               Active                                  18.05.0-ce
211o588k4qw2uymq6dl977mmt     worker1             Ready               Active                                  18.05.0-ce
hlzuosjp7wx6rxt0a66fms698     worker2             Ready               Active                                  18.05.0-ce



Monitorozás

Több grafikus docker monitor eszköz is létezik:

  • Shipyard (webes)
  • Portainer (webes)
  • Kitematic (vastag kliens)


A legegyszerűbb a Portainer használata, ami egyetlen konténert telepít fel a docker-be, képes távoli docker démonho is kapcsolódni, és van benne swarm mode támogatás is.


Két lehetőségünk van a Portainer futtatására:

  • Ahhoz hogy a swarm cluster adatait tudjuk monitorozni, valamelyik manager node-on futó docker démonhoz kell kapcsolódni a lokális docker -ben futó Portainer-el. Ezt TLS autentikációval lehet megoldani. Ekkor a Portanier a localhost-on érhető el. (mi ezt fogjuk használni, ez az ajánlott megoldás produkciós környezetben)
  • A Portainer-t eleve a manager node-ot is futtató docker démonban telepítjük fel a távoli gépen, ekkor Portanier a távoli gép IP címén érhető el. Ekkor a Portainer közvetlen tud csatlakozni a docker manager-en az ottan lokális docker démonhoz (ez inkább csak tesztelés céljára, a manager node-okon nem szokás semmi mást futtatni).


A KVM dirver-el készült docker-machine-ekre boot2docker operációs rendszer kerül feltelepítésre, ha ezt nem változtatjuk meg. A boot2docker-ben alapértelmezetten be van kapcsolva a TLS remote docker API (port: 2376), és a titkosítatlan távoli hozzáférés ki van kapcsolva (port: 2375), tehát csak TLS-el lehet a manager-en futó docker démon-ra csatlakozni

ImportantIcon.png

Note
A példában a mg0 manager node-ra fogunk kapcsolódni, de pont ugyan ezt az eredményt kapnánk az mg1 és mg2 manager-ekkel is.


TLS kulcsok és IP cím begyűjtése

Mikor a docker-machine létrehozta a manager node-okat, legyártotta azokat az ssh kulcsokat, aminek a segítségével a docker-machine be tud ssh-zni a VM-re jelszó és felhasználó név megadása nélkül (docker-machine ssh mg0). Ezeket a kulcsokat fogjuk mi is felhasználni, hogy a lokálisan futó Portainer hozzá tudjon kapcsolódni a (távoli) virtuális gépen futó docker démonhoz.


Adjuk ki docker-machine env parancsot, hogy megtudjuk, hol tárolja a lokális docker-machine környezetünk a távoli VM SSH kulcsait:

# docker-machine env mg0
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.42.41:2376"
export DOCKER_CERT_PATH="/root/.docker/machine/machines/mg0"
export DOCKER_MACHINE_NAME="mg0"
# Run this command to configure your shell: 
# eval $(docker-machine env mg0)

Látható, hogy a kulcsok a /root/.docker/machine/machines/mg0 mappában vannak


Nekünk három fájlra van innen szükségünk. A CA-ra, a certifikációnkra és a titkos kulcsunkra. A docker-machine a publikus kulcsot még telepítés közben felmásolta a VM-re.

# ll /root/.docker/machine/machines/mg0
total 316444
..
-rw-r--r-- 1 root root       1029 Jul 15 22:41 ca.pem
-rw-r--r-- 1 root root       1070 Jul 15 22:41 cert.pem
-rw------- 1 root root       1675 Jul 15 22:41 key.pem
...

Másoljuk a kulcsokat egy olyan mappába, ahol a böngészőt futtató user is eléri. (Ugyanis nagy valószínűséggel a root mappában jöttek ezek létre). A kulcsokat majd a Portainer webes telepítése közben majd tallózni kell.

A kulcsokon felül szükségünk lesz a master mg0 IP címére is, ezt kell megadni a Porainer-nek:

# docker-machine ip mg0
192.168.42.41

A port, ahogy már írtuk, az alapértelmezett TLS docker remote port: 2376
Ez az alapértelmezett remote port a docker démonnak. Szerencsére ez a port elve nyitva van a boot2docker operációs rendszerben.

Portainer telepítése

A Portainer-hez egyetlen egy image-et kell telepíteni: portainer/portainer

# docker container run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
  • A webes konzol a localhost:9000 -as porton lehsz elérhető:
  • Ha a lokális docker démon-t is monitorozni akarjuk, akkor a docker démon socket-re rá kell kötni a portainer-t.


ImportantIcon.png

Note
Ha nem akarjuk a lokális daemon-t is monitorozni, akkor a -v /var/run/docker.sock:/var/run/docker.sock mount nem szükséges


Ha elindult a konténer, akkor válasszuk Remote lehetőséget

ClipCapIt-180716-005426.PNG
  • Adjuk meg a manager-t futtató VM IP címét a 2376 portal (alapértelmezett TLS port)
  • Kapcsoljuk be a TLS-t.
  • TLS CA certificate: ca.pem
  • TLS certificate: cert.pem
  • TLS key: key.pem


WarningIcon.png

Warning
Ha nem adunk olvasási jogot a docker-nek a kulcsokra, azt fogja kiírni a Portainer: "Unable to create node"


Majd mondjuk hogy connect. Ekkor bejön a desboard. Innentől kezdve a távoli manager docker démonjához kapcsolódunk.

Cluster monitorozása

Nyomjunk rá a Go to cluster visualizer linkre, vagy a baloldali menüben a swarm menüpontra.

ClipCapIt-180716-010553.PNG


Nézzük meg az mg0 node részleteit. Láthatjuk, hogy jelenleg ő a managerek vezetője:

ClipCapIt-180717-020139.PNG


Service futtatása

https://blog.scottlogic.com/2016/08/30/docker-1-12-swarm-mode-round-robin.html

Service létrehozása image-ből (swarm service)

A docker service create paranccsal egy darab docker image-ből készíthetünk a swarm cluster-en futó szolgáltatást. Megadhatjuk, hogy hány példány jöjjön létre belőle, de lényegében megegyezik a szintaxisa a docker run paranccsal.

Szolgáltatás definiálása

Hozzunk létre

# docker-machine ssh mg0 docker service create --name web --replicas 3 --mount type=bind,src=/etc/hostname,dst=/usr/share/nginx/html/index.html,readonly --publish 80:80 nginx


TipIcon.png

Tip
A docker 1.17-es verziójától kezdve, a --mount paramétert kell használni a -v (--volume) helyett a storage-ek kezelésére, a -v már elavult. Korábbi verziókban csak a swarm parancsokba lehetett használni, mostanra már a standalone docker parancsokban is ezt illik használni. A szintaktikája eltér a -v-től, ugyanis a --mount után név=érték párok következnek vesszővel elválasztva szemben a -v három :-al elválasztott tagjával. Azonban swarm szolgáltatás esetén elve csak a --mount használható, a -v nem.


Monitorozás

Listázzuk ki a swarm-unkon futó szolgáltatásokat. Ezt bármelyik manager-en kiadhatjuk:

# docker-machine ssh mg1 docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
yv47d25nc6dr        web                 replicated          3/3                 nginx:latest        *:80->80/tcp


Most listázzuk ki ps-el a szolgáltatás részleteit. Láthatjuk hogy a woker0, 1 és az mg1-re telepítette fel.

# docker-machine ssh mg1 docker service ps web
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
deytk9w7z3et        web.1               nginx:latest        worker0             Running             Running 14 minutes ago                       
j6lwloj4q101        web.2               nginx:latest        mg1                 Running             Running 14 minutes ago                       
wfhucxtrq7pm        web.3               nginx:latest        worker1             Running             Running 14 minutes ago  


Nézzük meg a portainer-ben is az új szolgáltatásunkat a services menüpont alatt:

ClipCapIt-180717-225101.PNG
ClipCapIt-180717-231415.PNG



Load balancing

Nézzük meg a swarm nativ load balancert. Hívjuk meg a cluster bármelyik tagjának a publikus IP címét a 80-as porton:

# curl http://192.168.42.41:80
worker0
# curl http://192.168.42.41:80
worker1
# curl http://192.168.42.41:80
mg1

Minden egyes hívásra egy másik lábra fogunk beesni. Ez az elvárt működés. Ha máshogy nem határozzuk meg a swarm szolgáltatás telepítése közben, akkor a natív Layer 4 szolgáltatás rétegbeli load balancer lesz bekapcsolva. Az összes swarm node-on fut a load balancer egy példánya, és ezek össze vannak kötve az úgynevezett routing mesh-el, az ingress hálózaton. Így teljesen mindegy melyik lábra esünk be, az a load balancer példány ami azon a lábon fut, ahova beestünk, át fogja irányítania a kérést annak a node-nak aki a "globális" load balanc algoritmus szerint a soron következő. Ha másképp nem adjuk meg, akkor a load banac-olás round rubin, tehát mindig a soron következőt adja.

ClipCapIt-180718-210427.PNG


Részletek a Routing mesh című fejezetben.

Scaling

A replikák számát a docker service scale paranccsal változtathatjuk meg. Növeljük meg 5-re:

# docker-machine ssh mg0 docker service scale web=5
web scaled to 5


Majd nézzük meg mi lett:

# docker-machine ssh mg1 docker service ps web
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
deytk9w7z3et        web.1               nginx:latest        worker0             Running             Running 28 minutes ago                           
j6lwloj4q101        web.2               nginx:latest        mg1                 Running             Running 28 minutes ago                           
wfhucxtrq7pm        web.3               nginx:latest        worker1             Running             Running 28 minutes ago                           
7nwtcd43vva9        web.4               nginx:latest        worker2             Running             Running about a minute ago                       
kbz72e0wf1ba        web.5               nginx:latest        mg2                 Running             Running about a minute ago      


A portanier-ben egy kattintással növelni tudjuk a szolgáltatás replika számát felfelé vagy lefelé a scale nyílra kattintva a Services listában.

ClipCapIt-180717-225520.PNG



Swarm stack

A docker stack szolgáltatások összessége, amik együttesen egy közöz applikációt alkotnak a cluster-en. Lényegében a docker compose swarm mode-ra adaptált változata. A stack-et ugyan úgy egy yml fájlban kell leírni, akárcsak a docker compose esetén, azonban a yml fájlban van egy extra szekció a szimpla docker compose-hoz képest, ez a deploy, amivel a swarm cluser-nek adhatunk utasításokat, mint pl, hogy hány példányban fusson egy adott image a stack-en belül.



Networking

Hálózat típusok

Háromféle fontos hálózat típus van a swarm-ban az alap docker hálózatokon felül (ebből egyik a másik részlalmaza)
https://docs.docker.com/v17.09/engine/swarm/networking/


  • overlay network: Ez egy hostokon átívelő virtuális hálózat fajta, amit a docker emulál. (tehát nem Linux kernel funkció). A rá kapcsolódott konténerek számára transzparensen működik, hiába vannak más és más fizikai hálózatokban, úgy látják, mind ha közös hálózaton lennénk. Az overlay hálózatot a docker az úgynevezett overlay driver-el hozza létre. Ezzel emulálja a hálózatot.


  • ingress network: Ez egy speciális overlay hálózat, ebből csak 1 lehet egy swarm-on belül. Nem a neve, hanem a típusa számít. Ha mi nem hozzuk létre, akkor a docker fogja létrehozni a cluster inicializálásakor. Ezt load-balancolásra használja a docker. Ha bármelyik swarm node -ra érkezik egy kérés (akár olyanra is amin nem is fut konténer) akkor is továbbítja a kérést a megfelelő node-ra. A load-balancer-t a Linux kernelben található IPVS-el hozza létre, ami egy szállítási réteg beli load-balancer. A megfelelő konténer megtalálását (IP cím + port) az úgynevezett "routing mesh" végzi.


  • docker_gwbridge: Nem teljesen értem mire jó. Egy fizikai hálózati elem, tehát nem a docker emulálja. Az overlay network és a node interfésze között hoz létre egy virtuális hidat. Ha nincs, akkor a docker létrehozza. A neve számít. Ha újat akarunk csinálni, akkor Linux operendszer szinten kell törölni, majd egy pont ilyen nevű új hálózatot kell létrehozni a megfelelő paraméterekkel.



ClipCapIt-180718-213610.PNG



Overlay hálózatok

Átekintés

http://blog.nigelpoulton.com/demystifying-docker-overlay-networking/

  • A beépített ingress overlay hálózaton felül mi is létrehozhatunk kézzel új overlay hálózatokat. Az overlay hálózatot össze kell rendelni swarm service-ekkel (ami swarm stack-en belül is lehet)
  • Ha egy swarm service-t, egy overlay hálózathoz rendelünk, akkor az adott service összes konténere (akkor is ha távoli node-okon vannak) képes lesz egymással kommunikálni.
  • Az overlay hálózatot a manager csak azokra a node-okra fogja kiterjeszteni, amik a megadott szolgáltatás konténereit futtatják. Egészen addig csak a manager-en létezik.
  • Az overlay hálózat csak a node-on futó konténerből fog látszani. A konténerben létre fog jönne egy interfész, ami az overlay hálózatra csatlakozik, itt fog kiosztani egy IP címet az overlay network a konténernek. Tehát fontos, hogy a node gépen nem jön létre olyan interfész, ami az overlay hálózatra csatlakozok. A node gépen csak egy bridge jön létre.
  • A docker a VXLAN tunel technológiát használja az overlay hálózatok létrehozására. Egy Layer 3 hálózaton hoz létre egy virtuális Layer 2 hálózatot.


Az alábbi ábrán a C1 és C2 konténereken jött létre overlay interfész, aminek az overlay bridge kiosztotta a 10.0.0.3 ill a 10.0.0.4 IP címét. Látható hogy a node1 és node2 hoszt gépeken csak a bridge található, azok nem kaptak overlay IP címéet. A két bridge-et a VXLAN tunnel köti össze.

ClipCapIt-180718-225331.PNG

Hálózat létrehozása

Overlay hálózatot csak a manager node-okon lehet létrehozni a -d overlay kapcsoló használatával. Hozzuk létre az over-test hálózatot.

# docker-machine ssh mg0 docker network create -d overlay over-test


Egészen addig, amíg nem rendeljük szolgáltatáshoz az overlay hálózatot, csak a manager node-okon lesz listázható. Figyeljük meg, hogy az mg0-án hoztuk létre, de az mg1-en is látszik:

# docker-machine ssh mg1 docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
idf7f51tp95i        ingress             overlay             swarm
...
6hig77pse2xt        over-test           overlay             swarm <<<
ClipCapIt-180718-235218.PNG

Viszont a worker1-en nem látszik. (Aki nem hiszi nézze meg)


Most hozzunk létre egy új szolgáltatást két replikával, és rendeljük hozzá az új over-test overlay hálózathoz. A hálózatot a --network kapcsolóval kell megadni. A szolgáltatásneve test lesz. (Természetesen a manager node-ok egyikén kell létrehozni az új szolgáltatást)

# docker-machine ssh mg1 docker service create --name test \
--network over-test \
--replicas 2 \
ubuntu sleep infinity


Nézzük meg a test szolgáltatás részleteit, hogy lássuk melyik node-okon fut:

# docker-machine ssh mg1 docker service ps test
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
ldg4tr5olwmv        test.1              ubuntu:latest       worker2             Running             Running 50 seconds ago                       
5vxd6u2zgv1d        test.2              ubuntu:latest       mg0                 Running             Running 54 seconds ago                  
ClipCapIt-180718-232113.PNG

Láthatjuk, hogy létrejött a szolgáltatás két példánya az mg0-án és worker2-ön.


Listázzuk ki a worker2 docker hálózatait. Láthatjuk, hogy a swarm a worke2-re is kiterjesztette az over-test overlay hálózatot.

# docker-machine ssh worker2 docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
911906e5a269        bridge              bridge              local
5125832d68a8        docker_gwbridge     bridge              local
73a48e5dd720        host                host                local
idf7f51tp95i        ingress             overlay             swarm
ae8e1b7bd437        none                null                local
6hig77pse2xt        over-test           overlay             swarm <<<<



Tesztelés

Innentől kezdve a test szolgáltatás két konténere elérik egymást az over-test hálózaton. Ezt demonstrálva, a test szolgáltatás m0-án futó konténeréből meg fogjuk pingelni a worker2-n futó konténert.

ClipCapIt-180722-171736.PNG

Próbáljuk ki. Derítsük ki a worker2-n futó ubuntu konténer over-test hálózati IP címét. Elsőként listázzuk az overlay hálózatunk részleteit:

# docker-machine ssh worker2 docker network inspect over-test
...
        "Name": "over-test",
        "Driver": "overlay",
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
        "Peers": [
                "Name": "c3651bad2030",
                "IP": "192.168.42.136" <<< ez itt nem az overlay cím, hanem a host címe!!!

                "Name": "41d7e29fc1fc",
                "IP": "192.168.42.41"
ClipCapIt-180718-232653.PNG

Láthatjuk, hogy a over-test overlay hálózatunk alhálózata két végpont csatlakozik, ezen felül láthatjuk hogy az overlay hálózatunk IP tartománya a 10.0.0.0/24. Az egyik peer a worker2, a másik az mg0 (De ez nem innen látszik :) )

ImportantIcon.png

Note
Fontos látni, hogy a Peers alatt felsorolt IP címek nem az overlay interfészek címe, hanem azoknak a VM-eknek (valódi gépeknek) a 'publikus' IP címei, ahol azok a konténerek futnak, akik csatlakoznak az over-test overlay hálózatra.


Ki kell deríteni, hogy mi a worker2-ön futó ubuntu konténer azon interfészének az IP címe, ami az over-test overlay hálózatra csatlakozik. Ehhez elsőként be kell ssh-zni a worker2 node-ra, majd az ott futó ubuntu konténerhez kell csatlakozni interaktív módon, hogy listázni tudjuk az interfészeit:

# docker-machine ssh worker2
docker@worker2:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             
236f0a0cc334        ubuntu:latest       "sleep infinity"    35 minutes ago   
 
docker@worker2:~$ docker exec -it 23 bash
       
root@239f2a1d9bc1:/# apt-get update && apt-get install net-tools

root@239f2a1d9bc1:/# ifconfig | grep 10.0.0.
        inet 10.0.0.10  netmask 255.255.255.0  broadcast 10.0.0.255

Tehát a worker2 node-on futó ubuntu konténer overlay címe: 10.0.0.10


Pingeljük meg az mg0-en futó ubuntu konténerből a worker2-n futó konténert. Ha megnézzük a mg0-en futó konténereket, láthatjuk a test szolgáltatáshoz tartozó ubuntu konténert:

# docker-machine ssh mg0 docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             
426f0a0bb381        ubuntu:latest       "sleep infinity"    35 minutes ago     

Ebből az ubuntu konténerből fogjuk pingelni a test szolgáltatás másik konténert, ami a worker2 gépen fut (ami elvileg egy fizikailag teljesen máshol lévő gép is lehetne)

Elsőként ssh-val be kell lépni az mg0-ra. Majd az ubuntu konténeren futtassuk interaktív módon a bash-t. Ez után fel kell telepíteni a ping parancsot, majd már futtathatjuk is a ping-et.

# docker-machine ssh mg0

docker@mg0:~$ docker exec -it 426f0a0bb381 bash

root@426f0a0bb381:/# apt-get update && apt-get install -y iputils-ping

root@426f0a0bb381:/# ping 10.0.0.10     
PING 10.0.0.10 (10.0.0.10) 56(84) bytes of data.
64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=1.07 ms
64 bytes from 10.0.0.10: icmp_seq=2 ttl=64 time=1.34 ms

Láthatjuk, hogy a mg0-án lévő konténer képes kommunikálni a worker2-n lévő másik test konténerrel, mivel mind a ketten ugyan ahhoz az overlay hálózathoz (is) csatlakoznak.

Ingress hálózat

Ahogy azt már láthattuk, az ingress network virtuálisan összeköti az összes swarm node-ot, még akkor is ha azok nem egy lokális hálózaton vannak. Annyi a megkötés, hogy a node-oknak el kell tudni egymást érni az alábbi portokon:

  • 7946 TCP/UDP for container network discovery.
  • 4789 UDP for the container ingress network.

Az ingress hálózat segítségével tudja megvalósítani a swarm a stateless load balancer funkciót alapértelmezetten round rubin módon.


Bármelyik swarm node-on (akár manager, akár worker) kiadhatjuk a docker network ls parancsot, ugyan azt kell látni.

# docker-machine ssh mg0 docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b71223c228cd        bridge              bridge              local 
410e603aa9c2        docker_gwbridge     bridge              local 
53cd23b3594b        host                host                local
idf7f51tp95i        ingress             overlay             swarm <<<<
4fb53b47cf55        none                null                local

Ha mi magunk nem hoztunk létre új overlay hálózatot kézzel, akkor csak az ingress hálózat lesz swarm scope-ú, az összes többi hálózat lokális lesz



  • overlay hálózatból többet is csinálhatunk, de csak egynek lehet ingress a típusa. Az alapértelmezett ingress hálózaton felül a --network kapcsolóval adhatunk meg további overlay hálózatokat a docker service create -nek.
  • Ha az ingress hálózatnak nem megfelelőek az alapértelmezett beállításai, pl nem jó az IP tartomány, vagy a service-ek egymás között kommunikációját is titkosítani a akarjuk, akkor sajnos ki kell törölni és kézzel létre kell hozni --ingress kapcsolóval.
  • Ez a docker által létrehozott eszköz, nem a linux kernel hozza létre
  • Egyszerre csak egy ingress típusú hálózat lehet létezhet egy swarm-ban, ezért fontos, hogy előtt kitöröljük. A neve bármi lehet, nem csak ingress. A swarm nem a neve alapján fogja megtalálni, hanem a típusa alapján. Mivel csak egy lehet, ezért ez egyértelmű.
  • az egyetlen hálózat swarm scope-al
docker network create \
  --driver overlay \ 
  --ingress \ 
  --subnet=10.11.0.0/16 \
  --gateway=10.11.0.2 \
  -- --opt encrypted \  <<<  a service-ek kommunikációját titkosítja 
  --opt com.docker.network.driver.mtu=1200 \
  my-ingress




docker_gwbridge ??

  • A docker_gwbridge egy valódi fizikai hálózat, egy virtuális bridge, amit a Linux kernel-ben hoz létre a docker. Ezt láthatjuk a VM-en kiadott ifconfig paranccsal
  • viszont itt a név nagyon is számít. Mivel ez egy fizikai hálózat, a docker pont ilyen néven fogja keresni, mikor a swarm -ot létrehozza. Ha nincs készíteni fog egy újat, ha már van, akkor ezt fogja felhasználni.
  • Ha módosítani akarnánk, akkor ki kell törölni Linux parancsokkal (pl: ip), majd kézzel létre kell hozni az új beállításokkal a docker network create paranccsal.


# docker-machine ssh mg0 docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b71223c228cd        bridge              bridge              local 
410e603aa9c2        docker_gwbridge     bridge              local <<<<
53cd23b3594b        host                host                local
idf7f51tp95i        ingress             overlay             swarm <<<<
4fb53b47cf55        none                null                local


# docker-machine ssh mg0 ifconfig
...
docker_gwbridge Link encap:Ethernet  HWaddr 02:42:DF:B6:9C:AE  
          inet addr:172.18.0.1  Bcast:172.18.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:dfff:feb6:9cae/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:1418 (1.3 KiB)




Load balancing

Routing mesh for stateless services

ClipCapIt-180718-210427.PNG

A dokker-ben van egy beépített "layer 4", szállítási rétegbeli, beépített load balnacer.

Ha a --publis kulcsszóval hozunk létre úgy szolgáltatást, akkor

  • Ahogy azt már a bevezetőben láthattuk, az úgynevezett routing mesh felelős azért, hogy egy külső portról elérjük a swarm szolgáltatást egy megadott porton.
  • A --publish kulcsszóval kell regisztrálni a port mapping-et. A published a külső még a target a belső port.
WarningIcon.png

Warning
A routing mesh-t logikus módon csak akkor tudjuk használni, ha minden host-on a service-nek csak 1 példánya fut. Különben ki kell kapcsolni a routing mesh-t (lásd lentebb)


$ docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx


Vagy meglévő szolgáltatáshoz meg lehet adni új port mapping-et a --publish-add kapcsolóval.

$ docker service update \
  --publish-add published=8080,target=80 \
  my-web



A --publish és --publish-add parancs alapértelmezetten csak tcp portot ad hozzá. A protocol=udp kapcsolóval lehet udp portot is hozzáadni

--publish published=53,target=53,protocol=udp


A routing mesh akkor van bekapcsolva egy adott service-re, ha a --publish kapcsolónak megadjuk ezt: mode=ingress Ez az alapértelmezett. Ha ki akarjuk kapcsolni a routing mesh-t, akkor ezt host-re kell állítani:

# docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  dns-cache



Load balancing for statefull services

Traefik

Áttekintés

A Traefik egy univerzális Layer 7 (http) load-balancer és reverse proxy. Direkt microservice környezetre találták ki és támogatja is gyakorlatilag az összes konténer orchestration platformot és többféle service discovery szolgáltatást is:

  • Docker
  • Swarm mode <<<
  • Kubernetes
  • Marathon
  • Consul, Etcd --> service discovery
  • Rancher
  • Amazon ECS)

A docker-swarm-ot natívan támogatja. Telepíthető docker image-ként, és van hozzá webes információs felület is.

A Traefik úgy működik, hogy valamelyik swarm manager-tről periodikusan lekérdezi az aktuális swarm konfigurációt (szolgáltatások, és azokat futtató node-ok listája). Ez alapján teljesen automatikusan konfigurálja magát és változás estén újra konfigurálja magát (pl. ha nő vagy csökken a cluster, vagy ha új szolgáltatás kerül telepítésre). Mivel magától leköveti a swarm cluster változásait, ideális megoldás mint reverse proxy és Layer 7 load balancer.

A Traefik-et futtató node publikus IP címén lesz elérhető az összes Traefik által kezelt szolgáltatás. Minden szolgáltatás a következő formán érhető el:

http://<traeif node public IP>/<PathPrefix>


A PathPrefix-et a swarm szolgáltatás telepítése közben kell megadni label-ek segítségével. A Traefik nem kezd el automatikusan minden a cluster-re telepített szolgáltatáshoz load balancer/reverse proxy szolgáltatást nyújtani. A neki szánt szolgáltatásokat a szolgáltatás telepítése közben megadott traefik specifikus címék segítségével azonosítja be és konfigurálja.


Több fórumon is azt írják, hogy a Traefik-et csak valamelyik manager node-on lehet futtatni. Egyrészről ez nem igaz, másrészről hiba lenne ha így lenne. A manager node-ot egyrészt nem szabad load-balanc feladatokkal terhelni. Ha a manager-t túlterhelnénk, leállhat a swarm cluster-ünk. Másrészről másféle hardver konfigurációra van szükség load-balanceoláshoz mint swarm manager futtatásához nem is beszélve a tűzfal szabályokra/hálózati beállításokra. (A manager node-koat nyilván nem lehet elérni a publikus internetről). Ugyan a Traefik dokumentációból ez implicit nem derül ki, de ettől még lehet remote worker node-on futtatni a Traefik-et.


A Traefik a docker swarm API-n keresztül olvassa ki a swarm adatait (szolgáltatások, címék és nodok). Ezt vagy valamelyik manager lokális socker-jét csatlakozva teheti meg, vagy a docker remote API-n keresztül, ami általában TLS felett fut (pláne produkciós környezetben). Nyilván a legegyszerűbb ha az egyik manager node-ra telepítjük föl, és ott mount-oljuk a manager docker engine lokális socket-jét:

/var/run/docker.sock:/var/run/docker.sock

Így s swarm információkat ki tudja olvasni a lokális docker démonból. Azonban ezt csak tesztelésre szabad így megcsinálni, ahogy erre több helyen is felhívják a figyelmet. Ha megnézzük a Traefik konfigurációs leírásának docker szekcióját, találunk benne egy ilyet:

# Can be a tcp or a unix socket endpoint.
endpoint = 

Ezen felül van benne egy TLS szekció is:

[docker.tls]
 ca = ...

Tehát képes távoli docker démonhoz kapcsolódni TLS felett a portainer-hez hasonlóan. Tehát ez a része kipipálva.


Van még egy fontos megkötés. A Traefik-nek közös overlay hálózaton kell lenni az összes olyan konténerrel, akiknek load-balancer szolgáltatást nyújt, mindjárt meglátjuk miért. Nyilván az ingress (routing mesh) hálózaton lévő konténer interfészek nem megfelelőek layer 7 load balanc-olásra, mert ott már fut egy layer 4 load banacer, ami minden egyes kérésre másik node-ra irányítja a kérést, tehát a konténerek "publikus" IP címe nem megfelelő. Olyan konténer interfészekre van tehát szükségünk, aminek az IP címeit le lehet kérdezni a swarm master-től (szolgáltatásonként csoportosítva) de nem fut rajta a routing mesh, viszont fontos, hogy a load-balance-olás miatt a Traefik elérje ezen a hálózaton az összes konténert. Ezért létre kell hozzunk a Traefik számára egy új overlay hálózatot, amire egyrészt a Traefik, másrészt minden olyan konténer csatlakozik, ami olyan szolgáltatás része, amihez a Traefik load balancer szolgáltatást nyújt.


A Traefik-et futtathatjuk standalone módban is, docker nélkül egy távoli VM-en, viszont bárhol is fut, fontos, hogy rálásson a fent említett, közös overlay hálózatra. Nyilván ezt a legegyszerűbben úgy érhetjük el, hogy a Traefik-et is swarm szolgáltatásként indítjuk el a cluster-ben egy erre dedikált node-on, így nem kell külön azzal bajlódni, hogy egy cluster-en kívüli entitást csatlakoztassunk egy docker-es overlay hálózatra, ami nem lenne túl egyszerű. Így viszont a manager-ek ezt automatikusan megcsinálják.

ClipCapIt-180728-211924.PNG

A példában az összes kék doboz egy swarm cluster-be van kötve. A swarm clusre-nek két manager-e van, és három worker node-ja. A worker node-okra rá van telepítve egy darab swarm szolgáltatás, ami három példányban fut, miden node-on 1 konténer fut a test nevű szolgáltatásból. Szintén a cluster-re van telepítve a Traefik szolgáltatás, ami egy példányban fut, és ki van erőszakolva, hogy a loadbalancer nevű node-on hozza létre a swarm. A Traefik egy szem konténere a remote docker API-n keresztül rácsatlakozik a 0. számú manager node-ra, és onnan lekéri a szolgáltatások listáját. Meg fogja kapni a Teszt szolgáltatást. Ezután szintén a remote docker API-n keresztül le fogja kérni a Teszt szolgáltatást futtató node-ok IP cím listáját, ekkor fogja megkapni a következő listát: 10.0.0.2, 10.0.0.3, 10.0.0.4. Innentől kezdve, ha a http://example.com/test URL-re érkezik kérés, akkor mindig a 10.0.0.2,3, vagy 4-es IP -jű konténerre fogja irányítani a kérést a saját overlay hálózatán keresztül (az ábrán ezt hívják Traefik overlay hálózatnak). Látható, hogy ettől függetlenül minden node csatlakozik a beépített ingress overlay hálózatra, de a Traefik load-balancing szempontjából annak most nincs jelentősége.

WarningIcon.png

Warning
Van egy kisebb probléma a Traefik jelenlegi architektúrájával, ami az ábrából is látszik. Jelenleg csak 1 darab remote docker API-t lehet konfigurálni a Traefik-nek, vagyis hiába van 3 manager node a cluster-ben, a Traefik sajnos csak egy dedikált manager node-hoz tud kapcsolódni, és ha az az egy manager node kiesik, akkor megszűnik a load banacer is --> single point of failure (SPOF). Ezzel gyakorlatilag értelmét veszti a manger node-ok közötti fail-over. Persze ez csak nagyon nagy cluster-eket érintő probléma. Ezt többen is feszegetik különböző fórumokon, vannak rá különböző hekmányolások, de szép megoldás még nincs rá


Overlay hálózat definiálása

Ahogy azt már láthattuk, szükség van egy dedikált overlay hálózatra, amire a Traefik konténer és az összes többi olyan konténer is rá lesz csatlakozva, amik részt vesznek a load-balancing-ban.

Bármelyik manager node-on futtassuk le az alábbi parancsot. Ha nem fontos az IP tartomány, akkor simán a docker network create paranccsal hozzuk létre az új hálózatot mindösszesen a -d overlay paraméter megadásával.

# docker-machine ssh mg0 docker network create -d overlay balancer-net
o4rhm35gkh24cd25rdt7hsm62


Nézzük meg (szintén a manager node-okon). Látható, hogy létrejött a swarm scope-ú új hálózatunk.

# docker-machine ssh mg0 docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
o4rhm35gkh24        balancer-net        overlay             swarm <<<<
e7b191c598c3        bridge              bridge              local
4648968db4af        docker_gwbridge     bridge              local
f1ab56710cf2        host                host                local
mzwld5ddadk6        ingress             overlay             swarm
b9b55fc2d01d        none                null                local


Megnézhetjük a Portainter-ben is az új hálózatot a Networks menüpontban:

ClipCapIt-180728-223041.PNG


Load balancer node elkészítése

Elsőként készíteni fogunk egy új VM-et kifejezetten a load balancer számára, és ezt be fogjuk léptetni a swarm cluster-be. Létre fogunk hozni egy címkét is az új node-nak: loadbalancer=true. Ezzel fogjuk kikényszeríteni, hogy a Traefik swarm szolgáltatás egy szem konténere erre a node-ra települjön, ezen felül szintén ezzel a címkével fogjuk elérni, hogy semmilyen más konténert ne tegyen erre a node-ra a swarm.


Az alábbi script létrehozza az új VM-et, belépteti a cluster-be, és rárakja a címkét:

#!/bin/bash

#Get worker token
WORKER_TOKEN=`docker-machine ssh mg0 docker swarm join-token -q worker`

#Create load balancer node

docker-machine create -d kvm --kvm-network "docker-network" --kvm-disk-size "5000" --kvm-memory "800"  loadBalancer

docker-machine ssh loadbalancer docker swarm join --token $WORKER_TOKEN $(docker-machine ip mg0)

docker node update --label-add loadbalancer=true loadbalancer


Lépjünk be valamelyik manager node-ra és ott kérdezzük le az új loadbalancer nevű node címkéit. Látnunk kell hogy rendelkezik a loadbanacer=true címkével.

# docker node inspect --format='{{.Spec.Labels}}' loadbalancer
map[loadbalancer:true]

Traefik telepítése

A Traefik-et docker service-ként telepíteni kell a cluster-re, úgy hogy garantáltan loadbalancer nevű node-ra kerüljön, valamint csatlakozzon a balancer-net nevű overlay hálózatra. Ezen a ponton több lehetőségünk is van. Vagy a docker service create paranccsal definiáljuk az új szolgáltatást, vagy írunk egy compose (yml) fájlt, amiben a többi swarm szolgáltatással együtt telepítjük a Traefik-et is. Bármelyiket is választjuk, még azt is eldönthetjük, hogy megadunk a Traefik szolgáltatásnak (mivel csak egy példány lesz, mondhatnám azt is, hogy a Treaefik konténernek) egy külső konfigurációs fájt, vagy cmd argumentumokkal adjuk meg a teljes konfigurációt.

ImportantIcon.png

Note
Ne feledjük el, hogy csak is azért telepítjük swarm szolgáltatásként a Traefik-et, hogy egy mozdulattal rá tudjuk kötne egy közös docker overlay hálózatra, amin azok a konténerek is lógnak majd, akik olyan szolgáltatáshoz tartoznak, akiknek load balnacer szolgáltatást kell nyújtani. Ez ahhoz kell, hogy a Traefik le tudjon kérdezni olyan végpont listát a manager node-tól, ami független a routing mesh-től, és amin keresztül a Traefik el is éri a szóban forgó konténereket.


Mi most a docker service create megközelítést fogjuk alkalmazni:

docker service create -d -p 8080:8080 -p 80:80 --name loadbalancer \
--mount type=bind,src=/home/docker/traefik.toml,dst=/etc/traefik/traefik.toml \
--mount type=bind,src=/home/docker/ssl,dst=/etc/ssl --constraint node.labels.loadbalancer==true \
--network test_default traefik



# docker service ps loadbalancer 
ID                  NAME                 IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR                              PORTS
v524v9oqqpz7        loadbalancer.1       traefik:latest      loadbalancer        Running             Preparing 9 seconds ago                                      
4vnxiyz8xwoa         \_ loadbalancer.1   traefik:latest      loadbalancer        Shutdown            Rejected 9 seconds ago    "invalid mount config for type…"   

Ami a \_ -el van írva, azok elhalt kísérletek. De mivel alapértelmezetten mindig újra indítja a swarm, ezért mindig keletkezik egy új task, (a régi mindig "Shutdown" állapotban van.


ClipCapIt-180728-165011.PNG














http://www.littlebigextra.com/how-to-maintain-session-persistence-sticky-session-in-docker-swarm-with-multiple-containers/
https://boxboat.com/2017/08/03/deploy-web-app-docker-swarm-sticky-sessions/

ClipCapIt-180719-233145.PNG

https://traefik.io/

version: "3"
 
services:
 
  loadbalancer:
    image: traefik
    command: --docker \
      --docker.swarmmode \
      --docker.watch \
      --web \
      --loglevel=DEBUG
    ports:
      - 80:80
      - 9090:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      restart_policy:
        condition: any
      mode: replicated
      replicas: 1
      update_config:
        delay: 2s
      placement:
         constraints: [node.role == manager]
    networks:
      - net
 
networks:
  net:[


version: "3"
 
services:
 
  whoami:
    image: tutum/hello-world
    networks:
      - net
    ports:
      - "80"
    deploy:
      restart_policy:
        condition: any
      mode: replicated
      replicas: 5
      placement:
        constraints: [node.role == worker]
      update_config:
        delay: 2s
      labels:
        - "traefik.docker.network=test_net"
        - "traefik.port=80"
        - "traefik.frontend.rule=PathPrefix:/hello;"
        - "traefik.backend.loadbalancer.sticky=true"

http://192.168.42.79:9090/dashboard/

ClipCapIt-180719-232503.PNG

cendra/virtualhost

https://hub.docker.com/r/cendra/virtualhost/

NGINGX

https://www.nginx.com/blog/docker-swarm-load-balancing-nginx-plus/#nginx-demo



Auto scaling

A Docker swarm-ban nincs beépített auto scaling out of the box, nekünk kell implementálni, vagy használhatunk 3rd party eszközöket is. A Kubernetes-ben erre van egy remek beépített algoritmus, de a docker-swarm-ban is meg tudjuk ezt valósítani.

https://stackstorm.com/2017/06/22/autoscaling-swarm-aws-stackstorm/ https://github.com/sahajsoft/docker-swarm-service-autoscaler