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.

Pentru un fișier de deployment putem să avem următorul template:

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

Dorim, de exemplu, să facem următorul deploymentul, cu numele cc-dep-01, cu 4 replici și cu un label-ul app: lab3cc:

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

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.

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ă.

În cazul deployment-ului nostru, vrem să folosim o nouă versiune a webserver-ului aplicației noastre, deci vrem să folosim o versiune mai nouă a nginx.

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 cluster. Ce se întâmplă?

În primul rând, un aspect foarte important este că pod-urile sunt upgraded secvențial, nu toate odată, după ce un număr de noi pod-uri au fost create, urmează să se șteargă cele vechi, procedeul se repetă până când toate pod-urile au fost updated.

Așa cum puteți observa, numele unui pod are următoarea structură: numeDeployment-identificatorReplicaSet-identificatorPod

Task:

  • Listați toate obiectele de tip ReplicaSet din cluster: kubectl get rs # am folosit o prescurtare

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.

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>

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

Pentru a modifica imaginea folosită de un deployment, avem următoarea comandă: kubectl set image deployment <depname> nginx=nginx:failTest Î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ă.

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>

Observați ca avem mai multe “revizii” ale deployment-ului nostru. Pentru a ne întoarce la o anumită revizie, folosim următoarea comandă: kubectl rollout history deployment cc-dep-01 –revision=2

Servicii

Care sunt serviciile cunoscute în Kubernetes? Care este diferența între ele? Ne interesează în mod special diferența dintre ClusterIP și NodePort. 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:

apiVersion: v1
kind: ConfigMap
metadata:
 name: db-config-map
data:
 POSTGRES_USER: "admin"
 POSTGRES_PASSWORD: "admin"
 POSTGRES_DB: "books"

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):
apiVersion: v1
kind: PersistentVolume
metadata:
 name: postgres-pv-volume
 labels:
  type: local
spec:
 storageClassName: manual
 capacity:
   storage: 1Gi
 accessModes:
   - ReadWriteOnce
 hostPath:
   path: "/mnt/data"
  • PersistentVolumeClaim (PVC):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: posgress-pvc
spec:
 storageClassName: manual
 accessModes:
   - ReadWriteOnce
 resources:
   requests:
     storage: 1Gi

Pentru a crea pod-ul de Postgres, avem următorul fișier:

apiVersion: v1
kind: Pod
metadata:
 name: db-pod
 labels:
   app: postgres
spec:
 containers:
   - image: postgres:10.4
     name: postgres
     volumeMounts:
     - name: myvol
       mountPath: /etc/config
     ports:
       - containerPort: 5432
     envFrom:
       - configMapRef:
           name: db-config-map
 volumes:
   - name: myvol
     persistentVolumeClaim:
       claimName: posgress-pvc

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:

apiVersion: v1
kind: Service
metadata:
 name: postgres
 labels:
   app: postgres
spec:
 type: ClusterIP
 ports:
  - port: 5432
 selector:
  app: postgres

Pentru a porni podul de API, avem următorul fișier:

apiVersion: v1
kind: Pod
metadata:
 name: apipod
 labels:
   app: api
spec:
 containers:
   - image: andreidamian/lab3cc:first
     name: apicontainer
     env:
      - name: PGUSER
        value: "admin"
      - name: PGPASSWORD
        value: "admin"
      - name: PGDATABASE
        value: "books"
      - name: PGHOST
        value: "postgres"
      - name: PGPORT
        value: "5432"

Dupa ce și acest pod este up and running, trebuie 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

Apoi verificați portul asignat de noul serviciu (31598):

Folosiți Postman pentru a accesa API-ul deployed:

Avem următoarea eroare:

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
  • 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

  • rulați următorul script pentru a inițializa baza de date:
CREATE TABLE IF NOT EXISTS books (
    id uuid PRIMARY KEY NOT NULL ,
    title VARCHAR NOT NULL,
    author VARCHAR NOT NULL
);

Incercați din nou comanda GET din Postman. Inserați ceva în baza de date:

Stergeți pod-ul de Postgres și incercați să faceți GET. Ar trebui să primiți următoarea eroare:

Reporniți pod-ul de baza de date și executați un GET:

cc/laboratoare/03.txt · Last modified: 2022/10/23 19:39 by florin.mihalache
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