Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cc:laboratoare:03 [2021/10/22 14:09]
radu.ciobanu
cc:laboratoare:03 [2022/10/23 19:39] (current)
florin.mihalache
Line 1: Line 1:
-===== Laboratorul 03 - Docker Swarm =====+====== Laboratorul 03 - Kubernetes deployments,​ rollouts și servicii ​=====
 +===== Deployments ===== 
 +Despre deployments ați învățat în cadrul laboratorului trecut. În cadrul laboratorului curent veți învăța despre upgrade-ul unui deployment și despre rollback-ul unui deployment.
  
-==== Introducere ==== +Pentru ​un fișier de deployment putem să avem următorul template: 
- +<code yaml> 
-Î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. +apiVersionapps/v1 
- +kindDeployment 
-==== Arhitectura Docker Swarm ==== +metadata
- +  ​name: <> ​#name  
-Docker Swarm se bazează pe algoritmul distribuit [[https://​raft.github.io|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 [[https://​docs.docker.com/​engine/​swarm/​how-swarm-mode-works/​nodes/​|documentația oficială]]),​ se poate observa arhitectura unui cluster Docker Swarm. +spec: 
- +  ​replicas: ​<x#no of replicas 
-{{:cc:​laboratoare:​swarm-diagram.png?​600|}} +  ​selector:​ 
- +    ​matchLabels:​ 
-Mașinile gazdă care fac parte dintr-un Swarm se numesc **//​noduri//​** și pot avea două roluri+      key: value 
-  ​* manager - rol administrativ și funcțional;​ menține consistența clusterului,​ lansează în execuție servicii, expune endpoint-uri de rețea +  ​template
-  * worker - rol funcțional;​ execută serviciile. +    ​metadata:​ 
- +      ​labels:​ 
-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. +        pod-key: pod-value 
- +    spec
-<note important>​Întotdeauna trebuie să existe un nod leader.</​note+      ​containers
- +      namenginx 
-<note tip>​Deoarece toleranța este de (N - 1) / 2 noduri manager picate, este indicat să avem un număr impar de noduri și un număr impar de manageri. Docker recomanda 3, 5 sau 7 manageri.</​note+        ​image:​ <> #you can use the nginx image
- +
-==== Crearea unui Docker Swarm ==== +
- +
-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)+
- +
-<code bash> +
-$ docker swarm init --advertise-addr 192.168.99.100 +
- +
-Swarm initializedcurrent 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.+
 </​code>​ </​code>​
  
-<note tip>Așa cum se poate observacomanda ​de mai sus generează alte două comenzi pe care le putem folosi pentru a introduce alte noduri în clusteratât ca worker, cât și ca manager.</​note>​ +Dorim, de exemplu, să facem următorul deploymentul, cu numele ''​cc-dep-01''​, cu 4 replici ​și cu un label-ul ''​applab3cc''​:
- +
-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): +
- +
-<code bash> +
-$ docker node ls +
- +
-ID                            HOSTNAME ​    ​STATUS ​      ​AVAILABILITY ​     MANAGER STATUS +
-qtyx0t5z275wp46wibcznx8g5 *   ​node1 ​       Ready        Active ​           Leader +
-0xbb9al1kuvn0jcapxiqni29z ​    ​node2 ​       Ready        Active ​      +
-</​code>​ +
- +
-==== Servicii și stive de servicii Docker Swarm ==== +
- +
-Atunci când vorbim de deployment-ul unei aplicații în Docker Swarm, trecem de la noțiunea 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 [[cc:​laboratoare:​02|laboratorul 2]]. Comportamentul serviciilor dintr-o stivă este similar ​cu cel al containerelor din Docker Compose, doar că politica de denumire este diferită. +
- +
-<note tip>​Orice entitate creată într-o stivă (serviciu, volum, rețea, secret) va fi prefixată de **//​NUME-STIVA_//​**.</​note>​ +
- +
-Docker Swarm are acces la o colecție nouă de opțiuni în cadrul fișierului YAML de Compose, ce vor fi trecute în proprietatea [[https://​docs.docker.com/​compose/​compose-file/​compose-file-v3/#​deploy|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: +
 <code yaml> <code yaml>
-[...] +kind: Deployment 
-services+metadata
-  ​web+  ​namecc-dep-01 
-    imagemyimage +spec: 
-    ​deploy+  replicas: 10 
-      ​replicas4 +  selector
-      ​resources+    ​matchLabels
-        ​limits+      ​app: lab3cc 
-          cpus"​0.2"​ +  template: 
-          ​memory50M +    metadata
-      ​restart_policy+      ​labels
-        ​conditionon-failure +        ​applab3cc 
-[...]+    spec
 +      ​containers
 +      ​- namenginx 
 +        ​imagenginx
 </​code>​ </​code>​
  
-În fragmentul de fișier YAML de mai sus, se rulează un serviciu numit //**web**// care are patru copiiAstfel, 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 RAMNu î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).+<​note>​ 
 +Tasks: 
 +  * Creați deployment-ul cum știm deja: ''​kubectl apply -f lab3dep.yaml''​ 
 +  ​Afișați obiectele ​de tipul ReplicaSet ​și Deployment pe care le aveți momentan în cluster. 
 +  ​Afișați pod-urile care sunt up and running. 
 +</​note>​
  
-=== Rețele Swarm === +Ajungem la partea de upgrade a unui deployment. Un use-case relevant este unul des întâlnit în ziua de azi, presupunem că a apărut o nouă versiune a aplicației și vrem să folosim versiunea curentă.
  
-Spre deosebire de Docker clasic și Composerețelele create în Swarm nu mai sunt de tip bridge, ci de tip **//​overlay//​**. O rețea de tip overlay este rețea care se întinde peste toate nodurile dintr-un swarm. Din acest motiv, porturile publice expuse vor fi unice per rețea. Așadarnu pot fi expuse două porturi 3000 din două servicii diferite care se conectează la aceeași rețea overlay.+În cazul deployment-ului nostruvrem să folosim ​nouă versiune a webserver-ului aplicației noastredeci vrem să folosim o versiune mai nouă a nginx.
  
-<​note ​tip>Docker Swarm realizează balansare a încărcării la nivelul rețelei.</​note>​+<​note>​ 
 +Tasks: 
 +  * Creați un nou fișier plecând de la fișierul creat anterior. Schimbați imaginea folosită în ''​nginx:​1.21.1''​.  
 +  * Aplicați modificările făcute: ''​kubectl apply -f mynewdep.yaml''​ 
 +  * Listați pod-urile din clusterCe se întâmplă?​ 
 +</​note>​
  
-Un serviciu la care s-a făcut deploy pe un anumit port totdeauna va avea acel port rezervatindiferent pe ce nod rulează de fapt containerul sau containerele sale. Diagrama de mai jos (preluată din [[https://​docs.docker.com/​engine/​swarm/​ingress/​|documentația oficială]]) prezintă o situație în care avem un serviciu numit //**my-web**// publicat pe portul 8080 într-un cluster cu trei noduri. Se poate observa cădacă ne conectăm pe portul 8080 de pe oricare adresă IP de nod din clustervom fi redirecționați către un container care rulează serviciul specific portului extern 8080, indiferent de nodul pe care rulează.+În primul rând, un aspect foarte important este că pod-urile sunt upgraded secvențial,​ nu toate odată, după ce un număde noi pod-uri au fost createurmează să se șteargă cele vechiprocedeul se repetă până când toate pod-urile au fost updated.
  
-{{:cc.png?​600|}}+<note tip>Așa cum puteți observa, numele unui pod are următoarea structură''​numeDeployment-identificatorReplicaSet-identificatorPod''</​note>​ 
 +<​note>​Task:​ 
 +  * Listați toate obiectele de tip ReplicaSet din cluster: ''​kubectl get rs # am folosit o prescurtare''​ 
 +</​note>​
  
-=== Secrete Swarm ===+Din câte puteți observa, avem două ReplicaSets care corespund aceluiași deployment. Motivul este pentru că în momentul în care am făcut upgrade deployment-ului,​ a fost creat un nou ReplicaSet cu nouă imagine de nginx folosită. Obiectul ReplicaSet vechi este și el păstrat pentru că există mereu o șansă să vrem să ne întoarcem la versiunea anterioară a aplicației.
  
-Secretele din Swarm trebuie create înainte de fi rulată configurația. Putem folosi ​următoarea comandă:+===== Rollouts ===== 
 +Am realizat că avem o greșeală în deploymentul nostru, pentru ​reveni la versiunea anterioară folosim ​următoarea comandă: ​''​kubectl rollout history deployment <​depname>''​
  
-<code bash+<note
-$ docker secret create mysecret file.txt+Tasks: 
 +  * Analizați din nou obiectele de ReplicaSet și Pod. 
 +  * Scalați deployment-ul la 2 replici: ''​kubectl scale deployment <​depname>​ –replicas=2''​ 
 +  * Verificați numărul de pod-uri. 
 +  * Scalați din nou la 5 replici: ''​kubectl scale deployment <​depname>​ –replicas=5''​ 
 +</​note>​
  
-fm49ig0i8x9pdq0xxa8wdchoy +Pentru a modifica imaginea folosită de un deployment, avem următoarea comandă: ''​kubectl set image deployment ​<depnamenginx=nginx:​failTest''​ 
-</code>+În comanda de mai sus am introdus intenționat o imagine care nu există. Dacă urmariți comportamentul deployment-ului,​ o să observați că noile pod-uri nu vor fi create deoarece nu poate fi gasită imaginea specificată.
  
-Putem lista secretele existente astfel:+Am ajuns în situația în care vrem să ne întoarcem la o versiunea anterioară. Pentru a vedea istoricul modificărilor făcute pe acest deployment, avem următoarea comandă''​kubectl rollout history deoployment <​depname>''​
  
-<code bash> +Observați ca avem mai multe "​revizii"​ ale deployment-ului nostru. Pentru a ne întoarce la o anumită revizie, folosim următoarea comandă: 
-$ docker secret ls+''​kubectl rollout history deployment cc-dep-01 --revision=2''​
  
-ID                          NAME       ​DRIVER ​   CREATED ​        ​UPDATED +===== Servicii ===== 
-fm49ig0i8x9pdq0xxa8wdchoy ​  ​mysecret ​            3 seconds ago   3 seconds ago +Care sunt serviciile cunoscute în Kubernetes? Care este diferența între ele? Ne interesează în mod special diferența dintre ClusterIP și NodePort. 
-</​code>​+Pentru a instanția o aplicație simplă care conține o bază de date și un API care face interogări,​ avem nevoie, asa cum intuiți, de 2 pod-uri. 
 +Pentru a porni un pod de Postgres, avem nevoie de a seta variabilele ''​POSTGRES_USER''​ și ''​POSTGRES_PASSWORD'',​ dar și numele bazei de date pe care urmează să o folosim - ''​POSTGRES_DB''​. Avem mai multe moduri prin care putem face asta, cel mai simplu exemplu (și cel mai nesigur) este cu un ConfigMap.
  
-Secretele din Swarm sunt criptate în Raft și deci este recomandat să fie folosite în producție. +Exemplu: 
- +<code yaml> 
-=== Diferențe între Docker Swarm și Docker Compose === +apiVersion: v1 
- +kind: ConfigMap 
-Exista câteva diferențe între Swarm și Compose la nivelul fișierelor declarative YAML+metadata
-  * deoarece Swarm rulează servicii în rețea, nu poate exista cuvântul-cheie **//​build//​**;​ serviciile trebuie obligatoriu să fie rulate pe baza unor imagini deja existente într-un registru + name: db-config-map 
-  * stivele de servicii nu accepta fișiere **//​.env//​** (spre deosebire de Docker Compose) +data: 
-  * Docker Compose rulează containere în mod single-host,​ pe când Docker Swarm orchestrează servicii în mod multi-host. + POSTGRES_USER:​ "​admin"​ 
- + POSTGRES_PASSWORD:​ "​admin"​ 
-=== Pornirea unei stive de servicii în Docker Swarm === + POSTGRES_DB"​books"​
- +
-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 //​**lab3**//​): +
- +
-<code bash> +
-$ docker stack deploy -c my_stack.yml lab3+
 </​code>​ </​code>​
  
-<note important>​Dacă folosim un registru diferit de Docker (precum [[https://​docs.gitlab.com/​ee/​user/​packages/​container_registry/​|GitLab Container Registry]]),​ este nevoie ​să fim autentificați și să adăugăm opțiunea **//-–with-registry-auth//​** atunci când lansăm ​stivă de servicii.</​note>​ +Când o să creăm pod-ul ​deployment-ul, să folosim acest ConfigMap pentru a injecta variabilele ​de mediuPentru ​avea datele persistenteavem nevoie, asa cum știm din labul trecut, de un PV și de un PVC
- +  * ''​PersistentVolume''​ (PV): 
-Odată ce o stivă de servicii ​fost pornităputem să îi vedem statusul prin următoarea comandă+<​code ​yaml
- +apiVersion: v1 
-<​code ​bash+kind: PersistentVolume 
-$ docker stack ps lab3                                                                                                      ​ +metadata: 
- + name: postgres-pv-volume 
-ID             ​NAME ​                  ​IMAGE ​                                  ​NODE ​     DESIRED STATE    CURRENT STATE           ​ERROR ​              PORTS + ​labels
-cuktma92gm62 ​  ​lab3_adminer.1 ​        ​adminer:latest ​                         myvm2     ​Running ​         Running 9 minutes ago                        +  typelocal 
-njak2qzaobtt ​  ​lab3_db.1 ​             ​postgres:12                             ​myvm1 ​    ​Running ​         Running 8 minutes ago                        +spec
-m811buil7e63 ​  ​lab3_io-service.1 ​     mobylab/cc-laborator3-io:latest ​        ​myvm1 ​    ​Running ​         Running 9 minutes ago                        + storageClassName:​ manual 
-jnfw37e34kz3 ​  ​lab3_books-service.1 ​  ​mobylab/​cc-laborator3-books:latest ​     myvm1     ​Running ​         Running 9 minutes ago                        + ​capacity
-pzlzkgsxxc00 ​  ​lab3_gateway.1 ​        ​mobylab/​cc-laborator3-gateway:latest ​   myvm2     ​Running ​         Running 9 minutes ago                        +   storage1Gi 
-kpaahb931rbq ​  ​lab3_io-service.2 ​     mobylab/​cc-laborator3-io:latest ​        ​myvm1 ​    ​Running ​         Running 9 minutes ago                        + accessModes
-num87yijgxrg ​  ​lab3_books-service.2 ​  ​mobylab/​cc-laborator3-books:latest ​     myvm2     ​Running ​         Running 9 minutes ago                        +   ​- ​ReadWriteOnce 
-d9m63k9h7ium ​  ​lab3_gateway.2 ​        ​mobylab/​cc-laborator3-gateway:latest ​   myvm1     ​Running ​         Running 9 minutes ago                        + ​hostPath
-lkmy60wpy0gv ​  ​lab3_io-service.3 ​     mobylab/​cc-laborator3-io:latest ​        ​myvm2 ​    ​Running ​         Running 9 minutes ago                        +   path: "/mnt/​data"​
-fy21iizn0reb ​  ​lab3_gateway.3 ​        ​mobylab/cc-laborator3-gateway:​latest ​   myvm2     ​Running ​         Running 9 minutes ago                       +
 </​code>​ </​code>​
- +  * ''​PersistentVolumeClaim''​ (PVC)
-De asemenea, putem vedea lista de stive pornite astfel: +<​code ​yaml
- +apiVersion: v1 
-<​code ​bash+kind: PersistentVolumeClaim 
-$ docker stack ls                                                                                                            +metadata: 
- + name: posgress-pvc 
-NAME      SERVICES ​     ORCHESTRATOR +spec: 
-lab3      5             Swarm+ ​storageClassName:​ manual 
 + ​accessModes:​ 
 +   - ReadWriteOnce 
 + ​resources:​ 
 +   ​requests:​ 
 +     ​storage:​ 1Gi
 </​code>​ </​code>​
  
-Putem vedea lista de servicii (din toate stivele pornite) astfel: +Pentru a crea pod-ul ​de Postgres, avem următorul fișier
- +<​code ​yaml
-<​code ​bash+apiVersion: v1 
-$ docker service ls                                                                                                          +kind: Pod 
- +metadata: 
-ID               ​NAME ​                ​MODE ​          ​REPLICAS ​              ​IMAGE ​                                 PORTS + namedb-pod 
-dekzzyais8g7 ​    ​lab3_adminer ​        ​replicated ​    ​1/​1 ​                   adminer:latest ​                        ​*:​8080->​8080/​tcp + ​labels:​ 
-74y84hvq4irn ​    ​lab3_books-service ​  ​replicated ​    2/2 (max 1 per node)   ​mobylab/​cc-laborator3-books:latest ​     +   app: postgres 
-ns9mxet1rkx5 ​    ​lab3_db ​             replicated ​    ​1/​1 ​                   ​postgres:12                              +spec: 
-dh3sv3q74fy6 ​    ​lab3_gateway ​        ​replicated ​    3/3 (max 2 per node)   ​mobylab/​cc-laborator3-gateway:latest ​  *:3000->80/tcp + ​containers:​ 
-ru0rd7g2ypu8 ​    ​lab3_io-service ​     replicated ​    ​3/3 (max 2 per node)   ​mobylab/​cc-laborator3-io:latest+   - imagepostgres:​10.4 
 +     name: postgres 
 +     ​volumeMounts
 +     ​- ​namemyvol 
 +       ​mountPath: /etc/config 
 +     ports: 
 +       containerPort:​ 5432 
 +     ​envFrom: 
 +       configMapRef:​ 
 +           name: db-config-map 
 + ​volumes: 
 +   - name: myvol 
 +     ​persistentVolumeClaim:​ 
 +       ​claimName:​ posgress-pvc
 </​code>​ </​code>​
-==== Deployment-ul unui cluster Docker ==== 
  
-În cadrul laboratoarelor ​de Cloud Computing, avem două variante principale ​cu ajutorul cărora putem să ne creăm un cluster Docker format din mai multe mașini: [[https://​docs.docker.com/​machine/​|Docker Machine]] sau [[https://​labs.play-with-docker.com|Play with Docker]]. +Pentru ca podul nostru ​de API să comunice ​cu cel de baze de date, trebuie ​să expunem pod-ul de Postgres printr-un serviciu ​de tip ClusterIP
- +<​code ​yaml
-=== Docker Machine === +apiVersion: v1 
- +kind: Service 
-Docker Machine este un utilitar care permite rularea Docker Engine pe gazde virtuale (atât local, cât și în cloud, la provideri ca AWS, Azure sau DigitalOcean),​ precum și gestiunea facilă a acestora din terminal. Docker Machine trebuie instalat separat ​de Docker, conform [[https://​docs.docker.com/​machine/​install-machine/​|documentației oficiale]]. +metadata: 
- + name: postgres 
-Î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:​ + labels: 
- +   app: postgres 
-<​code>​ +spec: 
-$ docker-machine create --driver virtualbox myvm1 + type: ClusterIP 
- + ​ports:​ 
-Running pre-create checks... +  port: 5432 
-Creating machine... + selector: 
-(myvm1) Copying /​home/​radu/​.docker/​machine/​cache/​boot2docker.iso to /​home/​radu/​.docker/​machine/​machines/​myvm1/​boot2docker.iso... +  apppostgres
-(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, rundocker-machine env myvm1+
 </​code>​ </​code>​
  
-Putem verifica rularea corectă ​comenzilor ​și alte informații utile despre starea nodurilor virtuale astfel: +Pentru ​porni podul de API, avem următorul fișier
- +<​code ​yaml
-<​code>​ +apiVersion: v1 
-$ docker-machine ls +kind: Pod 
-NAME    ACTIVE ​  ​DRIVER ​      ​STATE ​    ​URL ​                        ​SWARM ​  ​DOCKER ​       ERRORS +metadata: 
-myvm1   -        ​virtualbox ​  ​Running ​  tcp://​192.168.99.100:2376           ​v17.09.0-ce   + name: apipod 
 + ​labels:​ 
 +   app: api 
 +spec: 
 + ​containers:​ 
 +   ​- image: andreidamian/​lab3cc:​first 
 +     name: apicontainer 
 +     ​env:​ 
 +      - name: PGUSER 
 +        value: "​admin"​ 
 +      name: PGPASSWORD 
 +        value"​admin"​ 
 +      - namePGDATABASE 
 +        value: "​books"​ 
 +      ​name: PGHOST 
 +        value: "​postgres"​ 
 +      - name: PGPORT 
 +        value: "​5432"​
 </​code>​ </​code>​
  
-Prin comanda //​**docker-machine ssh**//putem trimite comenzi prin SSH către un nod virtual Docker ​pe care îl specificăprin nume, așa cum se poate observa mai jos.+Dupa ce și acest pod este up and runningtrebuie să îl expunem printr-un serviciu de tip NodePort pentru a putea comunica cu el de pe mașina noastră. Facem asta prin următoarea comandă (se poate face și printr-un fișier YAML): ''​kubectl expose pod apipod --port 80 --type=NodePort''​
  
-<​code>​ +Apoi verificați portul asignat de noul serviciu (31598): 
-$ docker-machine ssh myvm1 "ls -la" +{{ :​cc:​laboratoare:​image5.png |}}
-</​code>​+
  
-În mod similar, există școmanda //**docker-machine scp**//:+FolosițPostman pentru a accesa API-ul deployed: 
 +{{ :​cc:​laboratoare:​image2.png?​600 |}}
  
-<​code>​ +Avem următoarea eroare: 
-$ docker-machine scp file.txt myvm1:. +{{ :cc:​laboratoare:​image1.png?500 |}}
-</​code>​+
  
-De asemeneaexistă și comenzi ​pentru ​oprirea, respectiv ștergerea, nodurilor virtuale create+Avem această eroare pentru că baza de date nu a fost configurată. Pentru a configura baza de date avem mai multe variantecea mai simpla (dar și cea mai ineficientă) este următoarea:​ 
- +  * obtineți un shell pe podul de Postgres: ''​kubectl exec -it db-pod bash''​ 
-<​code>​ +  * ne conectam la baza de date books cu username ​și parola definite în ConfigMap-ul ​pentru ​acest pod (admin/​admin):​ ''​psql -h localhost -U admin  --password books''​ 
-$ docker-machine stop myvm1+{{ :​cc:​laboratoare:​image4.png?500 |}} 
 +  * rulați următorul script pentru a inițializa baza de date: 
 +<​code ​sql
 +CREATE TABLE IF NOT EXISTS books ( 
 +    id uuid PRIMARY KEY NOT NULL , 
 +    title varchar NOT NULL, 
 +    author varchar NOT NULL 
 +);
 </​code>​ </​code>​
  
-<​code>​ +Incercați din nou comanda GET din PostmanInserați ceva în baza de date: 
-$ docker-machine rm myvm1 +{{ :cc:​laboratoare:​image3.png?​500 ​|}}
-</​code>​ +
- +
-=== Play with Docker === +
- +
-Play with Docker este un mediu online de învățare Docker ce oferă mașini virtuale pe o durată de 4 ore. +
- +
-{{:​idp:​laboratoare:​playwithdocker.png?​900}} +
- +
-==== Comenzi utile ==== +
- +
-=== Interacțiune servicii === +
- +
-<note tip>​Aceste comenzi pot fi rulate doar de pe noduri manager.</​note>​ +
- +
-<code bash> +
-$ docker service create --name <​NUME_SERVICIU>​ <​IMAGINE_DOCKER>​ # creează un serviciu pornind de la o imagine +
-$ docker service ls                                             # afișează toate serviciile din sistem +
-$ docker service inspect <​NUME_SERVICIU> ​                       # afișează informații despre un serviciu +
-$ docker service logs –f <​NUME_SERVICIU> ​                       # afișează log-urile unui serviciu +
-$ docker service ps <​NUME_SERVICIU> ​                            # afișează task-urile (șstatusurile lor) pentru un serviciu +
-$ docker service update --replicas <N> <​NUME_SERVICIU> ​         # actualizează serviciul, replicând containerele de N ori +
-$ docker service rm <​NUME_SERVICIU> ​                            # șterge un serviciu +
-</​code>​ +
- +
-=== Interacțiune cluster === +
- +
-<note tip>​Aceste comenzi pot fi rulate doar de pe noduri manager.</​note>​ +
- +
-<code bash> +
-$ docker node ls                            # afișează nodurile ​din cluster +
-$ docker node promote <​NUME_NOD> ​           # promovează nodul din worker în manager +
-$ docker node demote <​NUME_NOD> ​            # retrogradează nodul din manager în worker +
-$ docker swarm init [--advertise-addr <IP>] # creează un cluster Docker +
-$ docker swarm join --token <​TOKEN>​ <​IP> ​   # se alătură unui cluster Docker +
-</​code>​ +
- +
-=== Docker Machine === +
- +
-<code bash> +
-$ docker-machine create [--driver <​DRIVER>​] <​NUME>​ # creează o mașină virtuală Docker +
-$ docker-machine start <​NUME> ​                     # pornește o mașină virtuală Docker +
-$ docker-machine stop <​NUME> ​                      # oprește o mașină virtuală Docker +
-$ docker-machine rm <​NUME> ​                        # șterge o mașină virtuală Docker +
-$ docker-machine ls                                # listează toate mașinile virtuale Docker +
-$ docker-machine ssh <​NUME> ​                       # se conectează prin SSH la o mașină virtuală Docker +
-$ docker-machine scp <​FISIER>​ <​NUME>:<​DESTINATIE> ​ # copiază un fișier pe o mașină virtuală Docker +
-</​code>​ +
- +
-==== Exerciții ==== +
- +
-=== Descriere aplicație === +
- +
-Pentru exercițiile din acest laborator, vom lucra cu o variantă extinsă a aplicației bibliotecă din [[idp:​laboratoare:​02|laboratorul 2]]Astfel, codul (care se găsește pe [[https://​gitlab.com/​mobylab-idp/​laborator3|repository-ul oficial IDP]]) este format din trei mici microservicii scrise în NodeJS și un script de inițializare pentru o bază de date PostgreSQL. Cele trei microservicii sunt: +
-  * //​**ApiGateway**//​ - mediază accesul dinspre lumea exterioară șredirecționează cererile HTTP către serviciul de cărți +
-  * //​**Books**//​ - se ocupă de partea de „business logic” ce ține de cărți și apelează serviciul IO pentru date +
-  * //**IO**// - gestionează datele sistemului și realizează comunicația cu baza de date+
- +
-=== Scop exerciții === +
- +
-Scopul exercițiilor este ca, plecând de la codul propus, să realizați o stivă de servicii care să funcționeze corect. Funcționalitatea este reprezentată de trei acțiuni+
-  * adăugarea unei cărți în bibliotecă +
-  * vizualizarea informațiilor despre toate cărțile din bibliotecă +
-  * vizualizarea detaliilor unei cărți. +
- +
-Pe scurt, va trebui să scrieți unul sau mai multe fișier Docker Compose pe care să le folosiți pentru a rula configurația sub forma unei stive de servicii Docker Swarm. Stiva creată va fi formată din 5 servicii: +
-  * //​**gateway**//​ - puteți să creați imaginea pe baza surselor din repository, sau puteți folosi imaginea //​**mobylab/​idp-laborator3-gateway**//​ +
-  * //​**books-service**//​ - puteți să creați imaginea pe baza surselor din repository, sau puteți folosi imaginea //​**mobylab/​idp-laborator3-books**//​ +
-  * //​**io-service**//​ - puteți să creați imaginea pe baza surselor din repository, sau puteți folosi imaginea //​**mobylab/​idp-laborator3-io**//​ +
-  * //**db**// - folosiți imaginea //​**postgres:​12**//​ +
-  * //​**adminer**//​ - folosiți imaginea //​**adminer**//​. +
- +
-=== Variabile de mediu === +
- +
-Variabilele de mediu ce vor trebui puse in fișierul Docker Compose sunt următoarele:​ +
-  * serviciul //​**gateway**//:​ +
-    * BOOKS_SERVICE_API_ROUTE:​ books-service/​api +
-    * NODE_ENV: development +
-  * serviciul //​**books-service**//:​ +
-    * IO_SERVICE_API_ROUTE:​ io-service/​api +
-    * NODE_ENV: development +
-  * serviciul //​**io-service**//:​ +
-    * PGUSER: admin +
-    * PGPASSWORD: admin +
-    * PGHOST: db +
-    * PGPORT: 5432 +
-    * PGDATABASE: books +
-    * NODE_ENV: development +
-  * serviciul //​**db**//:​ +
-    * POSTGRES_DB:​ books +
-    * POSTGRES_USER:​ admin +
-    * POSTGRES_PASSWORD:​ admin. +
-  +
-=== Rețele === +
- +
-Pentru a izola accesul serviciilor asupra clusterului,​ sunt necesare mai multe rețele, astfel: +
- +
-  * serviciul //​**gateway**//​ va comunica doar cu serviciul //​**books-service**//​ +
-  * serviciul //​**books-service**//​ va comunica atât cu serviciul de //​**gateway**//,​ cât și cu //​**io-service**//​ +
-  * serviciul //​**io-service**//​ va comunica atât cu serviciul //​**books-service**//,​ cât și cu serviciul //​**db**//​ +
-  * serviciul //**db**// va comunica atât cu serviciul //​**io-service**//,​ cât și cu //​**adminer**//​. +
- +
-=== Volume și bind mounts === +
- +
-Configurația de volume și bind mounts este la fel ca cea de la exercițiile din [[idp:​laboratoare:​02|laboratorul 2]]Astfel, serviciul de bază de date are nevoie de un volum pentru persistență și de un bind mount pentru a se injecta scriptul de inițializare. +
- +
-=== Porturi publice === +
- +
-Singurele servicii accesibile din exterior vor fi //​**gateway**//​ și //​**adminer**//​. Pentru //​**gateway**//,​ trebuie expus portul intern 80, peste care se mapează alt port (de exemplu, 3000), iar pentru //​**adminer**//​ trebuie expus portul intern 8080 (peste care se poate de asemenea mapa alt port extern). +
- +
-=== Rute HTTP === +
- +
-Dacă reușiți să rulați configurația,​ puteți să o testați folosind cURL sau [[https://​learning.postman.com/​docs/​getting-started/​sending-the-first-request/​|Postman]] pe următoarele rute: +
- +
-  * //**POST localhost:​PORT_PUBLIC/​api/​books**//​ cu corpul JSON ''​%%{"​title":​ "Harry Potter and the Prisoner of Azkaban",​ "​author":​ "J.K. Rowling",​ "​genre":​ "​Fantasy"​}%%''​ +
-  * //**GET localhost:​PORT_PUBLIC/​api/​books**//​ +
-  * //**GET localhost:​PORT_PUBLIC/​api/​books/<​ID_CARTE>​**//​. +
- +
-<note tip>​Pentru a adăuga un corp JSON unei cereri POST in Postman, selectați Body -> Raw -> JSON și scrieți JSON-ul aferent.</​note>​ +
- +
-=== Secrete === +
- +
-Opțional, puteți adăuga secrete aplicației,​ pentru numele de utilizator și parola necesare logării în baza de date. Astfel, serviciile care vor avea nevoie de secrete sunt //​**io-service**//​ și //**db**//. În cele două servicii, va trebui să sufixați variabilele de mediu destinate numelui de utilizator și parolei cu //​**_FILE**//​ și să puneți valorile acestor variabile de mediu în funcție de documentație:​ +
-  * pentru //​**io-service**//,​ la variabilele de mediu pentru numele de utilizator și parolă se pune doar **//numele secretului//​** iar NODE_ENV se setează la **//​staging//​** +
-  * pentru serviciul //**db**//, la variabilele de mediu se pune toată calea secretului (//​**/​run/​secrets/​nume-secret**//​).+
  
-=== Enunțuri ===+Stergeți pod-ul de Postgres și incercați să faceți GET. Ar trebui să primiți următoarea eroare: 
 +{{ :​cc:​laboratoare:​image6.png?​500 |}}
  
-  - Scrieți un fișier Docker Compose care sa folosească un build local și rulați pe mașina voastră +Reporniți pod-ul de baza de date și executați un GET: 
-  ​Construiți imaginile și urcați-le pe Docker Hub sau orice alt registru +{{ :​cc:​laboratoare:​image7.png?500 |}}
-  - Scrieți un fișier Docker Compose care să folosească imaginile din registru și rulați pe mașina voastră +
-  - Adăugați elemente ​de Docker Swarm la serviciile din fișierul Docker Compose (la proprietatea //​**deploy**//​) ​și rulați stiva de servicii într-un cluster (folosind Play with Docker sau Docker Machine) +
-  - Modificați fișierul Docker Compose ca să utilizați secrete externe pentru numele de utilizator și parolă în containerele de IO și bază de date.+
cc/laboratoare/03.1634900988.txt.gz · Last modified: 2021/10/22 14:09 by radu.ciobanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0