Docker Swarm konfiguracija sa Nginx-om

Docker Swarm je alat za klasterizaciju i raspoređivanje Docker kontejnera sličan alatu Kubernetes. Sa Swarm-om je moguće napraviti klaster od Docker čvorova koji izgledaju kao jedan virtuelni sistem.

Uvod

Zamislite da imate veb sajt, i da saobraćaj na njemu naglo poraste tako da vaš server postaje preopterećen. Rešenje bi bilo da se prebacite na veći server, koji bi bez problema mogao da podnese ovaj nagli rast. Međutim, za to bi bilo potrebno izdvojiti značajna sredstva i vreme za konfigurisanje. Podnošljivija varijanta bi bila da zakupite još jedan, „manji“ server na kome će se nalaziti isti veb sajt i da balansirate saobraćajem.

Rešenje ovog problema ćemo predsatviti kreiranjem Docker Swarm klastera, na kojem će biti pokrenut Nginx veb server.

Docker Swarm je sistem za klasterizaciju Docker kontejnera. On pretvara nekoliko Docker čvorova u jedan virtuelni sistem koristeći API proxy sistem. Zbog toga što koristi standardni Docker API, svaki alat koji već komunicira sa Docker deamon-om, može koristiti Swarm da skalira na više čvorova transparentno. Otvorenog je koda, nastao kao alternativa Google-ovom Kubernetes-u.

O Docker-u i Kubernetes-u je već pisano na ovom blogu, a o tome se možete informisati preko sledećeg linka.

Nginx je veb server otvorenog koda, koji je poznat po visokim performansama, stabilnosti, jednostavnoj konfiguraciji i malim memorijskim zahtevima. Više informacija o Nginx-u možete pronaći na sledećem linku.

Swarm arhitektura i koncepti

Swarm se kreira pomoću jednog ili više Docker Engine-a, koji koriste swarmkit za upravljanje klasterom i raspoređivanje. Možete omogućiti Swarm mod kreiranjem novog Swarm-a ili spajanjem na već postojeći.

Kada se koristi Swarm, ne pokreću se kontejneri, već servisi koji rade na čvorovima (nodes). Čvor je instanca Docker Engine, koji je član Swarm-a. Postoje dve vrste čvorova: čvorovi Menadžeri i čvorovi Radnici.

Menadžer čvor

Menadžer čvor prihvata definiciju servisa, a zatim otprema zadatak čvorovima Radnicima. Oni se takođe bave raspoređivanjem i upravljačkim funkcijama klastera potrebnim za održavanje Swarm-a. Može biti i više Menadžer čvorova u Swarm-u, ali samo jedan lider, koji je izabran od ostalih Menadžer čvorova korišćenjem Raft algoritma, čija je uloga raspoređivanje poslova.

Radnik čvor

Radnici primaju i izvršavaju zadatke od Menadžera. Podrazumevano, Menadžer čvor je takođe i Radnik, ali menadžeri mogu biti konfigurisani i tako da ne prihvataju nikakve poslove.

Servisi

Servis je definicija jednog ili više zadataka koje treba izvršiti na čvorovima radnicima. Kada se kreira servis, potrebno je naznačiti koji Image se koristi i koja komanda se izvrašava u kontejnerma. Servis može biti globalni ili replicirani. Kada je servis globalni, on se pokreće na svakom dostupnom čvoru odjednom. Kada je repliciran, Menadžer distribuira zadati broj poslova na čvorove.

Zadatak je kontejner i komande koje treba izvršiti unutar kontejnera. Zadatak je osnovna jedinica raspoređivanja u Swarm-u. Kada se zadatak dodeli jednom čvoru, ne može se premestiti na drugi čvor.

Virtuelizacija

