This is an old revision of the document!
În acest laborator, vom face tranziția de la Docker Compose la Docker Swarm, orchestratorul de servicii oferit de Docker. Acesta are rolul de a gestiona servicii de Docker pe una sau mai multe mașini într-o rețea (într-un cluster) de mașini fizice și/sau virtuale. Spre deosebire de Docker Compose, care rulează containere pe o singură gazdă, Docker Swarm rulează servicii între mai multe gazde. La fel ca și Compose, Docker Swarm folosește fișiere de configurare YAML.
Docker Swarm se bazează pe algoritmul distribuit Raft, cu ajutorul căruia se menține consistentă starea internă a întregului cluster. În plus, traficul dintre nodurile din Swarm este criptat de către Raft. În imaginea de mai jos (preluată din documentația oficială, se poate observa arhitectura unui cluster Docker Swarm.
Mașinile gazdă care fac parte dintr-un Swarm se numesc noduri și pot avea două roluri:
Dintre toate nodurile manager, un singur nod este leader, care are rolul de a crea task-uri și de a face logging. Task-urile sunt distribuite apoi nodurilor manager.
Odată ce avem un cluster de mașini pe care rulează Docker, ne putem inițializa un Docker Swarm. Astfel, putem rula următoarea comandă pe nodul care va fi leader (opțiunea –advertise-addr este necesară atunci când nodul are mai multe interfețe de rețea și trebuie specificat pe care din ele se face advertising):
$ docker swarm init --advertise-addr 192.168.99.100 Swarm initialized: current node (qtyx0t5z275wp46wibcznx8g5) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4hd41nyin8kn1wx4bscnnt3e98xtlvyxw578qwxijw65jp1a3q-32rl6525xriofd5xmv0c1k5vj 192.168.99.100:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Putem verifica dacă swarm-ul a fost creat cu succes dând comanda de mai jos pe mașina leader (unde avem două noduri numite node1 și node2, primul din ele fiind leader, iar al doilea worker):
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS qtyx0t5z275wp46wibcznx8g5 * node1 Ready Active Leader 0xbb9al1kuvn0jcapxiqni29z node2 Ready Active
Atunci când vorbim de deployment-ul unei aplicații în Docker Swarm, trecem de la noțiune de container la noțiunea de serviciu. Un serviciu Docker reprezintă o colecție de task-uri (unul sau mai multe), iar un task reprezintă un container. Așadar, un serviciu este format din unul sau mai multe containere identice. Serviciul controlează ciclul de viață al containerelor, încercând întotdeauna să mențină starea containerelor oferite în configurație. Cu alte cuvinte, un serviciu reprezintă un set de containere cu orchestrare.
Mai departe, o stivă de servicii reprezintă mai multe astfel de servicii grupate în același spațiu de nume. Putem vizualiza o stivă de servicii ca fiind o aplicație Docker formată din mai multe servicii. Cel mai facil mod de a defini o stivă de servicii este prin intermediul unui fișier Docker Compose, așa cum am văzut în laboratorul 2. Comportamentul serviciilor dintr-o stivă este similar cu cel al containerelor din Docker Compose, doar că politica de denumire este diferită.
Docker Swarm are acces la o colecție nouă de opțiuni în cadrul fișierului YML de Compose, ce vor fi trecute în proprietatea deploy a unui serviciu. Imaginea de mai jos prezintă un fragment de fișier Docker Compose unde se exemplifică o parte din aceste opțiuni noi:
[...] services: web: image: myimage deploy: replicas: 4 resources: limits: cpus: "0.2" memory: 50M restart_policy: condition: on-failure [...]
În fragmentul de fișier YAML de mai sus, se rulează un serviciu numit web care are patru copii. Astfel, vor exista patru containere diferite care rulează imaginea myimage, oricare din ele putând răspunde la cereri pentru serviciul web, în funcție de încărcare. De asemenea, fiecare instanță este limitată la 20% CPU (pe toate core-urile) și 50 MB de RAM. Nu în ultimul rând, un container al serviciului web se restartează imediat ce întâlnește o eroare (scopul final fiind ca, la orice moment de timp, să existe 4 copii ale containerului în rețea).
Spre deosebire de Docker clasic și Compose, rețelele create în Swarm nu mai sunt de tip bridge, ci de tip overlay. O rețea de tip overlay este o rețea care se întinde peste toate nodurile dintr-un swarm. Din acest motiv, porturile publice expuse vor fi unice per rețea. Așadar, nu pot fi expuse două porturi 3000 din două servicii diferite care se conectează la aceeași rețea overlay.
Un serviciu la care s-a făcut deploy pe un anumit port totdeauna va avea acel port rezervat, indiferent pe ce nod rulează de fapt containerul sau containerele sale. Diagrama de mai jos (preluată din documentația oficială) prezintă o situație în care avem un serviciu numit my-web publicat pe portul 8080 într-un swarm cu trei noduri. Se poate observa că, dacă ne conectăm pe portul 8080 de pe oricare adresă IP de nod din swarm, vom fi redirecționați către un container care rulează serviciul specific portului extern 8080, indiferent de nodul pe care rulează.
Secretele din Swarm trebuie create înainte de a fi rulată configurația. Putem folosi următoarea comandă:
$ docker secret create mysecret file.txt fm49ig0i8x9pdq0xxa8wdchoy
Putem lista secretele existente astfel:
$ docker secret ls ID NAME DRIVER CREATED UPDATED fm49ig0i8x9pdq0xxa8wdchoy mysecret 3 seconds ago 3 seconds ago
Secretele din Swarm sunt criptate în Raft și deci este recomandat să fie folosite în producție.
Exista câteva diferențe între Swarm și Compose la nivelul fișierelor declarative YAML:
Odată ce swarm-ul Docker a fost creat și inițializat, comanda prin care se face deployment la o stivă de servicii este următoarea (unde configurația se găsește în fișierul my_stack.yml, iar numele stivei va fi stack_name):
$ docker stack deploy -c my_stack.yml stack_name
În cadrul laboratoarelor de IDP, avem două variante principale cu ajutorul cărora putem să ne creăm un cluster Docker format din mai multe mașini: Docker Machine sau Play with Docker.
Docker Machine este un utilitar care permite rularea Docker Engine pe gazde virtuale (atât local, cât și în cloud, la provideri precum AWS, Azure sau DigitalOcean), precum și gestiunea facilă a acestora din terminal. Pe Windows și macOS, Docker Machine face parte din instalarea de Docker, dar pe Linux trebuie date explicit comenzile următoare:
$ curl -L https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine
$ chmod +x /tmp/docker-machine
$ cp /tmp/docker-machine /usr/local/bin/docker-machine
În Docker Machine, putem folosi drivere pentru a crea noduri virtuale configurate pentru a rula Docker. Exista drivere pentru a crea noduri direct în cloud, dar și drivere pentru a crea mașini virtuale pe gazda locală. În exemplul de mai jos, se creează un nod virtual local folosind driverul pentru VirtualBox:
$ docker-machine create --driver virtualbox myvm1 Running pre-create checks... Creating machine... (myvm1) Copying /home/radu/.docker/machine/cache/boot2docker.iso to /home/radu/.docker/machine/machines/myvm1/boot2docker.iso... (myvm1) Creating VirtualBox VM... (myvm1) Creating SSH key... (myvm1) Starting the VM... (myvm1) Check network to re-create if needed... (myvm1) Waiting for an IP... Waiting for machine to be running, this may take a few minutes... Detecting operating system of created instance... Waiting for SSH to be available... Detecting the provisioner... Provisioning with boot2docker... Copying certs to the local machine directory... Copying certs to the remote machine... Setting Docker configuration on the remote daemon... Checking connection to Docker... Docker is up and running! To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env myvm1
Putem verifica rularea corectă a comenzilor și alte informații utile despre starea nodurilor virtuale astfel:
$ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS myvm1 - virtualbox Running tcp://192.168.99.100:2376 v17.09.0-ce
Prin comanda docker-machine ssh, putem trimite comenzi prin SSH către un nod virtual Docker pe care îl specificăm prin nume, așa cum se poate observa mai jos.
$ docker-machine ssh myvm1 "ls -la"
În mod similar, există și comanda docker-machine scp:
$ docker-machine scp file.txt myvm1:.
De asemenea, există și comenzi pentru oprirea, respectiv ștergerea, nodurilor virtuale create.
$ docker-machine stop myvm1
$ docker-machine rm myvm1