Kubernetes (prescurtat K8s) este cel mai popular orchestrator, folosit la scara largă și oferit ca și CaaS (Container as a Service) de toți vendorii de infrastructură (Amazon, Google, Microsoft). Este considerat standard în materie de deployment al serviciilor orchestrate.
Varianta originală este dezvoltată de Google, este open source și face parte din Cloud Native Foundation (CNF). Fiecare vendor adaugă pachete în plus, pentru a îl adapta la ecosistemul proprietar (de exemplu, Azure adaugă comenzi și straturi în plus peste varianta de baza).
Este mai complicat decât Docker Swarm, dar în multe situații nu veți fi nevoiți să rulați propriul vostru cluster de Kubernetes, ci doar să rulați aplicații peste un cluster de Kubernetes gata oferit (de exemplu, Azure Kubernetes Service (AKS)).
Avantajul major asupra Docker Swarm îl oferă utilizarea sa în industrie, cât și faptul că este mai flexibil și oferă mai multe funcționalități, însă nu out of the box. Faptul că este customizabil implică, bineînțeles, și un factor de dificultate mai mare. Kubernetes este mai greu de învățat decât Swarm, dar are și mai multe capabilități.
Kubernetes se poate seta în multe moduri:
Este metoda cea mai dificilă, în care se leagă mai multe mașini în rețea folosind Kubeadm. Se folosește pentru a crea un cluster de la 0 și necesită un nivel de cunoștințe mediu-avansat.
Asa cum am precizat în introducere, sunt puține cazurile cand veți trebui să setați un cluster de la 0, deoarece vendorii principali de infrastructură au versiunile lor de Kubernetes și sistemele de CaaS deja pregătite.
Cea mai buna metodă de a învăța este să vă setați local un cluster cu un singur nod de Kubernetes. Acest lucru se poate face în mai multe moduri:
Precum Docker Swarm, Kubernetes este un sistem format din mai multe componente:
Kubernetes folosește o ierarhie logică de componente pentru aplicații:
MicroK8s reprezintă o versiune de Kubernetes folosită pe scară mică, pentru testarea aplicațiilor în medii offline (pe local, pe mașini virtuale). Pentru laboratoarele de Cloud Computing, acesta poate fi folosit (nu este obligatoriu, puteți să alegeți ce doriți). Instrucțiuni legate de setup-ul MicroK8s le aveți aici.
Pentru pornirea unui cluster de Kubernetes pe local se poate folosi următoarea comandă: minikube start
.
O altă modalitate de a crea un cluster Kubernetes este folosind kind
. Instrucțiunile de setup pentru acest utilitar le aveți aici. kind
rulează Kubernetes în Docker, simulând câte un nod din cluster cu câte un container.
Pentru crearea unui cluster folosind kind
ne putem folosi de un fișier de configurare:
# Configurare de cluster cu trei noduri (dintre care doi workeri) kind: Cluster # precizăm ce dorim să creăm: cluster, pod, etc. apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker
Pentru a crea un cluster folosind kind și un fișier de configurare, folosim următoarea comandă: kind create cluster –config kind-config.yaml
, unde kind-config.yaml
reprezintă numele fișierului de configurare a cluster-ului.
Dacă dorim să aflăm informații despre cluster-ul curent folosim următoarea comandă: kubectl cluster-info [dump]
Pentru a afișa date despre componentele din cluster, folosim comanda kubectl get all
.
Dacă dorim să aflăm informații despre nodurile din cluster folosim următoarea comandă: kubectl get nodes
. Pentru a vedea detalii despre nodurile dintr-un cluster folosim comanda kubectl describe nodes <node>
.
Pentru ștergerea cluster-ului în care ne aflăm folosim comanda kind delete cluster
.
Putem crea și rula pod-uri în două maniere: imperativă (prin comenzi cu parametri) și declarativă (folosind fișiere de configurare).
Dacă dorim să rulăm un pod în mod declarativ, folosim următoarea comandă: kubectl run <pod-name> –image <image name>
. Exemple practice de folosire:
kubectl run my-nginx --image=nginx kubectl run alpine --image=alpine
Dacă dorim ca un pod să ruleze interactiv (mai sus aveți exemple de pod-uri care rulează în background), folosim comanda kubectl run -i –tty –rm <pod-name> –image=<image name>
. Exemplu de folosire: kubectl run -i –tty –rm alpine –image=alpine
Un pod poate rula în cadrul unui namespace. Dacă dorim acest lucru, creăm mai întâi un namespace folosind comanda kubectl create namespace <namespace-name>
. Pentru a rula un pod în cadrul unui namespace: kubectl run alpine –image=alpine -n <namespace-name>
Dacă dorim să afișăm toate pod-urile folosim comanda kubectl get pods
și dacă dorim să listăm toate namespace-urile folosim kubectl get namespaces
. De asemenea, având în vedere că un pod poate rula în cadrul unui namespace, putem să afișăm toate pod-urile din cadrul unui namespace: kubectl get pods -n <namespace>
Pentru a obține mai multe informații cu ajutorul comenzii get, putem să folosim următoarea sintaxă: kubectl get pods -o wide
Pentru a rula o comanda in interiorul unui pod, folosim subcomanda exec:
kubectl exec -it <podname> <command> kubectl exec -it mypod ls # (mypod trebuie sa existe deja in cluster)
my-first-namespace
, rulați două pods (unul cu imaginea alpine, altul cu imaginea nginx) în cadrul namespace-ului creat, afișati namespace-urile și pod-urile din cadrul acelui namespace. Rulați comanda ls în ambele pod-uri.
După cum s-a putut observa mai sus, pentru crearea unui cluster am folosit un fișier de configurare de tip YAML (aici am folosit metoda declarativă). Orice fișier YAML are 4 componente importante:
Pentru a face deploy la unul (sau mai multe) obiecte dintr-un fișier YAML folosim următoarea comandă: kubectl apply -f myfile.yaml
kubectl create
, kubectl update
, kubectl delete
, dar este indicat sa folositi direct kubectl apply
, care combină create
, replace
și delete
. Aceasta reprezintă cel mai avansat model de aplicare a unei configurații declarative.
kubectl apply
se poate da și pe un folder care conține fișiere YAML sau pe un URL care point-ează către un fișier YAML
Putem crea pod-uri și folosind metoda declarativă, mai precis prin fișiere de configurare. Creăm un fișier de configurare, cu numele nginxpod.yaml
:
apiVersion: v1 kind: Pod metadata: name: nginx01 # numele pod-ului spec: containers: - image: nginx name: nginx
Pentru a crea acest pod, folosim comanda apply și specificăm fișierul: kubectl apply -f nginxpod.yaml
. Se obține un pod cu numele nginx01
.
De asemenea, în lucrul cu pods putem face următoarele lucruri:
kubectl port-forward <nume-pod> 8888:5000 # realizeaza mapare de porturi kubectl logs <nume-pod> # afiseaza loguri kubectl exec <nume-pod> -- ls # executa o comanda intr-un pod kubectl cp file.txt <nume-pod>:/file.txt # copiaza un fisier intr-un pod kubectl delete pods/<nume-pod> # sterge un pod
Fișierele YAML pot fi scrise de la 0 sau pot fi generate prin rularea uscată a pod-urilor.
#Exemplu oficial de fisier YAML apiVersion: v1 kind: Pod metadata: name: nginx labels: run: nginx whatever: dude spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
Pentru a genera fișiere YAML plecând de la o comandă imperativă putem folosi flag-urile –dry-run=client -o yaml
. Exemplu: kubectl run nginx - -image=nginx - -dry-run=client -o yaml
În fișierul YAML generat de comanda anterioară, putem observa că în câmpul metadata
, pe lângă atributul name
, avem și atributul labels
:
metadata: creationTimestamp: null labels: run: nginx name: nginx
Aceste labels sunt perechi de tipul cheie-valoare care sunt folosite pentru identificarea obiectelor din Kubernetes. În exemplul de mai sus, avem perechea run=nginx
. Această pereche poate fi folosită de către un label selector pentru a referi acest obiect (mai multe detalii în continuare).
Spre deosebire de nume, label-urile nu asigură unicitate. În general, ne așteptăm ca mai multe obiecte să aibă aceleași label-uri.
Asa cum am spus anterior, cu ajutorul unor Label Selectors putem identifica numite seturi de obiecte în Kubernetes. Un exemplu relevant este expunerea unui pod printr-un serviciu.
Un exemplu comun de utilizare a labels și labels selectors prin intermediul fișierelor de configurare YAML este următorul:
kubectl run nginx –image=nginx –port=8080 –dry-run=client -o yaml >vtest.yaml
Adăugați podului următorul label:
app: myapp
Creați pod-ul:
kubectl apply -f test.yaml. kubectl describe pod nginx # analizate label-urile podului.
Pentru a expune acest pod trebuie creat un serviciu de tipul ClusterIP care să selecteze podul nostru prin intermediul label selectors. Un fișier de configurare YAML pentru acest serviciu este următorul:
apiVersion: v1 kind: Service metadata: creationTimestamp: null name: nginx spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: myapp #select the pod/pods status: loadBalancer: {}
Observați că nu am definit tipul de serviciu, astfel Kubernetes a creat by default un serviciu de tipul ClusterIP. Verificați faptul că podul nginx este expus.
Un ReplicaSet are rolul de a menține un număr stabil de replici ale unui pod. Acest obiect este definit prin anumite câmpuri, ca de exemplu un label selector care specifică modul în care pot fi controlate pod-urile, un număr de replici care indică numarul de pod-uri pe care le vrem up and running și un template al pod-urile pe care le orchestrează.
Exemplu de ReplicaSet:
apiVersion: apps/v1 kind: ReplicaSet metadata: name: nume spec: replicas: 4 # numărul de replici ale pod-ului selector: matchLabels: app: containerlabel template: metadata: name: pod-template labels: app: containerlabel spec: containers: - name: container image: nginx
Pentru detalii legate de ReplicaSets putem folosi următoarele comenzi:
kubectl apply -f testapp-rs.yaml # creează un ReplicaSet dintr-un fisier kubectl get replicasets # afișează lista de ReplicaSet-uri kubectl describe rs <nume-replicaset> # afișează detalii despre un ReplicaSet kubectl delete rs <nume-replicaset> # sterge un ReplicaSet
Un ReplicaSet poate fi scalat prin două moduri:
kubectl scale replicasets <nume-replicaset> –replicas=4
Un deployment ne dă opțiunea declarativă de a updata pod-uri și ReplicaSets. Într-un deployment descriem starea dorită, apoi un Deployment Controller are grijă ca clusterul să ajungă în starea descrisă. Putem folosi deployment-uri pentru a crea noi ReplicaSets sau chiar pentru a șterge un deployment existent și a adopta toate resursele sale.
Exemplu de deployment (varianta declarativă):
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
kubectl get pods
.kubectl get rs # am folosit un shortcut aici
kubectl get deploy
Un ConfigMap este un obiect folosit pentru a stoca într-un format de tipul cheie-valoare date care nu sunt sensitive. Un pod poate consuma un ConfigMap ca o variabilă de mediu, ca un argument în linie de comandă sau ca un fișier de configurare într-un volum. Un astfel de obiect oferă opțiunea de a decupla configurația specifica unui mediu de imaginile de container și de codul aplicației, ceea ce sporește portabilitatea aplicațiilor.
Un exemplu simplu este separarea mediilor. Pentru development, o să folosim calculatorul local, iar pentru producție o să folosim un provider de cloud. Configurăm codul astfel încât acesta se conectează la o bază de date folosind o variabilă de mediu, de ex DATABASE_HOST
. Pe mediul local o să setăm variabila de mediu la localhost (presupunând că avem un server de bază de date pe localhost), iar în cloud o să setăm variabila la un serviciu de Kubernetes prin care este expusă o bază de date (o să învățăm despre servicii în următorul laborator).
Un obiect de tipul ConfigMap nu este folosit pentru a stoca cantități mari de date. Pentru o dimensiune mai mare de 1MB se vor folosi volume (despre care învățăm în laboratorul următor).
Fișier pentru configurarea unui ConfigMap:
apiVersion: v1 kind: ConfigMap metadata: name: game-demo data: # property-like keys; each key maps to a simple value player_initial_lives: "3"
kubectl apply -f <configmapfile>
kubectl get configmap
Un ConfigMap poate fi folosit într-un pod în mai multe moduri, nu doar ca în exemplul de mai sus, într-o variabilă de mediu. Mai există și opțiunea de a folosi un ConfigMap într-un volum (cum înca nu știm să lucrăm cu volume, o să învățăm în laboratorul următor).
Fișier pentru configurarea unui pod folosind ConfigMap (în acest exemplu folosind ConfigMap-ul definit anterior):
apiVersion: v1 kind: Pod metadata: name: configmap-demo-pod spec: containers: - name: demo image: alpine command: ["sleep", "3600"] env: # Define the environment variable - name: PLAYER_INITIAL_LIVES # Notice that the case is different here # from the key name in the ConfigMap. valueFrom: configMapKeyRef: name: game-demo # The ConfigMap this value comes from. key: player_initial_lives # The key to fetch.
S-a creat în interiorul pod-ului o variabilă de mediu numită PLAYER_INITIAL_LIVES
care o să își ia valoarea din cheia player_initial_lives
al ConfigMap-ului nostru.