Pomoću virtuelnih mašina postižemo da više izolovanih instanci budu pokrenute na jednoj mašini. U ovom slučaju to su više čvorova na kojima će se izvršavati kontejneri. Virtuelna mašina je instanca ordeđenog računarskog sistema sa operativnim sistemom i aplikacijama instaliranim koji koriste softver za emulaciju i pokreću se na host sistemu (što najčešće je fizički računar, a može biti i virtuelni). Sa druge strane, kontejneri su blaža verzija virtuelizacije koji se pokreću na vrhu kernela operativnog sistema, što znači da ne moraju sadržati operativni sistem, već samo kod i biblioteke potrebne da bi taj kod radio.

Instalacija

Da biste pokrenuli Docker u Swarm modu, potrebno je prvo da instalirate Docker. Instalaciju Docker-a možete pronaći na sledećem linku. Sledeće što ćemo instalirati je Docker Machine. Docker Machine je alat koji omogućava instalaciju Docker-a na virtuelnim čvorovima, i upravljanje tim čvorovima pomoću docker-machine komande. Više informacija o Docker Machine možete naći na sledećem linku.

Instalaciju Docker Machine možete izvršiti na sledeći način:

$ base=https://github.com/docker/machine/releases/download/v0.14.0 &&
curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
sudo install /tmp/docker-machine /usr/local/bin/docker-machine

Proverite da li je uspešno instaliran Docker Machine ispisivanjem verzije:

$ docker-machine version

Swarm klaster

Problem opisan u uvodu ćemo predstaviti inicijalizacijom Docker Swarm klastera sa tri čvora, na kojima će biti pokrenut Nginx servis. Okruženje u kojem je izrađen ovaj primer je Ubuntu 18.04.

Inicijalizacija čvorova

Pomoću alata docker-machine možete kreirati čvorove. Komandom docker-machine ls možete izlistati sve inicijalizovane čvorove. Mi treba da kreiramo tri čvora, jednog manager-a i dva worker-a. Da biste kreirali novi čvor potrebno je da pokrenete komandu:

$ docker-machine create manager

Ako je komanda uspešno izvršena, izlistavanjem svih čvorova na listi će biti manager. Na ovaj način se kreira mašina pomoću podrazumevanog driver-a, u ovom slučaju to je softver za virtuelizaciju VirtualBox.Ukoliko želite da pokrenete čvor na driver-u koji nije podrazumevani, to možete učiniti dodavanjem –driver driverName u komandu.

Sada je potrebno ponoviti isti postupak za worker1 i worker2 čvorove.

$ docker-machine create worker1
$ docker-machine create worker2

Pomoću komande

$ docker-machine env manager

možemo videti IP adresu čvora. Komanda env nam služi ukoliko želimo da neku od ovih mašina proglasimo za podrazumevanu Docker mašinu.

Povezivanje čvorova u Swarm klaster

Nakon što smo inicijalizovali čvorove, potrebno je da ih povežemo u klaster. Prvo ćemo se logovati u manager čvor, pomoću komande:

$ docker-machine ssh manager

Nakon uspešnog logovanja, potrebno je inicijalizovati Docker Swarm. Da bismo inicijlazivoali Swarm klaster, potrebna nam je IP adresa manager čvora. Klaster inicijalizujemo na sledeći način:

$ docker swarm init --advertise-addr 192.168.99.100

gde je 192.168.99.100 IP adresa manager čvora. Nakon izvršenja ove komande dobićemo komandu za povezivanje ostalih čvorova u Swarm klaster. Komanda u ovom primeru izgleda ovako:

$ docker swarm join --token SWMTKN-1-0w35606lat3l0c6r4mffux9s5ormjjqk4f4qhj17bpjdoqtg3y-6nt07i1vihn59wi3llmod4sqj 192.168.99.100:2377

Sada je potrebno ulogovati se na preostala dva čvora i pokrenuti komandu za povezivanje:

$ docker-machine ssh worker1
$ docker swarm join --token SWMTKN-1-0w35606lat3l0c6r4mffux9s5ormjjqk4f4qhj17bpjdoqtg3y-6nt07i1vihn59wi3llmod4sqj 192.168.99.100:2377
$ exit
$ docker-machine ssh worker2
$ docker swarm join --token SWMTKN-1-0w35606lat3l0c6r4mffux9s5ormjjqk4f4qhj17bpjdoqtg3y-6nt07i1vihn59wi3llmod4sqj 192.168.99.100:2377
$ exit

