Differences

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

Link to this comparison view

cc:laboratoare:03 [2020/10/25 20:23]
alexandru.hogea [Composing a Composition of Compose Files]
cc:laboratoare:03 [2022/10/23 19:39] (current)
florin.mihalache
Line 1: Line 1:
-===== Laboratorul 03. Docker Compose ​=====+====== 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> 
 +apiVersion: apps/v1 
 +kind: Deployment 
 +metadata: 
 +  name: <> #name  
 +spec: 
 +  replicas: <x> #no of replicas 
 +  selector: 
 +    matchLabels:​ 
 +      key: value 
 +  template: 
 +    metadata: 
 +      labels: 
 +        pod-key: pod-value 
 +    spec: 
 +      containers:​ 
 +      - name: nginx 
 +        image: <> #you can use the nginx image 
 +</​code>​
  
-[[https://​docs.docker.com/​compose/​|Docker Compose]] este un creat de catre Dockerfolosit pentru **centralizarea configurarii** ​de rulare a containerelor in maniera **declarativa**.+Dorim, de exemplu, să facem următorul deploymentul,​ cu numele ''​cc-dep-01'',​ cu 4 replici și cu un label-ul ''​app:​ lab3cc'':​ 
 +<code yaml> 
 +kind: Deployment 
 +metadata: 
 +  name: cc-dep-01 
 +spec: 
 +  replicas: 10 
 +  selector: 
 +    matchLabels:​ 
 +      app: lab3cc 
 +  template: 
 +    metadata: 
 +      labels: 
 +        app: lab3cc 
 +    spec: 
 +      containers:​ 
 +      - name: nginx 
 +        image: nginx 
 +</​code>​
  
-In mod clasic, pentru rularea unor containere, este nevoie sa rulati comanda aferenta ​de rulare (__docker run__) si sa dati toti parametri necesariAcest proces poate deveni anevoios daca este repetat pentru pornirea mai multor containere.+<​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>​
  
-Un mod primitiv ​de a "​salva"​ configuratia de rulare este sa va creati scripturiProblema in rularea mai multor scripturi ​este pierderea consistentei in configurare (Ce container la ce retea se conecteazacu cine comunica, etc...).+Ajungem la partea ​de upgrade ​unui deploymentUn use-case relevant ​este unul des întâlnit în ziua de azipresupunem că a apărut o nouă versiune a aplicației și vrem să folosim versiunea curentă.
  
-Utilizand fisiere de configurare **.yml**, Docker Compose centralizeaza procesul de configurare intr-o maniera naturaladeclarativa.+În cazul deployment-ului nostru, vrem să folosim ​nouă versiune a webserver-ului aplicației noastredeci vrem să folosim o versiune mai nouă a nginx.
  
-Mai mult de atat, formatul pentru fisiere compose este utilizat si in cadrul ​**Docker Swarm**, orchestratorul creat de Docker pentru gestiunea serviciilor Docker. Despre Swarm vom discuta ​la laboratorul urmator.+<​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>​
  
-<note tip>O sa observati de mai multe ori ca folosim terminologia servicii/​containere. Asta pentru ca Docker Swarm lucreaza cu servicii, in timp ce Docker Compose cu containere. Ne referim la amandoua in acelasi context deoarece configuratia, este, in proportie ​de 90%identicaindiferent de utilizarea Swarm sau Compose</​note>​+În primul rândun aspect foarte important ​este că pod-urile sunt upgraded secvențialnu toate odată, după ce un număr ​de noi pod-uri au fost createurmează să se șteargă cele vechiprocedeul se repetă până când toate pod-urile au fost updated.
  
-==== Elemente Cheie ====+<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>​
  
-=== Formatul unui fisier YAML ===+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.
  
-Fisierele YAML (Yet Another Markup Language)de obicei, sunt folosite ​pentru a scrie configurari declarativ. Formatul este unul foarte usor de inteles si folosit:+===== Rollouts ===== 
 +Am realizat că avem o greșeală în deploymentul nostru, pentru a reveni la versiunea anterioară folosim următoarea comandă''​kubectl rollout history deployment <​depname>''​
  
-  ​elemente ​de tip cheie:​valoare +<​note>​ 
-  * aliniatele **identate** reprezinta proprietati copii ale pargrafelor anterioare +Tasks: 
-  * listele se delimiteaza prin +  ​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>​
  
-=== Exemplu Fisier docker-compose.yml === +Pentru a modifica imaginea folosită de un deployment, avem următoarea comandă: ''​kubectl set image deployment ​<depnamenginx=nginx:failTest''​ 
-<code yaml> +Î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ă.
-# docker-compose.yml +
-version: '3.8+
-services: +
-  api: +
-    build: . # construieste imaginea dintr-un Dockerfile +
-    image: nume-imagine-registru:​versiune # foloseste ​o imagine ​de pe registrul curent +
-    environment:​ +
-      NODE_ENV: development +
-      VARIABILA_DE_MEDIU:​ valoare +
-    ports: +
-     - "​5000:​80"​ +
-    networks: +
-     - network-laborator-3 +
-  postgres: +
-    image: postgres:​12 +
-    environment:​ +
-      PGPASSWORD_FILE:​ /​run/​secrets/​parola-mea-ultra-secreta +
-    volumes: +
-      - volum-laborator-3:/​var/​lib/​postgresql/​data +
-      - ./scripturi-initializare/​init-db.sql:/​docker-entrypoint-init.d/​init-db.sql +
-    networks: +
-     - network-laborator-3+
  
-volumes: +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>''​
-  volum-laborator-3:+
  
-networks+Observați ca avem mai multe "​revizii"​ ale deployment-ului nostru. Pentru a ne întoarce la o anumită revizie, folosim următoarea comandă
-  ​network-laborator-3:+''​kubectl rollout history deployment cc-dep-01 --revision=2''​
  
-secrets: +===== Servicii ===== 
-  ​parola-mea-ultra-secreta+Care sunt serviciile cunoscute în Kubernetes? Care este diferența între ele? Ne interesează în mod special diferența dintre ClusterIP și NodePort. 
-    file'​./​parola-mea-nu-atat-de-secreta.txt'​+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. 
 + 
 +Exemplu
 +<code yaml> 
 +apiVersionv1 
 +kind: ConfigMap 
 +metadata: 
 + name: db-config-map 
 +data: 
 + ​POSTGRES_USER:​ "​admin"​ 
 + ​POSTGRES_PASSWORD:​ "​admin"​ 
 + ​POSTGRES_DB:​ "​books"​
 </​code>​ </​code>​
  
-=== Version ===+Când o să creăm pod-ul / deployment-ul,​ o să folosim acest ConfigMap pentru a injecta variabilele de mediu. Pentru a avea datele persistente,​ avem nevoie, asa cum știm din labul trecut, de un PV și de un PVC: 
 +  * ''​PersistentVolume''​ (PV): 
 +<code yaml> 
 +apiVersion: v1 
 +kind: PersistentVolume 
 +metadata: 
 + name: postgres-pv-volume 
 + ​labels:​ 
 +  type: local 
 +spec: 
 + ​storageClassName:​ manual 
 + ​capacity:​ 
 +   ​storage:​ 1Gi 
 + ​accessModes:​ 
 +   - ReadWriteOnce 
 + ​hostPath:​ 
 +   path: "/​mnt/​data"​ 
 +</​code>​ 
 +  * ''​PersistentVolumeClaim''​ (PVC): 
 +<code yaml> 
 +apiVersion: v1 
 +kind: PersistentVolumeClaim 
 +metadata: 
 + name: posgress-pvc 
 +spec: 
 + ​storageClassName:​ manual 
 + ​accessModes:​ 
 +   - ReadWriteOnce 
 + ​resources:​ 
 +   ​requests:​ 
 +     ​storage:​ 1Gi 
 +</​code>​
  
-**Version** descrie ce set de functionalitati va fi incarcat la rularea utilitarului Docker Compose +Pentru a crea pod-ul ​de Postgres, avem următorul ​fișier: 
-<note important>Este **obligatoriu** sa treceti versiunea in orice fisier docker-compose.yml </note>+<code yaml> 
 +apiVersion: v1 
 +kind: Pod 
 +metadata: 
 + name: db-pod 
 + ​labels:​ 
 +   app: postgres 
 +spec: 
 + ​containers:​ 
 +   - image: postgres:10.
 +     name: postgres 
 +     ​volumeMounts:​ 
 +     - name: myvol 
 +       ​mountPath:​ /​etc/​config 
 +     ​ports:​ 
 +       - containerPort:​ 5432 
 +     ​envFrom:​ 
 +       - configMapRef:​ 
 +           name: db-config-map 
 + ​volumes:​ 
 +   - name: myvol 
 +     ​persistentVolumeClaim:​ 
 +       ​claimName:​ posgress-pvc 
 +</code>
  
-=== Services ===+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> 
 +apiVersion: v1 
 +kind: Service 
 +metadata: 
 + name: postgres 
 + ​labels:​ 
 +   app: postgres 
 +spec: 
 + type: ClusterIP 
 + ​ports:​ 
 +  - port: 5432 
 + ​selector:​ 
 +  app: postgres 
 +</​code>​
  
-**Services** descrie serviciile/​containerele ce vor rula dupa ce configuratia este pornita ​de catre compose. Fiecare serviciu reprezinta un container care va avea **numele** si configuratia serviciului. In exemplul de mai suscontainerele se vor numi //api// si //​postgres//​. +Pentru a porni podul de APIavem următorul ​fișier:
- +
-  * **build** - mentioneaza folderul unde se afla Dockerfile-ul de la care se va efectua construirea containerului +
-  * **image** - mentioneaza numele imaginii folosit pentru rularea containerului +
-<note important>​build si image sunt optiuni disjuncte</​note>​ +
-  * **ports** - lista de intrari de tipul **PORT_HOST:​PORT_SERVICIU** unde este realizata maparea de porturi +
-  * **volumes** - lista de intrari de tipul **VOLUM_HOST:​CALE_SERVICIU** unde sunt precizate maparile de volume. Aceleasi reguli care se aplica la rularea clasica sunt mentinute si aici. VOLUM_HOST poate fi **named volume** sau **bind mount**. +
-  * **networks** - lista de retele din care face parte serviciul/​containerul +
-  * **secrets** - lista de secrete ce vor fi folosite in cadrul serviciului/​containerului +
-<note tip>​Secretele trebuie trecute si in cadrul variabilelor de mediu, conform documentatiei. De exemplu, [[https://​hub.docker.com/​_/​postgres|in configuratia Postgres]] trebuie trecute in variabile de mediu speciale, sufixate cu **_FILE**, impreuna cu calea lor completa (adica /​run/​secrets/​NUME_SECRET)</​note>​ +
-  * **environment** - obiect de intrari de tipul **VARIABILA_MEDIU_SERVICIU:​valoare** care injecteaza variabilele de mediu specificate la rularea serviciului/​containerului +
- +
-=== Volumes === +
- +
-**Volumes** descrie //NAMED VOLUMES// utilizate in cadrul configuratiei. +
-<note tip>​Observati ca **volumes**,​ ca si proprietate top level, este scrisa pe acelasi nivel de identatie ca **services**. Nu trebuie confundata cu proprietatea copil **volumes** din interiorul configuratiei serviciilor</​note>​ +
- +
-Volumele se trec sub forma de obiecte. Daca nu se doreste schimbarea configuratiei default, valoarea este un camp gol. In laboratorul urmator vom lucra cu volume NFS, unde va trebui oferita o configuratie custom. +
- +
-=== Networks === +
- +
-**Networks** descrie //​retelele//​ utilizate in cadrul configuratiei. +
-<note tip>​Observati ca **networks**,​ ca si proprietate top level, este scrisa pe acelasi nivel de identatie ca **services**. Nu trebuie confundata cu proprietatea copil **networks** din interiorul configuratiei serviciilor</​note>​ +
- +
-Retelele se trec sub forma de obiecte. Daca nu se doreste schimbarea configuratiei default, valoarea este un camp gol. Un exemplu de configuratie de retea este atunci cand se foloseste o retea care deja exista, de exemplu:+
 <code yaml> <code yaml>
-networks+apiVersionv1 
-  ​reteaua-mea-care-de-fapt-exista+kind: Pod 
-    ​externaltrue +metadata: 
-    name: reteaua-originala-care-deja-exista+ 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>​
  
-In cazul de mai sus//reteaua-mea-care-de-fapt-exista// este doar o "​redenumire"​ a unei retele deja existente.+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''​
  
-=== Secrets ===+Apoi verificați portul asignat de noul serviciu (31598): 
 +{{ :​cc:​laboratoare:​image5.png |}}
  
-**Secrets** descrie //​secretele//​ utilizate in cadrul configuratiei. +Folosiți Postman pentru a accesa API-ul deployed: 
-<note tip>​Observati ca **secrets**,​ ca si proprietate top level, este scrisa pe acelasi nivel de identatie ca **services**Nu trebuie confundata cu proprietatea copil **secrets** din interiorul configuratiei serviciilor</​note>​+{{ :​cc:​laboratoare:​image2.png?600 |}}
  
-Secretele retin informatii sensibile intr-o maniera securizata, criptata, in cadrul Swarm, despre care vom vorbi la laboratorul urmator. In compose nu sunt securizate, insa au fost introduse pentru a usura tranzitia catre Swarm.+Avem următoarea eroare: 
 +{{ :​cc:​laboratoare:​image1.png?500 |}}
  
-In cadrul compose, secretele pot proveni doar din fisiere externe. Fisierele externe sunt mentionate ​pentru ​fiecare secret in parte. +Avem această eroare ​pentru ​că baza de date nu a fost configuratăPentru a configura baza de date avem mai multe variante, cea mai simpla (dar și cea mai ineficientă) este următoarea:​ 
- +  * obtineți un shell pe podul de Postgres: ''​kubectl exec -it db-pod bash''​ 
-==== Comenzi Docker Compose ==== +  * 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''​ 
- +{{ :​cc:​laboratoare:​image4.png?500 |}} 
-Comenzile pentru interactiunea cu docker-compose seamana, ca si sintaxa, cu cele clasice ​de docker. Mai jos va oferim cele mai utilizate comenzi. +  * rulați următorul script pentru a inițializa baza de date: 
- +<code sql> 
-<code bash> +CREATE TABLE IF NOT EXISTS books 
-# Porneste containerele +    id uuid PRIMARY KEY NOT NULL , 
-docker-compose start +    title varchar NOT NULL, 
-# Opreste containerele +    ​author varchar NOT NULL 
-docker-compose stop +);
-# Pune in stare de pauza conainerele unui serviciu. Diferenta fata de stop e ca la procesul din container se trimite SIGPAUSE +
-docker-compose pause +
-# Scoate din stare de pauza containerele +
-docker-compose unpause +
-# Listeaza containerele active +
-docker-compose ps +
-# Face build, recreaza, porneste si ataseaza containere ​la un serviciu +
-docker-compose up +
-# Serviciile ruleaza in background detasat ​de terminalul care le-a initializat +
-docker-compose up -d +
-# Creaza imaginile inainte de pornire unde a fost declarata calea pentru ​un Dockerfile pentru un container +
-docker-compose up --build +
-# Se foloseste fisierul de docker-compose specificat in loc de cel implicit +
-docker-compose -f my-docker-compose.yml up +
-# Opreste containerele si le sterge pe acestea impreuna cu retelele, volumele si imagine create la up. +
-docker-compose down +
-# Sterge toate containerele oprite ​(se poate specifica la sfarsit si numele containerului care trebuie sters) +
-docker-compose rm +
-# Cu -s se opresc toate containerele si cu -v se sterg si volumele anonime atasate +
-docker-compose rm -s -v +
 </​code>​ </​code>​
  
-==== Composing a Composition of Compose Files ====+Incercați din nou comanda GET din Postman. Inserați ceva în baza de date: 
 +{{ :​cc:​laboratoare:​image3.png?​500 |}}
  
-Docker Compose este recomandat sa fie utilizat **doar** in etapa de **dezvoltare locala**. Pentru medii de testare sau productie se foloseste Docker Swarm sau alte orchestratoare,​ precum Kubernetes.  +Stergeți pod-ul ​de Postgres și incercați să faceți GETAr trebui să primiți următoarea eroare: 
- +{{ :​cc:​laboratoare:​image6.png?500 |}}
-Tocmai pentru ca este folosit in etapa de dezvoltare, acesta are un mecanism de a combina mai multe fisiere compose pentru a crea mai multe configuratii de rulare, fara a replica partile comune +
- +
-Pentru a rula o configuratie de compose bazata pe mai multe fisiere, este nevoie sa rulati  +
- +
-<code bash> +
-docker-compose -f fisier-compose-1.yml -f fisier-compose-2.yml up --build +
-</​code>​+
  
-Informatiile din //fisier-compose-2.yml//​ vor suprascrie/​completa informatiile din fisier-compose-1.yml. Acest lucru este util pentru a testa diverse configuratii rapid.+Reporniți pod-ul de baza de date și executați un GET: 
 +{{ :​cc:​laboratoare:​image7.png?500 |}}
cc/laboratoare/03.1603650203.txt.gz · Last modified: 2020/10/25 20:23 by alexandru.hogea
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