Differences

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

Link to this comparison view

idp:laboratoare:04 [2021/04/01 06:37]
radu.ciobanu [SSHFS]
idp:laboratoare:04 [2023/04/24 21:41] (current)
radu.ciobanu
Line 1: Line 1:
-===== Laboratorul 04 - Persistență în Docker Swarm =====+===== Laboratorul 04 - Portainer, GitLab CI/CD, monitorizare,​ logare, vizualizare,​ cozi de mesaje ​=====
  
-==== Introducere ====+În acest laborator, vom începe prin a discuta despre utilizarea Portainer, care acționează ca un GUI pentru Docker Swarm, și apoi vom implementa procesul de CI/CD („continuous integration and continuous deployment”) utilizând GitLab CI/CD și Portainer. Această parte a laboratorului se va desfășura pe local sau folosind Docker Machine, întrucât infrastructura de la Play With Docker nu permite rularea runnerilor de GitLab. Găsiți toate fișierele de configurare prezentate în această parte de laborator în [[https://​gitlab.com/​mobylab-idp|repo-ul oficial al laboratorului]] (în **BooksService** și **IOService** găsiți sursele și Dockerfile-urile pentru cele două containere proprii, iar în **Configs** găsiți fișierele Docker Compose și YAML-ul de configurare pentru Kong).
  
-În contextul Docker Swarmnu mai există o singură gazdă, ci multiple noduri conectate în rețea. Acest lucru face ca folosirea volumelor locale să nu fie recomandatădeoarce orchestrarea unui task pe un nod care nu are volumul cerut de container va rezulta ​în respingerea acelui task.+Pentru partea a doua a laboratorului (logare și monitorizare)vom lucra cu fișierele care se găsesc în subgrupul [[https://​gitlab.com/​mobylab-idp/​laborator-7|Laborator 4]] din grupul oficial de GitLab al materiei. Directoarele **Testapp** și **Worker** conțin fișierele sursă și Dockerfile pentru cele două aplicații pe care le vom ruladirectorul **Docker** conține fișierele Docker Compose cu care vom face deploymentiar directorul **Configs** conține configurările pentru diversele servicii ​pe care le vom adăuga ​în deployment.
  
-Există două posibilități principale ​de rezolvare a acestei problemePrima variantă presupune constrângerea unor servicii astfel încât să ruleze doar pe noduri managerastfel:+==== Portainer ==== 
 + 
 +[[https://​www.portainer.io|Portainer]] este o platformă Web care permite administrarea unui cluster Docker Swarm. Instrucțiunile oficiale se pot găsi [[https://​docs.portainer.io/​start/​install-ce|aici]]. 
 + 
 +{{:​idp:​laboratoare:​lab6_dashboard2.png?​750|}} 
 + 
 +Portainer poate rula ca un container separat sau ca serviciu de Swarm. **Vă recomandăm să îl rulați ca serviciu ​de Swarm**. 
 + 
 +<note tip>În cazul în care rulează ca serviciu de SwarmPortainer are două componenteaplicația Web propriu-zisă,​ și un agent care rulează în mod global (pe toate nodurile).</​note>​ 
 + 
 +Un exemplu de fișier Docker Compose de stivă de servicii pentru Portainer poate fi observat mai jos.
  
 <code yaml> <code yaml>
 +version: '​3.2'​
 +
 services: services:
-    example+  agent: 
-        deploy: +    image: portainer/​agent:​2.11.1 
-            placement:​ +    volumes: 
-                constraints:​ [node.role == manager]+      - /​var/​run/​docker.sock:/​var/​run/​docker.sock 
 +      - /​var/​lib/​docker/​volumes:/​var/​lib/​docker/​volumes 
 +    networks: 
 +      - agent_network 
 +    deploy: 
 +      mode: global 
 +      placement
 +        ​constraints:​ [node.platform.os == linux] 
 + 
 +  portainer:​ 
 +    image: portainer/​portainer-ce:​2.11.1 
 +    command: -H tcp://​tasks.agent:​9001 --tlsskipverify 
 +    ports: 
 +      - "​9443:​9443"​ 
 +      - "​9000:​9000"​ 
 +      - "​8000:​8000"​ 
 +    volumes: 
 +      - portainer_data:/​data 
 +    networks: 
 +      - agent_network 
 +    ​deploy: 
 +      mode: replicated 
 +      replicas: 1 
 +      ​placement:​ 
 +        constraints:​ [node.role == manager] 
 + 
 +networks: 
 +  agent_network:​ 
 +    driver: overlay 
 +    attachable: true 
 + 
 +volumes: 
 +  portainer_data:​ 
 </​code>​ </​code>​
  
-Această practică este utilă doar atunci când există un singur nod manager și astfel suntem siguri că taskurile ale căror containere au nevoie de volumele definite în configurație vor rula doar pe managerul unde exista volumele.+Dashboard-ul Portainer va fi accesibil pe portul 9000. La prima accesare, se setează un utilizator administrator cu o parolă.
  
-În cazul în care există mai multe noduri manager și dorim, de exemplu, să rulăm o bază de date într-un serviciu, dacă aceasta va fi orchestrată să ruleze pe alt nod față de cel pe care fost prima oară orchestrată, nu va mai avea acces la volumul unde a stocat date inițial. În acest cazva crea un volum nou pe noul nodajungându-se astfel la inconsistență.+Pe lângă utilitatea oferită de posibilitatea gestiunii cluster-ului prin interfața vizuală, Portainer oferă **//​webhook-uri//​** de CI/CD. Un webhook este un endpoint careatunci când este accesat, execută o acțiune. În cazul Portainerwebhook-urile vor actualiza serviciile de Docker. Pentru a genera ​un webhook, se intră ​pe pagina serviciului și se face toggle pe „Service Webhook”așa cum se observă în imaginea de mai jos.
  
-Cea de-a doua variantă pentru a rezolva problema descrisă mai sus este configurarea volumelor astfel încât să folosească un sistem de stocare extern (cum ar fi NFS, GlusterFS, Samba, Amazon S3, etc).+{{:​idp:​laboratoare:​lab6_webhook.png?750|}}
  
-<note important>​Din păcateinfrastructura de Play with Docker nu permite realizarea unui demo practic care să ilustreze folosirea volumelor cu stocare externă, având limitări la nivel de comunicație inter-mașini. Totuși, dacă aveți acces la un cluster de mașini ​Docker, vă recomandăm să încercați să vă configurați o stivă de servicii care folosește volume cu stocare externă.</​note>​+<note important>​ 
 +Pentru a crea un webhooktrebuie mai întâi ca serviciul ​să ruleze în cadrul ​Docker ​Swarm. 
 +</​note>​
  
-==== NFS ====+De asemenea, Portainer vă facilitează interacțiunea cu Docker Swarm fără a fi nevoie de a da comenzi în terminal, cum ar fi gestionarea secretelor.
  
-Cea mai facilă metodă de a adăuga stocare externă în Docker este prin intermediul NFS (Network File System). Pentru aceasta, este în primul rând nevoie de existența unui server NFS, care poate fi rulat fie nativ (pe una din mașinile din cluster-ul Docker sau undeva în exterior), fie prin intermediul unui container Docker. Există multiple soluții de rulare a unui server NFS folosind Docker, însă noi vă recomandăm [[https://hub.docker.com/​r/​itsthenetwork/​nfs-server-alpine/​|această soluție populară]] bazată pe Alpine Linux.+{{:idp:​laboratoare:​portainersecret.png?750|}}
  
-Soluția de mai sus reprezintă un container care rulează în mod privilegiatavând acces la resursele gazdei. Înainte ​să rulați ​containerul,​ trebuie ​să vă creați un director ce va fi partajat în rețea prin intermediul NFS.+Nu doar atât, darca să aveți control complet asupra serviciilor ce pot rula în Swarm, puteți să lansați stiva de servicii direct din editorul de YML din secțiunea Stacks.
  
-<note important>​Directorul partajat trebuie să nu fie de tipul OverlayFS.</​note>​+{{:​idp:​laboratoare:​portainereditor.png?750|}}
  
-<note tip>​Pentru a vedea sistemul ​de fișiere, se poate executa comanda ''​%%df -Th%%''​ (pe Linux).</note>+Ca Portainer să poată să vă acceseze registrele private, puteți să adăugați acele registre ​de imagini în secțiunea Registries cu utilizatorul vostru ​și parola/un token de acces.
  
-Dupa ce s-a creat directorul ​ce va reține datele partajate ​în rețea, se execută comanda de mai jos pentru ​pornirea serverului ​de NFS și exportul directorului partajat:+{{:​idp:​laboratoare:​portainerregistry.png?​750|}} 
 + 
 +==== Gitlab CI/CD ==== 
 + 
 +Conceptul de **//​CI/​CD//​** se referă la: 
 +  * continuous integration ​integrarea automată în sistem ​modificărilor de cod 
 +  * continuous deployment - plasarea automată a codului modificat în testare/​producție. 
 + 
 +Acest concept se mulează natural pe filozofia microserviciilor,​ unde o aplicație este „spartă” în mai multe **//module separate și independente//​**. Pe măsură ​ce codul unui modul este actualizat, acesta este integrat automat în sistem, fără să perturbe execuția celorlalte module. 
 + 
 +În acest laborator, se exemplifică procesul de CI/CD folosind GitLab. Gitlab CI/CD se bazează pe două componente:​ 
 + 
 +  * [[https://​docs.gitlab.com/​runner/​|Gitlab Runners]] - procese care executa pipeline-uri 
 +  * //​**.gitlab-ci.yml**//​ - fișier YAML de configurații declarative,​ care descrie ce face fiecare etapă dintr-un pipeline. 
 + 
 +<note tip> 
 +Un runner execută un pipeline. Un pipeline este format din etape. Fiecare etapă este descrisă ​în fișierul de configurație **//​.gitlab-ci.yml//​**.</​note>​ 
 + 
 +=== Structura codului sursă === 
 + 
 +Pentru a putea folosi conceptul de CI/CD cu GitLab cat mai eficient, se recomandă ca fiecare microserviciu să se afle în propriul său **//​repository//​**,​ iar toate repository-urile să fie grupate într-un **//​grup//​**. Așadar, pentru acest laborator, vom avea următoarele repository-uri:​ 
 +  * IOService - conține codul pentru microserviciul IO implementat la laboratoarele anterioare 
 +  * BooksService - conține codul pentru microserviciul de cărți implementat la laboratoarele anterioare 
 +  * Configs - conține fișierele de configurare necesare rulării stivei de servicii. 
 + 
 +Codul este accesibil pe [[https://​gitlab.com/​mobylab-idp|repo-ul oficial al laboratorului]]. 
 + 
 +=== Gitlab Runners === 
 + 
 +Gitlab Runners sunt procese care execută pipeline-uri. Atunci când se dă comanda ​//**git push**//, este lansat în execuție un pipeline aferent repository-ului respectiv (de aici recomandarea de a avea un repository per serviciu). 
 + 
 +Acestea vin în mai multe forme, însă modul cel mai facil de a lansa un runner în execuție este sub formă de containere Docker. 
 + 
 +== Configurare == 
 + 
 +Pentru a folosi un runner, este nevoie, în primul rând, să se acceseze pagina repository-ului sau a grupului GitLab. 
 + 
 +<note tip> 
 +Un runner de grup va putea rula pipeline-uri ​pentru ​fiecare repository din grupul respectiv. Un runner ​de repository va putea rula pipeline-uri doar pentru acel repository. 
 +</​note>​ 
 + 
 +Se intră în meniul de CI/CD al paginii de proiect ​și apoi se selectează opțiunea „Expand” din dreptul „Runners”. 
 + 
 +{{:​idp:​laboratoare:​lab6_cicd.png?​300|}} 
 + 
 +{{:​idp:​laboratoare:​lab6_runners.png?​750|}} 
 + 
 +== Gitlab Runners în Docker == 
 + 
 +Configuraera unui runner folosind Docker este simplă și necesită [[https://​docs.gitlab.com/​runner/​install/​docker.html|trei pași]]: 
 +    - instalarea 
 +    - înregistrarea 
 +    - modificarea fișierului de configurație //​**config.toml**//​. 
 + 
 +Pentru instalare, se rulează următoarea comandă:
  
 <code bash> <code bash>
-$ docker run -d --name ​nfs --privileged ​-v /cale/director/partajat:/nfsshare ​+$ docker run -d --name ​gitlab-runner ​--restart always ​-v /srv/gitlab-runner/config:/etc/​gitlab-runner ​
-      -e SHARED_DIRECTORY=/nfsshare itsthenetwork/nfs-server-alpine:latest +    -/var/run/​docker.sock:/​var/​run/​docker.sock gitlab/​gitlab-runner:latest 
-</​code>​+</​code> ​
  
-În comanda ​de mai sus, directorul ​pe care dorim să-l partajăm se află la calea //**/cale/director/partajat**//, fiind mapat pe serverul NFS la calea //​**/​nfsshare**//​. Odată ce serverul NFS a fost pornit, se pot crea volume peste NFS în mai multe moduriO variantă este crearea de volume prin intermediul API-ului din linia de comandăAstfeldacă se dorește crearea unui volum numit //​**mynfsvol**/​/, care apoi poate fi atașat la alte containere sau servicii, se poate executa ​următoarea comandă:+<note important>​ 
 +Runner-ul va rula în modul bind mount. Calea de pe gazdă dată runner-ului (în cazul de față//**/srv/gitlab-runner/config**//) trebuie să existeÎn ea vor fi reținute configurațiile runner-ului din interiorul containeruluiÎn mod similar, se poate folosi un volum
 +</note> 
 + 
 +Pentru înregistrare, se rulează ​următoarea comandă ​și se urmează pașii specificați:
  
 <code bash> <code bash>
-$ docker ​volume create ​--driver local --opt type=nfs ​--opt o=nfsvers=3,​addr=192.168.99.1,​rw \ +$ docker ​run --rm -it -v /srv/gitlab-runner/​config:/etc/​gitlab-runner gitlab/​gitlab-runner register
-      --opt device=:/nfsshare mynfsvol+
 </​code>​ </​code>​
  
-În comanda de mai sus, IP-ul serverului NFS este 192.168.99.1 și se folosește versiunea 3 de NFSSe poate inspecta volumul nou-creat pentru a se observa caracteristicile sale:+<note tip>​Token-ul de înregistrare ​este cel din pagina grupului ​de GitLab.</​note>​
  
-<code bash+<note tip>​Trebuie ținut minte ce se specifică la tag, deoarece tag-ul runnerul-ui va fi folosit în cadrul script-ului **//​.gitlab-ci.yml//​**.</​note
-docker ​volume inspect mynfsvol + 
-[ +<note tip>​Atunci când se cere imaginea de Docker, se poate specifica **//docker:​19.03//​**.</​note>​ 
-    { + 
-        "​CreatedAt":​ "2021-03-31T17:​26:​11Z"​, +<note important>​Trebuie specificată aceeași cale de bind mount ca la comanda de instalare.</​note>​ 
-        "​Driver":​ "​local"​, + 
-        "​Labels":​ {}, +Runner-ul de GitLab care rulează în Docker se bazează pe conceptul //​**DinD**//​ („Docker in Docker”). Pentru anumite operațiieste nevoie de acces elevat asupra sistemului Docker din gazdă. Așadartrebuie făcute două modificări asupra fișierului de configurație **//config.toml//**. 
-        "​Mountpoint":​ "/mnt/sda1/var/lib/docker/volumes/mynfsvol/_data",​ + 
-        "​Name":​ "​mynfsvol",​ +<note tip> 
-        "Options": { +Fișierul **//config.toml//** se găsesște la calea specificata în comanda de instalare de la etapa 1. 
-            "​device": ​":/nfsshare", +</​note>​ 
-            "o": "​nfsvers=3,​addr=192.168.99.1,rw", + 
-            "​type": ​"nfs+<code yaml> 
-        }, +concurrent = 1 
-        "Scope": "local" +check_interval = 0 
-    ​+ 
-]+[session_server] 
 +  session_timeout = 1800 
 + 
 +[[runners]] 
 +  name = "IDP lab 4 runner
 +  url = "https://​gitlab.com/​
 +  token = "jEzCz9PACYL4Y1FB8vs2" 
 +  executor ​"​docker"​ 
 +  [runners.custom_build_dir] 
 +  [runners.cache] 
 +    [runners.cache.s3] 
 +    ​[runners.cache.gcs] 
 +    [runners.cache.azure] 
 +  [runners.docker] 
 +    tls_verify = false 
 +    image = "docker:19.03
 +    ​privileged = true 
 +    ​disable_entrypoint_overwrite = false 
 +    oom_kill_disable = false 
 +    disable_cache = false 
 +    volumes = ["/cache", "/​var/​run/​docker.sock:/​var/​run/​docker.sock"] 
 +    ​shm_size = 0
 </​code>​ </​code>​
  
-Un astfel de volum extern poate fi dat ca parametru ​la pornirea unui container din linia de comandă, astfel:+Modificările necesare sunt următoarele:​ 
 +  * „privileged” trebuie să fie setat pe „true” 
 +  * la volume, trebuie adăugat și „/​var/​run/​docker.sock:/​var/​run/​docker.sock”. 
 + 
 +Dupa ce se efectuează modificărilese execută următoarea comandă:
  
 <code bash> <code bash>
-$ docker ​run -v mynfsvol:/​test -it alpine+$ docker ​restart gitlab-runner
 </​code>​ </​code>​
  
-În comanda ​de mai sus, se mapează volumul NFS la calea //​**/​test**//​ din interiorul containerului. Acest lucru se poate face simultan pe mai multe containere de pe mașini diferite, toate având aceeași mapare și deci acces la aceleași fișiere.+== Script-ul ​de pipeline ==
  
-Putem folosi un volum creat în linia de comandă chiar într-un fișier de Docker Compose, fie la rularea locală, fie la rularea folosind Docker SwarmPentru acest lucru, este nevoie de câteva modificări în configurația volumelor din cadrul fișierelor YAMLCa exemplu, presupunem că avem un serviciu de bază de date care are nevoie de volume pentru scriptul de configurație șpentru persistența datelor (pe modelul temelor ​de casă din laboratoarele precedente):​+Script-ul **//.gitlab-ci.yml//​** descrie execuția unui pipeline pe un runnerPuteți observa un astfel ​de script mai jos.
  
 <code yaml> <code yaml>
-services+docker-build-master
-    db+  stagebuild 
-        imagepostgres:12 +  ​before_script
-        ​volumes:​ +    docker login -u "​$CI_REGISTRY_USER" ​-p "​$CI_REGISTRY_PASSWORD"​ $CI_REGISTRY 
-            ​db-data-nfs:/​var/​lib/​postgresql/​data +  script
-            db-config-nfs:/docker-entrypoint-initdb.d+    docker build --pull -t "​$CI_REGISTRY_IMAGE"​ . 
 +    - docker ​push "​$CI_REGISTRY_IMAGE"​ 
 +  only: 
 +    ​master 
 +  tags: 
 +    ​idp 
 +    - lab4
  
-volumes+deploy-service-master:​ 
-    ​db-data-nfs+  stage: deploy 
-        ​externaltrue +  script
-    ​db-config-nfs: +    - apk add --update curl 
-        ​externaltrue+    - curl -XPOST http://​192.168.99.126:​9000/​api/​webhooks/​e37c80b1-9315-49d2-b0ad-5b3d8dade98e 
 +  only
 +    - master 
 +  tags: 
 +    - idp 
 +    - lab4
 </​code>​ </​code>​
  
-În exemplul ​de mai sus, se presupune că volumele ​//**db-data-nfs**// și //​**db-config-nfs**//​ au fost create în prealabil folosind comenzile prezentate anterior. Este totuși posibil să se creeze volumele direct în fișierul Docker Compose, așa cum s-a prezentat și în laboratoarele precedente. În acest caz, volumele nu vor mai fi declarate ca fiind externe, ci trebuie configurate pentru a funcționa peste NFS, astfel:+<note tip>​Trebuie câte un astfel ​de script ​//**.gitlab-ci.yml**// pentru fiecare repository.<​/note> ​
  
-<code yaml> +Script-ul prezentat mai sus descrie două etape ale pipeline-ului
-volumes: +  * **//build//​** ​codul este construit într-o imagine de Docker și salvat într-un registru 
-    db-data-nfs+  * **//deploy//** - serviciul de Docker este încărcat in cluster-ul de Swarm, utilizând un webhook Portainer.
-        ​driver:​ local +
-        driver_opts:​ +
-           type: nfs +
-           o: "​nfsvers=3,​addr=192.168.99.1,​nolock,​soft,​rw"​ +
-           ​device:​ :/database/data +
-    db-config-nfs: +
-        driver: local +
-        driver_opts:​ +
-           type: nfs +
-           o: "​nfsvers=3,​addr=192.168.99.1,​nolock,​soft,​rw"​ +
-           device: :/database/config +
-</code>+
  
-În exemplul de mai sus, s-a folosit același IP pentru serverul NFS (192.168.99.1),​ iar directoarele //**/database/data**// și //​**/​database/​config**//​ trebuie să existe ​//**în interiorul**// directorului partajat de gazda containerului de server NFS (//​**/​cale/​director/​partajat**//​ din exemplul de pornire a serverului NFS).+<note tip>Un webhook se poate genera doar **//după ce serviciul rulează deja in Swarm//**.</note>
  
-O altă modalitate de a adăuga persistență folosind NFS ar fi montarea directoarelor de NFS pe toate nodurile (sau pe toți managerii) ​din clusterși apoi utilizarea de bind mounts pentru a mapa căile de NFS montate local în interiorul serviciilor Docker.+Un pipeline se poate observa ​din GitLab mergând la meniul „CI/CD” al unui repositoryla opțiunea „Pipelines”.
  
-=== Docker Machine NFS ===+{{:​idp:​laboratoare:​lab6_pipelines.png?​300|}}
  
-În cazul se folosește Docker Machine pentru gestiunea unui cluster de mașini virtuale, trebuie avut în vedere că aceste mașini vor avea [[http://​www.tinycorelinux.net|Tiny Core Linux]] ca sistem de operare, care folosește propriul package manager (numite //​**tce**//​) care descarcă pachete pre-compilate din repository-urile proprii. Din acest motiv, o modalitate mai facilă de a lucra cu NFS în Docker Machine este folosirea utilitarului [[https://github.com/​adlogix/​docker-machine-nfs|Docker Machine NFS]]. Acesta permite montarea de directoare NFS în noduri Docker Machine prin comenzi de forma următoare:+{{:idp:laboratoare:​lab6_pipelines2.png?750|}}
  
-<code bash> +Un exemplu de fișier //**.gitlab-ci.yml**// funcțional poate fi găsit [[https://​gitlab.com/​mobylab-idp/booksservice/-/blob/​master/​.gitlab-ci.yml| aici]].
-$ docker-machine-nfs myvm1 --shared-folder=/database/config --shared-folder=/database/data -+
-</code>+
  
-==== GlusterFS ​====+==== Monitorizare ​====
  
-[[https://​www.gluster.org|GlusterFS]] este un sistem ​de fișiere ​de rețea open-sourceutilizat pentru stocare ​în cloud sau streaming media. Pentru a putea folosi volume peste GlusterFSeste necesară instalarea ​și configurarea sa pe fiecare nod din clusterÎn continuaresunt prezentate comenzile necesare instalării pe un sistem bazat pe Ubuntu:+=== Monitorizare din linia de comandă === 
 + 
 +În această parte de laborator, se abordează problema monitorizării. Într-o aplicație Dockerse pot monitoriza ​în primul rând metrici despre mașinile (fizice ​sau virtuale) pe care rulează serviciile noastreapoi metrici care țin de containerele care rulează în swarm, și, nu în ultimul rând, metrici care țin de aplicația propriu-zisă și pe care le putem defini. 
 + 
 +Cea mai simplă metodă de a monitoriza unul sau mai multe containere este prin intermediul interfeței în linie de comandă din Dockerfolosind comanda //docker container stats// în felul următor:
  
 <code bash> <code bash>
-sudo apt-get install software-properties-common ​-y+docker container run --name myalpine ​-it -d alpine
 </​code>​ </​code>​
  
 <code bash> <code bash>
-sudo add-apt-repository ppa:gluster/glusterfs-3.12+docker container stats myalpine 
 + 
 +CONTAINER ID   ​NAME ​      CPU %     MEM USAGE LIMIT   MEM %     NET I/O     BLOCK I/O    PIDS 
 +5d002ad9bba1 ​  ​myalpine ​  0.00%     ​484KiB / 7.774GiB ​  ​0.01% ​    806B / 0B   135kB / 0B   1
 </​code>​ </​code>​
 +
 +În exemplul de mai sus, s-a pornit un container de Linux Alpine, care apoi se monitorizează continuu. Informațiile afișate includ ID-ul și numele containerului,​ consumul de CPU și memorie, cantitatea de date schimbate pe interfețele de rețea, activitatea pe disc, etc. Dacă se dorește monitorizarea mai multor containere simultan, se poate utiliza comanda //docker stats//:
  
 <code bash> <code bash>
-sudo apt-get update+docker container run --name myalpine2 -it -d alpine
 </​code>​ </​code>​
  
 <code bash> <code bash>
-sudo apt install glusterfs-server -y+docker stats 
 + 
 +CONTAINER ID   ​NAME ​       CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O    PIDS 
 +97ab4376c5b7 ​  ​myalpine2 ​  ​0.01% ​    ​352KiB / 7.774GiB ​  ​0.00% ​    586B / 0B     0B / 0B      1 
 +5d002ad9bba1 ​  ​myalpine ​   0.02%     ​484KiB / 7.774GiB ​  ​0.01% ​    ​1.02kB / 0B   135kB / 0B   1
 </​code>​ </​code>​
  
-Odată instalatGlusterFS ​se pornește cu următoarele comenzi:+În exemplul de mai sus, s-a mai pornit un container adițional. Prin comanda //docker stats//, se afișează informații statistice despre toate containerele care rulează pe mașină. 
 + 
 +Comanda de mai sus poate fi customizată prin formatarea output-ului în funcție de câmpurile care se doresc a fi afișate, precum ​și modul în care acest lucru este făcut:
  
 <code bash> <code bash>
-sudo systemctl start glusterd+docker stats --format "​{{.Container}}:​ {{.CPUPerc}}"​ 
 + 
 +97ab4376c5b7:​ 0.02% 
 +5d002ad9bba1:​ 0.01%
 </​code>​ </​code>​
  
 <code bash> <code bash>
-sudo systemctl enable glusterd+docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"​ 
 + 
 +NAME        CPU %     MEM USAGE / LIMIT 
 +myalpine2 ​  ​0.01% ​    ​352KiB / 7.774GiB 
 +myalpine ​   0.03%     ​484KiB / 7.774GiB
 </​code>​ </​code>​
  
-În continuare, nodul leader al clusterului ​(care va fi, cel mai probabil, nodul coordonator GlusterFSva trebui să execute următoarea comandă pentru fiecare ​din celălalte noduri din clusterpentru a conecta nodurile pentru sistemul ​de fișiere:+Dacă se dorește doar afișarea primului rezultat de monitorizare ​(în loc de o afișare continuă), se poate folosi comanda //docker container stats %%--%%no-stream//​. 
 + 
 +=== Monitorizare prin Docker Remote API === 
 + 
 +Pe lângă comenzile ​din CLI, Docker oferă și un set de endpoint-uri HTTP remote sub forma unui APIprin care se pot trimite comenzi către daemon-ul ​de Docker. Printre endpoint-urile din API-ul de Docker, există ​și câteva care oferă informații mai detaliate de monitorizare:
  
 <code bash> <code bash>
-gluster peer probe <​HOSTNAME_NOD>​+curl --unix-socket /​var/​run/​docker.sock http://​localhost/​containers/​97ab4376c5b7/​stats 
 + 
 +
 +  "​read":​ "​2022-04-19T08:​52:​27.9008855Z",​ 
 +  "​preread":​ "​0001-01-01T00:​00:​00Z",​ 
 +  "​pids_stats":​ { 
 +    "​current":​ 1, 
 +    "​limit":​ 18446744073709551615 
 +  }, 
 +[...] 
 +  "​cpu_stats":​ { 
 +    "​cpu_usage":​ { 
 +      "​total_usage":​ 51201000, 
 +      "​usage_in_kernelmode":​ 14821000, 
 +      "​usage_in_usermode":​ 36379000 
 +    }, 
 +    "​system_cpu_usage":​ 18947870000000,​ 
 +    "​online_cpus":​ 4, 
 +    "​throttling_data":​ { 
 +      "​periods":​ 0, 
 +      "​throttled_periods":​ 0, 
 +      "​throttled_time":​ 0 
 +    } 
 +  }, 
 +[...] 
 +  "​memory_stats":​ { 
 +    "​usage":​ 360448, 
 +    "​stats":​ { 
 +[...] 
 +    }, 
 +    "​limit":​ 8346984448 
 +  }, 
 +  "​name":​ "/​myalpine2",​ 
 +  "​id":​ "​97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249",​ 
 +  "​networks":​ { 
 +    "​eth0":​ { 
 +      "​rx_bytes":​ 936, 
 +      "​rx_packets":​ 12, 
 +[...] 
 +    } 
 +  } 
 +}
 </​code>​ </​code>​
  
-Conectarea nodurilor ​se poate verifica prin următoarea comandă dată pe manager:+Datele sunt generate o dată la o secundă și sunt în format JSON, așa cum se poate observa mai sus (unde s-a formatat JSON-ul pentru a fi urmărit mai ușor, și s-au păstrat doar părți din output, pentru claritate). La rularea comenzii, este necesar ID-ul containerului care se dorește a fi monitorizat. 
 + 
 +=== Monitorizare de evenimente Docker === 
 + 
 +Dacă se dorește monitorizarea în timp real a unor evenimente Docker ce au loc pe mașina gazdă, se poate folosi comanda //docker system events//, așa cum se prezintă mai jos:
  
 <code bash> <code bash>
-gluster pool list+docker system events 
 + 
 +# aceste evenimente se generează atunci când oprim containerul myalpine2 
 +2022-04-19T11:​57:​02.936639300+03:​00 container kill 97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249 (image=alpine,​ name=myalpine2,​ signal=15) 
 +2022-04-19T11:​57:​12.977888700+03:​00 container kill 97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249 (image=alpine,​ name=myalpine2,​ signal=9) 
 +2022-04-19T11:​57:​13.102094700+03:​00 container die 97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249 (exitCode=137,​ image=alpine,​ name=myalpine2) 
 +2022-04-19T11:​57:​13.165242800+03:​00 network disconnect 56499229054c04a928960053276ea4bf37c12e575bcdafa522140c835372df62 (container=97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249,​ name=bridge,​ type=bridge) 
 +2022-04-19T11:​57:​13.184247100+03:​00 container stop 97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249 (image=alpine,​ name=myalpine2) 
 + 
 +# acest eveniment se generează atunci când ștergem containerul myalpine2 
 +2022-04-19T11:​57:​19.124295200+03:​00 container destroy 97ab4376c5b7e0411abd33277d3ea6ec7e902bdc9af9826d3afe6ff8f9325249 (image=alpine,​ name=myalpine2) 
 + 
 +# aceste evenimente se generează atunci când pornim un container myalpine3 
 +2022-04-19T11:​57:​40.002873200+03:​00 container create fc65cf12a86cf253127415d0b0dabf2399e9dbfa15315c106e3f3566a9b2aee3 (image=alpine,​ name=myalpine3) 
 +2022-04-19T11:​57:​40.082728100+03:​00 network connect 56499229054c04a928960053276ea4bf37c12e575bcdafa522140c835372df62 (container=fc65cf12a86cf253127415d0b0dabf2399e9dbfa15315c106e3f3566a9b2aee3,​ name=bridge,​ type=bridge) 
 +2022-04-19T11:​57:​40.449862600+03:​00 container start fc65cf12a86cf253127415d0b0dabf2399e9dbfa15315c106e3f3566a9b2aee3 (image=alpine,​ name=myalpine3)
 </​code>​ </​code>​
  
-Următorul pas presupune crearea unui volum partajat pe întreg clusterul, printr-o comandă executată pe manager. ​În exemplul de mai josse presupune că avem un manager (cu hostname-ul //**docker-manager**//) și doi workeri (//**docker-worker1**// ​și //**docker-worker2**//​). Toate trei nodurile vor avea un volum partajat (numit //**mysharedvol**//) la calea //​**/​gluster/​mysharedvol**//​, deși nu este obligatoriu să fie aceeași cale la toate nodurile.+În exemplul de mai suss-a pornit monitorizarea de evenimente într-un terminal, iar în celălalt terminal întâi s-a oprit containerul ​**myalpine2** creat anterior, apoi s-șters, iar în final s-a creat un container ​**myalpine3**
 + 
 +Docker generează notificări pentru evenimente care au loc asupra containerelordaemonului Docker, imaginilor, rețelelor virtuale, volumelor, etc. Este de asemenea posibilă filtrarea output-ului comenzii de mai sus în funcție de tipul de eveniment căutat, de un anumit container, etc.:
  
 <code bash> <code bash>
-gluster volume create mysharedvol replica 3 docker-manager:/​gluster/​mysharedvol \ +$ docker ​system events ​-f event=die -f container=myalpine3 ​                           ​ 
-      ​docker-worker1:/​gluster/​mysharedvol docker-worker2:/​gluster/​mysharedvol force+ 
 +2022-04-19T12:​01:​22.419370500+03:00 container die fc65cf12a86cf253127415d0b0dabf2399e9dbfa15315c106e3f3566a9b2aee3 (exitCode=137,​ image=alpine,​ name=myalpine3)
 </​code>​ </​code>​
  
-În continuare, managerul trebuie să pornească volumul, astfel:+=== Monitorizare folosind Prometheus ===
  
-<​code ​bash+[[https://​prometheus.io|Prometheus]] este un toolkit open-source de monitorizare și alertare scris în Go, care colectează metrici prin citirea lor din endpoint-uri HTTP ale componentelor monitorizate (astfel de componente pot fi containere Docker, sau chiar Prometheus însuși). Oferă un model de date multi-dimensional,​ cu seriile de timp identificate prin-un nume de metrică și perechi cheie-valoare. Componentele monitorizate sunt descoperite prin servicii de descoperire (ca DNS, Consul, etc.) sau prin configurații statice. În plus, Prometheus oferă un limbaj de query funcțional numit PromQL, prin intermediul căruia se pot compune query-uri mai complexe. 
-$ gluster volume start mysharedvol+ 
 +În mod implicit, Docker expune metrici pentru Prometheus pe portul 9323, ceea ce înseamnă că o instanță de Prometheus poate monitoriza runtime-ul de Docker de pe un nod. 
 + 
 +<note important>​Această opțiune este încă în stadiu experimental pentru MacOS, așa că este nevoie să se adauge linia //"​metrics-addr"​ : "​0.0.0.0:​9323"//​ în setările avansate de daemon Docker din Docker Desktop.</​note>​ 
 + 
 +În general, metricile unei componente care expune date pentru Prometheus se găsesc la un endpoint numit **metrics**,​ și așa este cazul și pentru Docker, care expune datele pentru Prometheus la adresa [[http://​localhost:​9323/​metrics]]. Acolo se pot observa toate metricile expuse de Docker, iar pașii pentru a vizualiza datele de monitorizare folosind Prometheus sunt descriși în continuare. 
 + 
 +Așa cum s-a specificat și mai sus, Prometheus se poate auto-monitoriza. Pentru acest lucru, sunt necesare două componente. În primul rând, este necesar un fișier YAML prin care se setează componentele care se doresc a fi monitorizate,​ precum și modul în care acestea sunt descoperite pe rețea. Pentru a monitoriza Docker și Prometheus, putem folosi următorul fișier de configurare (pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​configs|Configs]]):​ 
 + 
 +<​spoiler>​ 
 +<​code ​yaml prometheus.yml
 +scrape_configs:​ 
 +  - job_name: '​prometheus'​ 
 +    scrape_interval:​ 5s 
 +    static_configs:​ 
 +      - targets: ['​prometheus:​9090'​] 
 + 
 +  - job_name: '​docker'​ 
 +    scrape_interval:​ 5s 
 +    static_configs:​ 
 +      - targets: ['​host.docker.internal:​9323'​]
 </​code>​ </​code>​
 +</​spoiler>​
  
-Ultimul pas se referă la montarea volumuluiastfel încât să se poate accesa și după un restart sau în alte situații. Comenzile ​de mai jos trebuie executate ​pe toate nodurile ​din cluster:+În fișierul de mai sus, se creează două job-uri de monitorizare:​ 
 +  * unul denumit **prometheus**,​ care va colecta date din endpoint-ul HTTP la 5 secundede pe interfața serviciului ​de Prometheus care va fi pornit ​pe portul 9090 
 +  * unul denumit **docker**, care va colecta date din endpoint-ul HTTP tot la 5 secunde, de pe interfața gazdei Docker pe care se rulează (**host.docker.internal** se rezolvă la adresa IP internă a gazdei).
  
-<​code ​bash+Vom rula Prometheus ca un serviciu Docker prin intermediul unui fișier Docker Compose (pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]),​ care arată astfel: 
-$ echo '​localhost:/mysharedvol /mnt glusterfs defaults,​_netdev,​backupvolfile-server=localhost 0 0' >> ​/etc/fstab+ 
 +<​spoiler>​ 
 +<​code ​yaml prometheus-stack.yml
 +version"​3.8"​ 
 + 
 +services: 
 +    prometheus:​ 
 +        image: prom/prometheus 
 +        volumes: 
 +            ​../​configs/​prometheus/​prometheus.yml:​/etc/prometheus/​prometheus.yml 
 +        ports: 
 +            - 9090:9090
 </​code>​ </​code>​
 +</​spoiler>​
 +
 +Odată ce facem deployment-ul pe baza acestui fișier de Compose (așa cum am studiat în [[https://​ocw.cs.pub.ro/​courses/​idp/​laboratoare/​03|laboratorul 3]]), la adresa [[http://<​IP>:​9090/​graph]] se va găsi dashboard-ul Prometheus (prezentat mai jos, unde se pot vedea datele monitorizate și se pot adăuga grafice noi), iar la [[http://<​IP>:​9090/​targets]] se vor găsi componentele monitorizate. De asemenea, ca la Docker, la [[http://<​IP>:​9090/​metrics]] se pot găsi toate metricile generate de Prometheus.
 +
 +<note important>​În URL-urile de mai sus, **<​IP>​** se referă la adresa externă a unui nod din cluster-ul Docker (sau **localhost**,​ dacă rulăm local).</​note>​
 +
 +{{:​idp:​laboratoare:​prom_dashboard.png?​800|}}
 +
 +În imaginea de mai sus, s-a ales monitorizarea metricii **prometheus_http_requests_total** și o reprezentare de tip stacked a datelor, pe un interval de un minut. În textbox-ul de sus, se poate alege metrica ce se dorește a fi afișată (din dropdown-ul de sub el, sau se poate scrie un query în PromQL). Pentru afișare, se apasă butonul **Execute**,​ iar vizualizarea poate fi atât în format de grafic (așa cum este prezentat în imaginea de mai sus), cât și la consolă. Se pot adăuga astfel oricâte grafice pe dashboard.
 +
 +== Monitorizarea stării nodurilor ==
 +
 +Pentru monitorizarea stării nodurilor care rulează servicii Docker, este necesar ca metricile aferente să fie publicate pe un endpoint HTTP. Pentru acest lucru, se poate folosi componenta [[https://​prometheus.io/​docs/​guides/​node-exporter/​|Node Exporter]] din Prometheus, care expune metrici hardware și de sistem de operare de pe mașina gazdă către Prometheus.
 +
 +Pentru a porni și componenta de Node Exporter pe fiecare nod din cluster, trebuie să adăugăm un serviciu nou în stiva noastră de servicii, rezultând următorul fișier Docker Compose (pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]):​
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter-stack.yml>​
 +version: "​3.8"​
 +
 +services:
 +    prometheus:
 +        image: prom/​prometheus
 +        volumes:
 +            - ../​configs/​prometheus/​prometheus-nexporter.yml:/​etc/​prometheus/​prometheus.yml
 +        ports:
 +            - 9090:9090
 +        networks:
 +            - monitoring
 +
 +    node_exporter:​
 +        image: prom/​node-exporter
 +        deploy:
 +            mode: global
 +        volumes:
 +            - /​proc:/​host/​proc:​ro
 +            - /​sys:/​host/​sys:​ro
 +            - /:/​rootfs:​ro
 +        command:
 +            - '​--path.procfs=/​host/​proc'​
 +            - '​--path.rootfs=/​rootfs'​
 +            - '​--path.sysfs=/​host/​sys'​
 +            - '​--collector.filesystem.mount-points-exclude=^/​(sys|proc|dev|host|etc)($$|/​)'​
 +        ports:
 +            - 9100:9100
 +        networks:
 +            - monitoring
 +
 +networks:
 +    monitoring:
 +</​code>​
 +</​spoiler>​
 +
 +Rețeaua comună este necesară pentru că cele două componente (Prometheus și Node Exporter) trebuie să poată comunica între ele pentru a avea acces la date. De asemenea, se poate observa mai sus că serviciul de Node Exporter este rulat în modul global, ceea ce înseamnă ca va rula pe fiecare nod din swarm (pentru a putea exporta metrici de monitorizare pentru fiecare nod în parte). Parametrii de tip **mount** au rolul de a realiza o mapare între sistemele de fișiere Linux/MacOS de statistici (**sysfs** și **procfs**) de pe mașina gazdă și cele din container.
 +
 +Noul fișier de configurare pentru Prometheus, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​configs|Configs]],​ arată în felul următor:
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter.yml>​
 +global:
 +  scrape_interval:​ 3s
 +
 +scrape_configs:​
 +  - job_name: '​prometheus'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​prometheus:​9090'​]
 +
 +  - job_name: '​docker'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​host.docker.internal:​9323'​]
 +
 +  - job_name: 'node resources'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - cpu
 +        - meminfo
 +        - diskstats
 +        - netdev
 +        - netstat
 +
 +  - job_name: 'node storage'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - filefd
 +        - filesystem
 +        - xfs
 +</​code>​
 +</​spoiler>​
 +
 +Se poate observa că au apărut două target-uri noi, **node resources** și **node storage**. Deși ambele iau date din același endpoint, sunt separate într-un mod logic după tipul de date pe care le expun.
 +
 +Când se face deploy, la adresa [[http://<​IP>:​9090/​targets]] se vor putea observa toate cele patru target-uri (Docker, Prometheus, cele două target-uri noi specifice Node Exporter), iar la [[http://<​IP>:​9090/​graph]] se pot acum alege pentru monitorizare inclusiv metrici generate de Node Exporter.
 +
 +{{:​idp:​laboratoare:​prom_nodex_targets.png?​800|}}
 +
 +== Monitorizare folosind cAdvisor ==
 +
 +O altă variantă de monitorizare a mașinilor gazdă și a containerelor este [[https://​github.com/​google/​cadvisor|cAdvisor]] de la Google, care oferă informații de nivel înalt despre CPU și memorie, dar și despre containerele existente. cAdvisor face sampling o dată pe secundă, iar datele sunt ținute un minut (dacă se dorește o stocare de lungă durată, sunt necesare alte servicii).
 +
 +Pentru monitorizarea folosind cAdvisor, este necesar să se pornească un serviciu de cAdvisor în aceeași rețea cu serviciul de Prometheus și să se adauge target-ul de cAdvisor în fișierul de configurare Prometheus. Noul fișier de configurare,​ pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​configs|Configs]],​ arată în felul următor:
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter-cadvisor.yml>​
 +global:
 +  scrape_interval:​ 3s
 +
 +scrape_configs:​
 +  - job_name: '​prometheus'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​prometheus:​9090'​]
 +
 +  - job_name: '​docker'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​host.docker.internal:​9323'​]
 +
 +  - job_name: 'node resources'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - cpu
 +        - meminfo
 +        - diskstats
 +        - netdev
 +        - netstat
 +
 +  - job_name: 'node storage'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - filefd
 +        - filesystem
 +        - xfs
 +
 +  - job_name: '​cadvisor'​
 +    static_configs:​
 +      - targets: ['​cadvisor:​8080'​]
 +</​code>​
 +</​spoiler>​
 +
 +Diferența față de fișierul precedent de configurare este adăugarea target-ului **cadvisor**. Mai departe, putem face deploy pe baza fișierul Docker Compose de mai jos, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]:​
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter-cadvisor-stack.yml>​
 +version: "​3.8"​
 +
 +services:
 +    prometheus:
 +        image: prom/​prometheus
 +        volumes:
 +            - ../​configs/​prometheus/​prometheus-nexporter-cadvisor.yml:/​etc/​prometheus/​prometheus.yml
 +        ports:
 +            - 9090:9090
 +        networks:
 +            - monitoring
 +
 +    node_exporter:​
 +        image: prom/​node-exporter
 +        deploy:
 +            mode: global
 +        volumes:
 +            - /​proc:/​host/​proc:​ro
 +            - /​sys:/​host/​sys:​ro
 +            - /:/​rootfs:​ro
 +        command:
 +            - '​--path.procfs=/​host/​proc'​
 +            - '​--path.rootfs=/​rootfs'​
 +            - '​--path.sysfs=/​host/​sys'​
 +            - '​--collector.filesystem.mount-points-exclude=^/​(sys|proc|dev|host|etc)($$|/​)'​
 +        ports:
 +            - 9100:9100
 +        networks:
 +            - monitoring
 +
 +    cadvisor:
 +        image: gcr.io/​cadvisor/​cadvisor
 +        deploy:
 +            mode: global
 +        volumes:
 +            - /:/​rootfs:​ro
 +            - /​var/​run:/​var/​run:​ro
 +            - /​sys:/​sys:​ro
 +            - /​var/​lib/​docker/:/​var/​lib/​docker:​ro
 +            - /​dev/​disk:/​dev/​disk/:​ro
 +        ports:
 +            - 8080:8080
 +        networks:
 +            - monitoring
 +
 +networks:
 +    monitoring:
 +</​code>​
 +</​spoiler>​
 +
 +În urma deployment-ului,​ metricile colectate de cAdvisor vor fi disponibile pentru monitorizare din dashboard-ul de Prometheus. Dacă nu se dorește accesarea din Prometheus, cAdvisor oferă și o interfață Web proprie, care se află la adresa [[http://<​IP>:​8080/​]],​ unde se pot regăsi informații despre containerele care rulează (sub categoria **/​docker**),​ precum și despre utilizarea nodului pe care rulează serviciul, așa cum se poate observa în imaginea de mai jos.
 +
 +{{:​idp:​laboratoare:​cadvisor.png?​550|}}
 +
 +== Monitorizarea propriilor aplicații ==
 +
 +Până acum, am monitorizat metrici despre nodurile Docker și despre containere, dar nu și despre aplicațiile noastre. Dacă dorim să facem acest lucru, este necesar să exportăm din aplicațiile noastre niște endpoint-uri HTTP care să poată fi citite de Prometheus, exact cum fac toate celelalte componente monitorizate mai sus.
 +
 +O modalitate de a realiza acest lucru este de a urma [[https://​prometheus.io/​docs/​practices/​instrumentation/​|documentația oficială Prometheus de instrumentare]] și de a ne expune direct din aplicații endpoint-ul de metrici cu datele afișate conform specificațiilor. Totuși, acest lucru nu este foarte la îndemână,​ dar partea bună este că există o serie de [[https://​prometheus.io/​docs/​instrumenting/​clientlibs/​|biblioteci sau framework-uri]] care ne ușurează exportarea de metrici, indiferent de limbajul folosit.
 +
 +În cadrul acestui laborator, exemplificăm monitorizarea propriilor aplicații folosind pachetul [[https://​github.com/​prometheus/​client_python|prometheus-client]] în Python. Însă, înainte de a vedea cum se folosește, ar fi util de discutat despre tipurile de metrici acceptate de Prometheus. Astfel, conform [[https://​prometheus.io/​docs/​concepts/​metric_types/​|documentației oficiale]], există patru categorii principale de metrici:
 +
 +  * Counter - un contor unic a cărui valoare poate doar să crească sau să fie resetată la zero
 +  * Gauge - o valoare numerică ce poate urca sau coborî în mod arbitrar
 +  * Histogram - colectează observații (precum durate de cereri sau dimensiuni de răspunsuri) și le numără în bucket-uri configurabile,​ oferind totodată și o sumă a tuturor valorilor observate
 +  * Summary - similar cu Histogram, dar oferă și cuantile configurabile peste o fereastră dinamică de timp.
 +
 +Pachetul [[https://​github.com/​prometheus/​client_python|prometheus-client]] oferă funcții ușor de utilizat pentru fiecare din tipurile de metrici de mai sus, plus alte câteva auxiliare. Este suficient ca, în aplicațiile din care vrem să exportăm metrici, să instanțiem obiecte specifice tipurilor de metrici și să le actualizăm unde este cazul, și să pornim partea de server care va expune metricile respective pe un endpoint pentru Prometheus. Puteți vedea un exemplu simplu de aplicație Flask care exportă cinci metrici (Counter, Gauge, Histogram, Summary și Info) pe portul 8000 în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​testapp|Testapp]]. Acolo, pe lângă surse, există și un Dockerfile cu ajutorul căruia se poate construi o imagine Docker pentru această aplicație. De asemenea, imaginea se poate găsi deja construită pe Docker Hub cu numele **mobylab/​idp-laborator4-testapp**.
 +
 +Aplicația din laborator rulează și un server web care poate primi cereri de tip POST pe portul 5000 pentru a genera date legate de metricile oferite, astfel:
 +
 +  * **inc_counter** - crește valoarea metricii de tip Counter
 +  * **inc_gauge** - crește valoarea metricii de tip Gauge
 +  * **dec_gauge** - scade valoarea metricii de tip Gauge
 +  * **set_gauge** - setează valoarea metricii de tip Gauge (cu un parametru numit **value**)
 +  * **set_summary** - setează valoarea metricii de tip Summary (cu un parametru numit **value**)
 +  * **set_histogram** - setează valoarea metricii de tip Histogram (cu un parametru numit **value**).
 +
 +Pe partea de deployment, este necesar să adăugam aplicația noastră într-o rețea comună cu Prometheus, rezultând următorul fișier Docker Compose, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]:​
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter-cadvisor-testapp-stack.yml>​
 +version: "​3.8"​
 +
 +services:
 +    prometheus:
 +        image: prom/​prometheus
 +        volumes:
 +            - ../​configs/​prometheus/​prometheus-nexporter-cadvisor-testapp.yml:/​etc/​prometheus/​prometheus.yml
 +        ports:
 +            - 9090:9090
 +        networks:
 +            - monitoring
 +
 +    node_exporter:​
 +        image: prom/​node-exporter
 +        deploy:
 +            mode: global
 +        volumes:
 +            - /​proc:/​host/​proc:​ro
 +            - /​sys:/​host/​sys:​ro
 +            - /:/​rootfs:​ro
 +        command:
 +            - '​--path.procfs=/​host/​proc'​
 +            - '​--path.rootfs=/​rootfs'​
 +            - '​--path.sysfs=/​host/​sys'​
 +            - '​--collector.filesystem.mount-points-exclude=^/​(sys|proc|dev|host|etc)($$|/​)'​
 +        ports:
 +            - 9100:9100
 +        networks:
 +            - monitoring
 +
 +    cadvisor:
 +        image: gcr.io/​cadvisor/​cadvisor
 +        deploy:
 +            mode: global
 +        volumes:
 +            - /:/​rootfs:​ro
 +            - /​var/​run:/​var/​run:​ro
 +            - /​sys:/​sys:​ro
 +            - /​var/​lib/​docker/:/​var/​lib/​docker:​ro
 +            - /​dev/​disk:/​dev/​disk/:​ro
 +        ports:
 +            - 8080:8080
 +        networks:
 +            - monitoring
 +
 +    testapp:
 +        image: mobylab/​idp-laborator4-testapp
 +        ports:
 +            - 8000:8000
 +            - 5000:5000
 +        networks:
 +            - monitoring
 +
 +networks:
 +    monitoring:
 +</​code>​
 +</​spoiler>​
 +
 +Din punct de vedere al fișierului de configurare pentru Prometheus, trebuie adăugat un job pentru aplicația noastră, pe portul 8000, rezultând următorul fișier, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​configs|Configs]]:​
 +
 +<​spoiler>​
 +<code yaml prometheus-nexporter-cadvisor-testapp.yml>​
 +global:
 +  scrape_interval:​ 3s
 +
 +scrape_configs:​
 +  - job_name: '​prometheus'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​prometheus:​9090'​]
 +
 +  - job_name: '​docker'​
 +    scrape_interval:​ 5s
 +    static_configs:​
 +      - targets: ['​host.docker.internal:​9323'​]
 +
 +  - job_name: 'node resources'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - cpu
 +        - meminfo
 +        - diskstats
 +        - netdev
 +        - netstat
 +
 +  - job_name: 'node storage'​
 +    static_configs:​
 +      - targets: ['​node_exporter:​9100'​]
 +    params:
 +      collect[]:
 +        - filefd
 +        - filesystem
 +        - xfs
 +
 +  - job_name: '​cadvisor'​
 +    static_configs:​
 +      - targets: ['​cadvisor:​8080'​]
 +
 +  - job_name: '​testapp'​
 +    static_configs:​
 +      - targets: ['​testapp:​8000'​]
 +</​code>​
 +</​spoiler>​
 +
 +Odată ce s-a făcut deployment-ul,​ putem observa la [[http://<​IP>:​9090/​targets]] și noul target, pe care putem apoi face query-uri din pagina de grafice, așa cum se poate observa în imaginea de mai jos.
 +
 +{{:​idp:​laboratoare:​prom_testapp.png?​800|}}
 +
 +==== Logare ====
 +
 +[[https://​grafana.com/​oss/​loki/​|Loki]] este un sistem de agregare de log-uri scalabil, creat de cei de la Grafana și inspirat de Prometheus. Mai concret, este un fel de Prometheus pentru log-uri, gândit să fie eficient și ușor de utilizat, folosind DynamoDB pentru indexare și S3 pentru stocare. Loki nu indexează textul log-urilor, ci grupează log-urile în stream-uri și le indexează astfel, împărțind query-urile în bucăți mici și realizându-le în paralel.
 +
 +Ca funcționalitate,​ Loki colectează log-uri de la mai mulți clienți (cum ar fi Promtail, Logstash, driver-ul de Docker, etc.), le indexează, și apoi le exportă către alte servicii precum Grafana sau AlertManager. În cadrul acestui laborator, vom folosi un driver Docker de logging custom pentru Loki, care se instalează în felul următor:
  
 <code bash> <code bash>
-mount.glusterfs localhost:/​mysharedvol /mnt+docker plugin install grafana/​loki-docker-driver:latest --alias loki --grant-all-permissions
 </​code>​ </​code>​
  
 <code bash> <code bash>
-chown -R root:docker ​/mnt+$ docker ​plugin ls 
 + 
 +ID             ​NAME ​         DESCRIPTION ​          ​ENABLED 
 +6a20054403a8 ​  ​loki:​latest ​  Loki Logging Driver ​  true
 </​code>​ </​code>​
  
-În acest moment, în directorul //​**/​mnt**//​ se va găsi mapatpe fiecare nod din cluster, volumul partajat ​de GlusterFS. Similar cu NFSacesta va putea fi folosit în fișiere Docker Compose ​ca un bind mount pentru a asigura persistență distribuită în aplicațiile noastre, astfel:+Odată instalat driver-ulacesta poate fi folosit la pornirea unui container sau a unui serviciu (fie din linia de comandăfie dintr-un ​fișier Docker Composepentru a redirecționa log-urile acestuia către Loki. Pe lângă această modificare pe care trebuie să o facem deployment-ului unei aplicațiieste nevoie să adăugăm serviciul de Loki (care rulează pe portul implicit 3100) și serviciul de Grafana (vom intra mai târziu în detalii despre Grafana, dar momentan ne este necesar pentru a putea vizualiza datele colectate de Loki). Ajungem ​astfel ​la următorul fișier Docker Compose, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]:​ 
 + 
 +<​spoiler>​ 
 +<code yaml prometheus-nexporter-cadvisor-testapp-loki-stack.yml>​ 
 +version: "​3.8"​
  
-<code yaml> 
 services: services:
-    ​db:+    ​prometheus: 
 +        image: prom/​prometheus
         volumes:         volumes:
-            - /mnt/db-config:/docker-entrypoint-initdb.d+            - ../configs/prometheus/​prometheus-nexporter-cadvisor-testapp.yml:/etc/​prometheus/​prometheus.yml 
-            - /mnt/db-data:/var/lib/postgresql/data+        ports: 
 +            ​9090:9090 
 +        networks: 
 +            ​monitoring 
 +            - visualizing 
 + 
 +    node_exporter:​ 
 +        image: prom/​node-exporter 
 +        deploy: 
 +            mode: global 
 +        volumes: 
 +            - /​proc:/​host/​proc:​ro 
 +            - /​sys:/​host/​sys:​ro 
 +            - /:/​rootfs:​ro 
 +        command: 
 +            - '​--path.procfs=/​host/proc' 
 +            - '​--path.rootfs=/rootfs'​ 
 +            - '​--path.sysfs=/host/​sys'​ 
 +            ​'​--collector.filesystem.mount-points-exclude=^/​(sys|proc|dev|host|etc)($$|/​)'​ 
 +        ports: 
 +            - 9100:9100 
 +        networks: 
 +            - monitoring 
 + 
 +    cadvisor: 
 +        image: gcr.io/​cadvisor/​cadvisor 
 +        deploy: 
 +            mode: global 
 +        volumes: 
 +            - /:/​rootfs:​ro 
 +            - /​var/​run:/​var/​run:​ro 
 +            - /​sys:/​sys:​ro 
 +            - /var/lib/docker/:/​var/​lib/​docker:​ro 
 +            - /​dev/​disk:/​dev/​disk/:​ro 
 +        ports: 
 +            - 8080:8080 
 +        networks: 
 +            - monitoring 
 + 
 +    testapp: 
 +        image: mobylab/​idp-laborator4-testapp 
 +        logging: 
 +            driver: loki 
 +            options: 
 +                loki-url: http://​host.docker.internal:​3100/​loki/​api/​v1/​push 
 +                loki-external-labels:​ job=myjob,​owner=radu,​environment=development 
 +        ports: 
 +            - 8000:8000 
 +            - 5000:5000 
 +        networks: 
 +            - monitoring 
 +            - logging 
 + 
 +    loki: 
 +        image: grafana/​loki 
 +        volumes: 
 +            - ../​configs/​loki/​loki.yml:/​etc/​config/​loki.yml 
 +            - ../​configs/​loki/​wal:/​wal 
 +        entrypoint:​ 
 +            - /​usr/​bin/​loki 
 +            - -config.file=/​etc/​config/​loki.yml 
 +        ports: 
 +            - 3100:3100 
 +        networks: 
 +            - logging 
 +            - visualizing 
 + 
 +    grafana: 
 +        image: grafana/​grafana 
 +        volumes: 
 +            - grafana-volume:/​var/​lib/​grafana 
 +        ports: 
 +            - 3000:3000 
 +        depends_on:​ 
 +            - loki 
 +        deploy: 
 +            placement:​ 
 +                constraints:​ [node.role == manager] 
 +        networks: 
 +            - visualizing 
 + 
 +networks: 
 +    monitoring:​ 
 +    logging: 
 +    visualizing:​ 
 + 
 +volumes: 
 +    grafana-volume:​
 </​code>​ </​code>​
 +</​spoiler>​
  
-==== Samba ====+Se poate observa adăugarea atributului **logging** pentru aplicația noastră, pe care am pus-o într-o rețea comună cu Loki. De asemenea, pentru partea de vizualizare a log-urilor, Loki este în aceeași rețea cu Grafana. De asemenea, se mai observă că Loki are nevoie de un fișier YAML de configurare. Puteți vedea un exemplu mai jos (care se găsește și în directorul **loki** din repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​configs|Configs]]):​
  
-TODO+<​spoiler>​ 
 +<code yaml loki.yml>​ 
 +auth_enabled:​ false
  
-==== SSHFS ====+server: 
 +  http_listen_port:​ 3100
  
-O altă variantă de a realiza persistență corectă într-un Docker Swarm este prin crearea de volume folosind alt driver de volum decât cel implicit (care le creează local). Un astfel de exemplu este driver-ul de SSHFS, numit [[https://hub.docker.com/​r/​vieux/​sshfs|vieux/​sshfs]]. SSHFS este un client de sistem de fișiere folosit pentru a monta și interacționa cu directoare și fișiere aflate pe un server, prin intermediul unei conexiuni SSH.+ingester: 
 +  lifecycler:​ 
 +    address: 127.0.0.
 +    ring: 
 +      kvstore: 
 +        store: inmemory 
 +      replication_factor:​ 1 
 +    final_sleep:​ 0s 
 +  chunk_idle_period:​ 5m 
 +  chunk_retain_period:​ 30s
  
-Pentru a putea folos driver-ul de SSHFS, acesta trebuie instalat pe toate gazdele Docker:+schema_config:​ 
 +  configs: 
 +  ​from: 2023-04-24 
 +    store: boltdb 
 +    object_store:​ filesystem 
 +    schema: v11 
 +    index: 
 +      prefix: index_ 
 +      period168h
  
-<code bash> +storage_config:​ 
-$ docker plugin install --grant-all-permissions vieux/sshfs+  ​boltdb:​ 
 +    directory: ​/tmp/​loki/​index 
 + 
 +  filesystem:​ 
 +    directory: /​tmp/​loki/​chunks 
 + 
 +limits_config:​ 
 +  enforce_metric_name:​ false 
 +  reject_old_samples:​ true 
 +  reject_old_samples_max_age:​ 168h 
 + 
 +chunk_store_config:​ 
 +  max_look_back_period:​ 0 
 + 
 +table_manager:​ 
 +  chunk_tables_provisioning:​ 
 +    inactive_read_throughput:​ 0 
 +    inactive_write_throughput:​ 0 
 +    provisioned_read_throughput:​ 0 
 +    provisioned_write_throughput:​ 0 
 +  index_tables_provisioning:​ 
 +    inactive_read_throughput:​ 0 
 +    inactive_write_throughput:​ 0 
 +    provisioned_read_throughput:​ 0 
 +    provisioned_write_throughput:​ 0 
 +  retention_deletes_enabled:​ false 
 +  retention_period:​ 0
 </​code>​ </​code>​
 +</​spoiler>​
  
-Odată ce driver-ul a fost instalatputem crea un volum peste SSFHS astfel:+<note important>​Atenție la data pe care o selectați la atributul **schema_config** și la perioada de indexare. Dacă perioadă de indexare nu este valabilă, nu veți putea vedea log-urile.</​note>​
  
-<​code ​bash+Se observă deci că nu trebuie modificat nimic în codul aplicației ale cărei log-uri dorim să le preluam, ci doar în Docker Compose. Odată ce facem deployment-ul,​ putem vizualiza log-urile preluate și agregate de Loki cu ajutorul Grafana. [[https://​grafana.com|Grafana]] este o suită open source de analiză și vizualizare de metrici (precum și alertare), care are suport pentru un număr mare de surse de date, printre care și Loki sau Prometheus. 
-$ docker ​volume create ​--driver ​vieux/sshfs -o sshcmd=remoteuser@remotenode:/home/remoteuser \ + 
-      -o password=remotepassword sshvolume+Odată ce serviciul de Grafana este pornit, putem accesa dashboard-ul său la [[http://<​IP>:​3000/​]]. Este nevoie întâi să ne logăm (credențialele implicite sunt **admin** / **admin**), după care putem adăuga o sursă nouă de date selectând opțiunea **Add your first data source** de pe ecranul principal. Ca tip de sursă de date, se selectează Loki, după care se introduce URL-ul [[http://​loki:​3100]] și se salvează. În acest moment, dacă intrăm pe [[http://<​IP>:​3000/​explore]],​ putem observa sursa de log-uri Loki și putem să selectăm în funcție de label-uri. Odată selectat un label, se pot vedea (în timp real sau pe o perioadă determinată) log-urile dorite, așa cum se observă în imaginea de mai jos. 
 + 
 +{{:​idp:​laboratoare:​loki.png?​800|}} 
 + 
 +==== Vizualizare ==== 
 + 
 +Așa cum am importat Loki ca sursă de date în Grafana pentru a realiza query-uri și a avea o interfață grafică ușor de utilizat, același lucru îl putem face și pentru Prometheus. Dacă, până acum, se generau date care să fie afișate în Prometheus, în cazul de față Prometheus funcționează ca sursă de date, iar Grafana va primi datele și le va afișa într-un dashboard. 
 + 
 +Tot ce trebuie făcut în Docker Compose este să punem Grafana și Prometheus în aceeași rețea, iar apoi să intrăm pe dashboard la [[http://<​IP>:​3000/​]] și să adăugăm noua sursă de date, similar cu Loki (URL-ul sursei fiind de această dată [[http://​prometheus:​9090]]). Odată adăugat Prometheus ca sursă, se pot crea dashboard-uri pe metricile expuse de Prometheus, așa cum se poate observa în imaginea de mai jos. 
 + 
 +{{:​idp:​laboratoare:​grafana.png?​800|}} 
 + 
 +==== Cozi de mesaje ==== 
 + 
 +În multe cazuri, am putea avea o aplicație unde este necesar să realizăm anumite procesări în mod asincron, separat de fluxul principal al aplicației,​ cu scopul de a îmbunătăți performanțele și timpii de răspuns ai aplicației noastre. Un mod de a realiza acest lucru este prin intermediul **cron jobs** și task-uri de background, dar o variantă mai facilă este utilizarea cozilor asincrone de mesaje. 
 + 
 +[[https://​hub.docker.com/​_/​rabbitmq|RabbitMQ]] este un exemplu popular de broker asincron de mesaje care este ușor de pornit și configurat, putând gestiona milioane de mesaje. RabbitMQ funcționează pe modelul **publish/​subscribe**,​ unde procese de tip **publisher** generează date care sunt stocate de broker-ul RabbitMQ în cozi, iar procese de tip **subscriber** se abonează la cozile respective și primesc mesajele atunci când acestea sunt publicate.  
 + 
 +În cadrul exemplului din acest laborator, aplicația [[https://​gitlab.com/​mobylab-idp/​laborator-7/​testapp|Testapp]] pe care am văzut-o înainte va avea rolul de **publisher**. Atunci când se trimite un POST pe ruta **generate_event** cu un parametru numit **event**, se va publica evenimentul respectiv într-o coadă numită **task_queue**. De cealaltă parte, va mai exista o aplicație separată numită Worker (ale cărei surse se găsesc [[https://​gitlab.com/​mobylab-idp/​laborator-7/​worker|aici]]) care va acționa ca **subscriber**. Se va abona la mesajele din coada **task_queue** și le va afișa atunci când le primește. Puteți găsi și o imagine Docker deja construită pentru Worker pe Docker Hub cu numele **mobylab/​idp-laborator4-worker**. 
 + 
 +<note important>​Este util de menționat faptul că, pentru a realiza conexiunea cu broker-ul RabbitMQ atât în Testapp, cât și în Worker, folosim pachetul [[https://​pika.readthedocs.io/​en/​stable/​|Pika]],​ deoarece acesta oferă o implementare a protocolului AMQP 0-9-1 folosit de RabbitMQ.</​note>​ 
 + 
 +Având imaginile pentru Testapp și Worker, putem să ne actualizăm fișierul Docker Compose astfel: 
 + 
 +  * adăugăm un serviciu de RabbitMQ cu imaginea **rabbitmq:​management-alpine** și îl punem într-o rețea nouă 
 +  * punem serviciul **testapp** (deja existent) și în această nouă rețea 
 +  * adăugăm serviciul Worker și îl punem în aceeași rețea. 
 + 
 +Cu aceste modificări,​ ajungem la următorul fișier Docker Compose, pe care îl puteți găsi în repository-ul [[https://​gitlab.com/​mobylab-idp/​laborator-7/​docker|Docker]]:​ 
 + 
 +<​spoiler>​ 
 +<​code ​yaml prometheus-nexporter-cadvisor-testapp-loki-rmq-stack.yml
 +version: "​3.8"​ 
 + 
 +services: 
 +    prometheus:​ 
 +        image: prom/​prometheus 
 +        volumes: 
 +            - ../​configs/​prometheus/​prometheus-nexporter-cadvisor-testapp.yml:/​etc/​prometheus/​prometheus.yml 
 +        ports: 
 +            - 9090:9090 
 +        networks: 
 +            - monitoring 
 +            - visualizing 
 + 
 +    node_exporter:​ 
 +        image: prom/​node-exporter 
 +        deploy: 
 +            mode: global 
 +        volumes: 
 +            - /​proc:/​host/​proc:​ro 
 +            - /​sys:/​host/​sys:​ro 
 +            - /:/​rootfs:​ro 
 +        command: 
 +            - '​--path.procfs=/​host/​proc'​ 
 +            - '​--path.rootfs=/​rootfs'​ 
 +            - '​--path.sysfs=/​host/​sys'​ 
 +            - '​--collector.filesystem.mount-points-exclude=^/​(sys|proc|dev|host|etc)($$|/​)'​ 
 +        ports: 
 +            - 9100:9100 
 +        networks: 
 +            - monitoring 
 + 
 +    cadvisor: 
 +        image: gcr.io/​cadvisor/​cadvisor 
 +        deploy: 
 +            mode: global 
 +        volumes: 
 +            - /:/​rootfs:​ro 
 +            - /​var/​run:/​var/​run:​ro 
 +            - /​sys:/​sys:​ro 
 +            - /var/lib/docker/:/​var/​lib/​docker:​ro 
 +            ​/​dev/​disk:/​dev/​disk/:​ro 
 +        ports: 
 +            ​8080:8080 
 +        networks: 
 +            - monitoring 
 + 
 +    testapp: 
 +        image: mobylab/​idp-laborator4-testapp 
 +        logging: 
 +            ​driver: loki 
 +            options: 
 +                loki-url: http://​host.docker.internal:​3100/​loki/​api/​v1/​push 
 +                loki-external-labels:​ job=myjob,​owner=radu,​environment=development 
 +        ports: 
 +            - 8000:8000 
 +            - 5000:5000 
 +        depends_on:​ 
 +            - rabbitmq 
 +        networks: 
 +            - monitoring 
 +            - logging 
 +            - rmq 
 + 
 +    rabbitmq: 
 +        image: rabbitmq:​management-alpine 
 +        ports: 
 +            - 5672:5672 
 +            - 15672:​15672 
 +        networks: 
 +            - rmq 
 +        hostname: rabbitmq 
 + 
 +    worker: 
 +        imagemobylab/idp-laborator4-worker 
 +        depends_on:​ 
 +            - rabbitmq 
 +        networks: 
 +            - rmq 
 + 
 +    loki: 
 +        image: grafana/loki 
 +        volumes: 
 +            ../​configs/​loki/​loki.yml:/​etc/​config/​loki.yml 
 +            - ../​configs/​loki/​wal:/​wal 
 +        entrypoint:​ 
 +            - /​usr/​bin/​loki 
 +            - -config.file=/​etc/​config/​loki.yml 
 +        ports: 
 +            - 3100:3100 
 +        networks: 
 +            - logging 
 +            - visualizing 
 + 
 +    grafana: 
 +        image: grafana/​grafana 
 +        volumes: 
 +            - grafana-volume:/​var/​lib/​grafana 
 +        ports: 
 +            - 3000:3000 
 +        depends_on:​ 
 +            - loki 
 +        deploy: 
 +            placement:​ 
 +                constraints:​ [node.role == manager] 
 +        networks: 
 +            - visualizing 
 + 
 +networks: 
 +    monitoring:​ 
 +    logging: 
 +    visualizing:​ 
 +    rmq: 
 + 
 +volumes: 
 +    grafana-volume:​
 </​code>​ </​code>​
 +</​spoiler>​
  
-Astfelse creează local un volum peste SSH, aflat pe serverul ​//**remotenode**//. La server, conectarea se face cu numele de utilizator //**remoteuser**// și parola //**remotepassword**// (dacă există chei partajate configurate între client și server, ​nu mai este necesară parola). Volumul astfel creat poate fi folosit ca orice alt volum, iar tot ce se scrie în el va fi persistat la server.+Odată ce deployment-ul este făcutputem întâi să verificăm dacă broker-ul RabbitMQ este funcțional intrând ​pe [[http://<​IP>:​15672/​]] și logându-ne cu credențialele implicite ​**guest** / **guest**. Putem astfel observa că avem o singură coadă (**task_queue**) pe care nu s-a publicat încă vreun mesaj.
  
-Volumul peste SSHFS se poate crea direct ​la rularea unui container, astfel:+{{:​idp:​laboratoare:​rmq1.png?​800|}} 
 + 
 +Dacă vrem să publicăm mesaje, este suficient să trimitem o cerere de POST pe ruta **generate_event** cu un parametru numit **event** către Testapp (adică pe portul 5000). În consola administrativă a RabbitMQ, putem observa prezența mesajului. 
 + 
 +{{:​idp:​laboratoare:​rmq2.png?​800|}} 
 + 
 +De asemenea, putem să ne uităm ​la log-urile aplicației Worker și să verificăm că mesajul a fost primit cu succes, astfel ​(presupunând că stiva noastră de servicii se numește **prom**):
  
 <code bash> <code bash>
-$ docker ​run -d --volume-driver vieux/sshfs \ +$ docker ​service logs prom_worker ​                                                           ​ 
-    --mount src=sshvolume,​target=/​myvol,​volume-opt=sshcmd=remoteuser@remotenode:/​home/​remoteuser,​volume-opt=password=remotepassword \ + 
-    ​alpine+prom_worker.1.q3clmboqw5ij@docker-desktop ​   | Worker started 
 +prom_worker.1.q3clmboqw5ij@docker-desktop ​   | Worker connected 
 +prom_worker.1.q3clmboqw5ij@docker-desktop ​   | Received hello
 </​code>​ </​code>​
  
-<note tip> +<note tip>Pentru a vă ușura testarea acestui laborator, găsiți în directorul **postman** din repository-ul ​[[https://gitlab.com/mobylab-idp/​laborator-7/configs|Configs]] o colecție ​de rute pe care le puteți importa direct în Postman.</​note>​
-Puteți testa SSHFS în [[https://training.play-with-docker.com/docker-volume-sshfs/|acest sandbox]] de Play with Docker. +
-</​note>​ +
-==== Exercițiu ====+
  
 +==== Exerciții ====
  
-Laboratorul se va desfasura, din nou, pe [[https://​www.docker.com/​play-with-docker|Play With Docker]] si va avea suport ​de cod [[https://​gitlab.com/​mobylab-idp/laborator3|repo-ul ​din laboratorul precedent]], peste care am mai adaugat 2 fisiere ​.yml in plus //(stack-nfs.yml si stack-kong.yml)//.+  ​Pornind ​de la structura din [[https://​gitlab.com/​mobylab-idp|repo-ul ​oficial al laboratorului]], creați un grup cu trei repository-uri (//​**BooksService**//,​ //​**Configs**//​ și //​**IOService**//​). 
 +  - Modificați fișierul ​//**stack-kong.yml**// pentru a folosi imagini din registrul vostru pentru serviciile de business logic și IO. 
 +  ​Porniți o stivă de servicii pentru aplicația de bibliotecă pe baza fișierului Docker Compose modificat. 
 +  - Pe baza exemplului de fișier Docker Compose pentru Portainer de mai sus, porniți o stivă de servicii Portainer. 
 +  - Din Portainer, generați un webhook pentru serviciul de business logic. 
 +  - Instalați și configurați un GitLab Runner. 
 +  - Adăugați un script //​**.gitlab-ci.yml**// în repository-ul de business logic cu o etapă de //​**build**//​ și una de //​**deploy**//,​ conform modelului din laborator. 
 +  - Faceți un push din repository-ul de business logic și verificați că stiva de servicii se actualizează corespunzător.
idp/laboratoare/04.1617248275.txt.gz · Last modified: 2021/04/01 06:37 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