Nakon pokretanja komande na oba čvora radnika, dobili smo Swarm klaster sa tri čvora, kao što smo i želeli. Ukoliko želite da vidite da li je spajanje čvorova u klaster bilo uspešno, potrebno je da se ulogujete u manager čvor i proverite pomoću komande docker node ls.

Pokretanje Docker servisa Nginx

Nakon uspešne inicijalizacije Swarm klastera, potrebno je da se ulogujemo u manager čvor i pokrenemo servis Nginx. Nginx servis pokrećemo pomoću sledeće komande:

$ docker service create --name mynginx --publish 8080:80 --replicas 3 nginx

Nakon uspešnog pokretanja i skaliranja na sva tri čvora, možete u internet pregledaču proveriti da li je sve pokrenuto. Ukucajte adresu manager čvora i port 8080. U ovom slučaju bi to bila adresa 192.168.99.100:8080, i pojaviće se početna strana Nginx-a.

Sada ćemo prepisati početne strane Nginx-a na čvorovima kako bismo ih međusobno razlikovali. Potrebno je prvo ulogovati se na čvor, zatim pomoću komande docker ps proveriti ID kontejnera kome želimo da pristupimo, a zatim mu pristupimo pomoću sledeće komande:

$ docker-machine ssh manager
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
95e528468e1d        nginx:latest        "nginx -g 'daemon of…"   About an hour ago   Up About an hour    80/tcp              mynginx.1.nsahtuqdgbny3knyczmu2sbfp
$ docker exec -ti 95e528468e1d /bin/bash

Nakon toga ćemo pomoću bash-a pristupiti ovom kontejneru. Sada ćemo prepisati početnu stranu na sledeći način:

$ echo "Hello from Manager node!" > /usr/share/nginx/html/index.html

Isti postupak ponovite na ostalim čvorovima.

$ docker-machine ssh worker1
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
d7d998ec44f8        nginx:latest        "nginx -g 'daemon of…"   About an hour ago   Up About an hour    80/tcp              mynginx.2.s8dcw8hhx7zgp3rhjfucqhs1d
$ docker exec -ti d7d998ec44f8 /bin/bash
$ echo "Hello from Worker1 node!" > /usr/share/nginx/html/index.html
$ exit

$ docker-machine ssh worker2
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
204a8e7ef06c        nginx:latest        "nginx -g 'daemon of…"   About an hour ago   Up About an hour    80/tcp              mynginx.3.mfdfebbtdlft1oga0drpgh8zs
$ docker exec -ti 204a8e7ef06c /bin/bash
$ echo "Hello from Worker2 node!" > /usr/share/nginx/html/index.html
$ exit

Sada ako opet proverite istu adresu, dobićete poruku sa čvora manager. Ako iz komandne linije pokrenemo sledeće

$ curl -s http://192.168.99.100:8080/
Hello from Manager node!
$ curl -s http://192.168.99.100:8080/
Hello from Worker1 node!
$ curl -s http://192.168.99.100:8080/
Hello from Worker2 node!

Dobićemo rezultate iz različitih kontejnera. To je zato što Swarm raspoređuje izvršenje zahteva čvoru koji je trenutno najmanje opterećen. Testiranjem pomoću alata ApacheBench komandom ab dobijamo iste rezultate. Da biste videli za pokretanje testnih primera iz kog kontejnera je stigao odgovor potrebno je da se ulogujete na svaki čvor, i pomoću komande docker logs ContainerID ćete videti na koje zahteve je taj kontejner odgovorio.

Skaliranje servisa

Ukoliko želimo da skaliramo servis, potrebno je da se ulogujemo na manager čvor i pokrenemo sledeću komandu:

$ docker service scale mynginx=brojKontejnera

Nakon izvršenja komande, servis bi trebalo da bude pokrenut na zadati broj kontejnera. Naravno, servis treba da bude pokrenut u replikativnom modu, da bi skaliranje uopšte bilo moguće.

Šta se dešava ako smo zatražili više kontejnera nego što imamo čvorova?

Swarm će rasporediti te kontejnere po postojećim čvorovima, tako da korišćenje resursa bude izbalansirano. Ako nema dovoljno resursa za pokretanje novog kontejnera, pojaviće se greška pri pokretanju, što ne znači da neće raditi servis i kontejneri koji su ranije funkcionisali. Platforme kao što su Amazon Web Services i Microsoft Azure pružaju usluge monitoringa kontejnera, pa biste mogli da podesite da se na neke događaje pokreću skripte, i na taj način biste mogli da instancirate novi čvor na kome bi bilo moguće pokrenuti kontejner. Pored toga, ove platforme pružaju mogućnost podizanja novog kontejnera ukoliko bi opterećenje resursa dostiglo određeni prag (npr. 70% korišćenja CPU-a).

Otkazivanje čvorova

Sada ćemo ispitati šta se dešava ako neki od čvorova radnika otkaže. Ulogovaćemo se u manager čvor i izlistati sve kontejnere koje naš servis poseduje i na taj način videti koji kontejner se nalazi na kom čvoru:

$ docker-machine ssh manager
$ docker service ps mynginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
r02d2je9ungm        mynginx.1           nginx:latest        worker1             Running             Running 15 minutes ago                       
qomigoy86zq7        mynginx.2           nginx:latest        worker2             Running             Running 15 minutes ago                       
plsv09km2sgu        mynginx.3           nginx:latest        manager             Running             Running 16 minutes ago     
$ exit

Kao što vidimo, sva tri čvora imaju po jedan kontejner na sebi. Pomoću komande docker-machine rm worker2 ćemo izbrisati čvor worker2, i nakon toga se ponovo se ulogovati u manager čvor kako bi izlistali sve kontejnere servisa:

$ docker-machine ssh manager
$ docker service ps mynginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
r02d2je9ungm        mynginx.1           nginx:latest        worker1             Running             Running 20 minutes ago                       
de3yiixnjj1b        mynginx.2           nginx:latest        manager             Running             Running 4 seconds ago                        
qomigoy86zq7         \_ mynginx.2       nginx:latest        worker2             Shutdown            Running 20 minutes ago                       
plsv09km2sgu        mynginx.3           nginx:latest        manager             Running             Running 21 minutes ago      
$ exit

Kao što možete primetiti, kontejner koji se nalazio u worker2 čvoru je ugašen, a na manager čvoru je momentalno podignut novi kontejner kako bi servis ostao skaliran na tri kontejnera.

Postavlja se pitanje šta bi se desilo ako bi uklonili manager čvor? Ukoliko bismo uklonili manager čvor, Swarm više ne bi funkcionisao i servis mynginx više ne bi postojao. Kontejner koji se nalazio na čvoru worker1 bi i dalje radio i mogli bismo da pristupimo Nginx-u preko 192.168.99.101:8080, što bi u ovom slučaju bila IP adresa worker1 čvora. Preporučuje se arhitektura sa više manager čvorova, kako se ovakve stvari ne bi dešavale.

Literatura

Autor: Mateja Ašanin

Student master studija i asistent na Prirodno-matematičkom fakultetu u Kragujevcu, softverski inženjer u Levi9 IT Services.

Osnovne akademske studije završio je na Prirodno-matematičkom fakultetu u Kragujevcu 2018. godine, smer Informatika. Tokom studija bio je polaznik programa praksi u kompanijama Emisia Consulting, Comtrade SE, Technomedia doo i Levi9 IT Services.

Mateja Ašanin

Student master studija i asistent na Prirodno-matematičkom fakultetu u Kragujevcu, softverski inženjer u Levi9 IT Services. Osnovne akademske studije završio je na Prirodno-matematičkom fakultetu u Kragujevcu 2018. godine, smer Informatika. Tokom studija bio je polaznik programa praksi u kompanijama Emisia Consulting, Comtrade SE, Technomedia doo i Levi9 IT Services.