This shows you the differences between two versions of the page.
cc:laboratoare:04 [2021/11/09 14:12] radu.ciobanu [Exemplu Comenzi] |
cc:laboratoare:04 [2022/10/30 19:29] (current) florin.mihalache |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 04 - Introducere in Kubernetes ===== | + | ====== Laboratorul 04 - Terraform ====== |
+ | ===== Ce este Terraform? ===== | ||
+ | [[https://developer.hashicorp.com/terraform | Terraform]] reprezintă un instrument open-source folosit pentru Infrastructure as Code, dezvoltat de HashiCorp, prin care, mai exact, se automatizează procese de infrastructură / devops. | ||
- | ==== Introducere ==== | + | Un use-case principal al Terraform îl reprezintă conectarea la cloud providers, precum Google Cloud Platform (GCP) și Amazon Web Services (AWS), și gestionarea resurselor oferite de către cloud providers. |
- | Kubernetes (prescurtat K8s) este cel mai popular orchestrator, folosit la scara larga si oferit ca si CaaS (Container as a Service) de toti vendorii de infrastructura (Amazon, Google, Microsoft). Este considerat **standard** in materie de deployment al serviciilor orchestrate. | ||
- | Varianta originala este dezvoltata de Google, este open source, si face parte din Cloud Native Foundation (CNF). Fiecare vendor adauga pachete in plus, pentru a il adapta la ecosistemul proprietar (de exemplu, Azure adauga comenzi si straturi in plus peste varianta de baza). | + | ===== Instalare Terraform ===== |
+ | Folosim site-ul oficial al Terraform pentru a instala tool-ul. Găsiți toate detaliile necesare aici: https://www.terraform.io/downloads | ||
- | Este mai complicat decat Docker Swarm, dar in multe situatii nu veti fi nevoiti sa rulati propriul vostru cluster de K8s, ci doar sa rulati aplicatii peste un cluster de kubernetes gata oferit (de exemplu, Azure Kubernetes Service (AKS)). | + | Pentru a instala Terraform pe o mașinp cu un sistem de operare Ubuntu / Debian, folosim următoarele comenzi: |
- | + | <code bash> | |
- | Avantajul **major** asupra Docker Swarm il ofera utilizarea sa in industrie, cat si faptul ca este mai flexibil si ofera mai multe functionalitati, insa nu out of the box. Faptul ca este customizabil implica, bineinteles, si un factor de dificultate mai mare. Kubernetes este mai greu de invatat decat Swarm, dar are si mai multe capabilitati. | + | wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg |
- | + | echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list | |
- | <note tip>[[https://kubernetes.io/partners/#conformance|Aici]] puteti vedea toti partenerii Kubernetes</note> | + | sudo apt update && sudo apt install terraform |
- | + | </code> | |
- | ==== Instalare ==== | + | |
- | + | ||
- | Kubernetes se poate seta in multe moduri: | + | |
- | + | ||
- | === Bootstrap la propriul cluster === | + | |
- | + | ||
- | Este metoda cea mai dificila, in care se leaga mai multe masini in retea folosind [[https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/|Kubeadm]]. Se foloseste pentru a crea un cluster de la 0 si necesita un nivel de cunostinte mediu-avansat. | + | |
- | + | ||
- | === Folosirea unui cluster deja setat === | + | |
- | + | ||
- | Asa cum am precizat in introducere, sunt putine cazurile cand veti trebui sa setati un cluster de la 0, deoarece vendorii principali de infrastructura au versiunile lor de Kubernetes si sistemele de CaaS deja pregatite. | + | |
- | + | ||
- | === Instalare locala === | + | |
- | + | ||
- | Cea mai buna metoda de a invata este sa va setati local un cluster cu un singur nod de kubernetes. Acest lucru se poate face in mai multe moduri: | + | |
- | * Pentru utilizatorii Windows PRO care au si Docker instalat, Kubernetes vine preinstalat | + | |
- | * Pentru utilizatorii Windows Non-Pro se foloseste [[https://minikube.sigs.k8s.io/docs/start/|Minikube]] | + | |
- | * Pentru utilizatorii Linux, se foloseste [[https://microk8s.io/|MicroK8s]] | + | |
- | + | ||
- | ==== Arhitectura Kubernetes ==== | + | |
- | + | ||
- | {{:cc:laboratoare:kubernetesarhitecture.png?800|}} | + | |
- | + | ||
- | Precum Docker Swarm, Kubernetes este un sistem format din mai multe [[https://kubernetes.io/docs/concepts/overview/components/#master-components|componente]]: | + | |
- | - **Kubectl** - CLI pentru configurarea clusterului si managementului aplicatiilor. Asemanator cu comanda //docker// | + | |
- | - **Node** - nodul fizic din cadrul unui cluster | + | |
- | - **Kubelet** - agentul (daemon) de Kubernetes care ruleaza pe fiecare nod | + | |
- | - **Control Plane** - colectia de noduri care fac management la cluster. Include API Server, Scheduler, Controller Manager, CoreDNS, Etcd. Asemanator cu nodurile "master" din Docker Swarm. | + | |
- | + | ||
- | {{:cc:laboratoare:controlplane.png?800|}} | + | |
- | + | ||
- | ==== Componentele unei aplicatii Kubernetes ==== | + | |
- | + | ||
- | La fel ca in cadrul Docker Swarm, Kubernetes foloseste o ierarhie logica de componente pentru aplicatii: | + | |
- | + | ||
- | * **Pod** - unitatea fundamentala de lucru. Un pod contine intotdeauna containere. | + | |
- | * **Controllere** - creaza, actualizeaza si mentine starea de rulare a pod-urilor. Echivalentul unui serviciu din docker swarm. | + | |
- | <note tip>Exemple de controllere: **Deployment**, ReplicaSet, StatefulSet, DaemonSet, Job, CronJob</note> | + | |
- | * **Service** - endpoint de conectare in retea. Se ataseaza unui pod. Echivalentul configuratiei de retea din docker swarm. | + | |
- | <note tip>Tipurile de services sunt: NodePort, ClusterIP si LoadBalancer.</note> | + | |
- | * **Storage** - obiecte care se ocupa de persistarea datelor. PersistentVolume (PV) si PersistentVolumeClaim (PVC). Asemanator cu docker mounts. | + | |
- | <note tip>Datorita PV si PVC, in kubernetes se poate realiza persistarea datelor chiar si intre mai multe noduri. In cadrul Docker Swarm eram limitati la utilizarea unui NFS extern.</note> | + | |
- | * **Namespace** - grup de obiecte intr-un cluster. Asemanator cu stack din docker swarm | + | Pentru a verifica dacă instalarea fost efectuată cu succes, încercăm să obținem versiunea de Terraform instalată: ''terraform -version'' |
- | * **Configurations** - obiecte de configuratie. Exemple de obiecte de configuratie: Secrets, ConfigMaps | + | === Terraform autocomplete === |
+ | Pentru a putea utiliza funcția de autocomplete cu Terraform: ''terraform -install-autocomplete'' | ||
- | ==== Exemplu Comenzi ==== | + | ===== Terraform + Docker ===== |
+ | În laboratorul curent o să folosim Terraform împreună cu Docker, cu care suntem deja familiari. Începem prin a crea un director nou pentru configuratia noastră: | ||
<code bash> | <code bash> | ||
+ | mkdir lab4cc | ||
+ | cd lab4cc | ||
+ | </code> | ||
- | ## Kubernetes Local Install | + | Creăm un fișier cu numele ''main.tf'' și introducem următorul cod: |
+ | <code terraform> | ||
+ | terraform { | ||
+ | required_providers { | ||
+ | docker = { | ||
+ | source = "kreuzwerker/docker" | ||
+ | version = "~> 2.13.0" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | provider "docker" {} | ||
+ | |||
+ | resource "docker_image" "nginx" { | ||
+ | name = "nginx:latest" | ||
+ | keep_locally = false | ||
+ | } | ||
+ | |||
+ | resource "docker_container" "nginx" { | ||
+ | image = docker_image.nginx.latest | ||
+ | name = "tutorial" | ||
+ | ports { | ||
+ | internal = 80 | ||
+ | external = 8000 | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
- | ### minikube | ||
- | minikube start | + | Să analizăm pe rând fiecare bloc de cod introdus: |
+ | * ''terraform {}'' - conține setarile de Terraform, inclusiv provider-ul pe care urmează să îl folosim. Pentru fiecare provider, câmpul ''source'' definește numele provider-ului. By default, Terraform folosește Terraform Registry pentru a instala un provider. Astfel, în exemplul nostru, ''kreuzwerker/docker'' este un provider care se găsește în registrul Terraform la path-ul ''registry.terraform.io/kreuzwerker/docker''. Câmpul ''version'' este opțional, dacă nu îl folosim, Terraform o să descarce by default ultima versiune disponibilă. | ||
+ | * ''provider {}'' - un block de tipul provider conține configurările necesare pentru ca acel provider să poată fi folosit. În cazul nostru, am folosit ''docker''. Un provider este doar un plugin pe care Terraform îl folosește pentru a crea și pentru a gestiona resursele. | ||
+ | * Blocurile de tip resource - un astfel de bloc, așa cum sugerează și numele, este folosit pentru a defini resurse ale infrastructurii noastre. Așa cum putem observa, un bloc de tip resursă are 2 labels: ''resource "docker_image" "nginx"''. În acest exemplu, ''docker_image'' este tipul de resursă, iar ''nginx'' este numele resursei. Fiecare astfel de bloc are mai multe proprietăți, acestea diferă de la resursă la resursă. Exemplu: în laboratorul viitor o sa configurăm o mașină virtuală într-un provider de cloud unde o să folosim parametrii ca tipul de masină, hard disk, dimensiune hard disk, regiunea în care să fie deployed masina, etc. | ||
- | ### microk8s | + | Recapitulare cod: |
+ | - Am populat block-ul ''terraform'' cu config-ul unde am specificat providerul ''docker'' și versiunea dorită. | ||
+ | - Am inițializat providerul ''docker''. | ||
+ | - Am creat o resursă de tipul ''docker_image'' cu numele ''nginx'' (numele variabilei). | ||
+ | - Am creat o resursă de tipul ''docker_container'' cu numele ''nginx''. În această resursă, pentru imagine am folosit imaginea definită mai sus, iar numele container-ului este dat de câmpul ''name''. | ||
- | microk8s.kubectl | + | Pentru a pune in picioare infrastructura: |
+ | - Initializare: ''terraform init''. Urmăriți output-ul comenzii pentru a înțelege ce face această comandă. | ||
+ | - Formatarea codului. Acest pas este opțional, dar foarte util: ''terraform fmt'' | ||
+ | - Validarea configurării (și acest pas este optional, în cazul în care mergem mai departe cu o configurare invalidă, o să primim eroare): ''terraform validate'' | ||
+ | - Rulăm comanda ''terraform plan''. Această comandă este un dry-run, deci putem observa cum o să arate infrastructura noastră după ce o să aplicăm configurarea creată anterior. **Atenție**, această comandă nu modifică infrastructura. | ||
+ | - Aplicăm configurația: ''terraform apply'' | ||
- | microk8s.enable dns | + | <note tip> |
+ | Task: urmati instrucțiunile din shell-ul interactiv și faceți deploy la infrastructură. Observați output-ul comenzii. | ||
- | alias kubectl=microk8s.kubectl | + | Pentru a observa state-ul: ''terraform show'' |
+ | </note> | ||
- | ## Kubectl run, create and apply | + | <note tip> |
+ | Task: modificarea unei infrastructuri existente - modificati fișierul anterior, astfel încât container-ul să folosească portul 8080, nu 8000 | ||
- | kubectl run | + | Rulați comanda pentru a vedea planul. Modificarea este facută in-place? |
- | kubectl create | + | Ștergere infrastructură - rulați comanda ''terraform destroy'' |
+ | </note> | ||
- | kubectl apply | + | ===== Variabile în Terraform ===== |
+ | Avem următorul fișier'' outputs.tf'', unde avem acest bloc: | ||
+ | <code terraform> | ||
+ | output "Lab" { | ||
+ | value="lab4 first output" | ||
+ | } | ||
+ | </code> | ||
- | ## Pornirea unui Pod | + | Am creat primul output în Terraform. Pentru a observa comportamentul, urmați pașii din exercițiul anterior pentru a "aplica" infrastructura. |
- | kubectl version | + | Avem acest bloc cu următorul cod: |
+ | <code terraform> | ||
+ | variable "LabCCTerraform" { | ||
+ | description = "primul lab in terraform" | ||
+ | default = "valoare default a primului lab in terraform" | ||
+ | } | ||
+ | </code> | ||
+ | Aplicați planul și observați comportamentul. | ||
- | kubectl run my-nginx --image nginx | + | ==== Prioritatea variabilelor ==== |
+ | Un alt mod de a seta variabile în Terraform este prin variabile de mediu. By default, Terraform caută variabilele de mediu care încep cu ''F_VAR_''. De exemplu, o variabilă de mediu cu numele ''TF_VAR_MYTESTVAR=myvalue'' o să atribuie valoarea myvalue unei variabile cu numele ''MYTESTVAR''. Variabila cu numele ''MYTESTVAR'' trebuie sa fie totuși declarată in configurația noastră de Terraform. | ||
- | kubectl get pods | + | <note tip> |
+ | Task: | ||
+ | * Creați o variabilă de mediu care sa suprascrie variabilă folosită de noi: ''export TF_VAR_LabCCTerraform="Value from environment"'' | ||
+ | * Rulați din nou comanda ''terraform apply'' pentru a observa comportamentul. | ||
+ | </note> | ||
- | kubectl get all | + | ==== Fișiere tfvars ==== |
+ | <note tip> | ||
+ | Task: | ||
+ | * Creați un nou fișier cu numele terraform.tfvars si adăugați următoarea linie de cod: ''LabCCTerraform="Value from tfvars file"''. Acest fișier, deși are extensia diferită față de cele anterioare foloseste exact aceeași sintaxă. | ||
+ | * Folosiți din nou comanda terraform apply pentru a observa comportamentul. | ||
+ | </note> | ||
- | kubectl delete deployment my-nginx | + | ==== Injectare variabile din linia de comandă ==== |
+ | Un alt mod prin care putem atribui o valoare unei variabile este prin linia de comandă. | ||
- | kubectl get all | + | Rulați următoarea comandă: ''terraform apply -var LabCCTerraform=valueFromCommandLine'' |
- | ## Scalarea unui Pod (se foloseste de ReplicaSet) | + | In urma acestui exercițiu, am aflat ca ordinea de prioritizare a variabilelor este următoarea: |
+ | - linie de comandă | ||
+ | - fișier tfvars | ||
+ | - varibila de mediu | ||
+ | - valoarea default | ||
- | kubectl run my-apache --image httpd | + | ==== Tipuri de variabile ==== |
+ | Un alt tip de variabilă pe care îl putem folosi este lista: | ||
+ | <code terraform> | ||
+ | variable "mylist" { | ||
+ | default = ["ana", "are", "mere"] | ||
+ | } | ||
+ | </code> | ||
+ | Pentru a accesa un element dintr-o listă avem 2 variante. | ||
+ | * folosind o funcție: | ||
+ | <code terraform> | ||
+ | output "getelement" { | ||
+ | value = element(var.mylist,1) | ||
+ | } | ||
+ | </code> | ||
+ | * folosind accesare direct cu indexul: | ||
+ | <code terraform> | ||
+ | output "useindex" { | ||
+ | value = var.mylist[1] | ||
+ | } | ||
+ | </code> | ||
- | kubectl get all | + | Liste nested: |
+ | <code terraform> | ||
+ | variable "nestedlist" { | ||
+ | type = list | ||
+ | default = [ | ||
+ | ["item1", "item2"], | ||
+ | ["item3", "item4"] | ||
+ | ] | ||
+ | } | ||
+ | </code> | ||
+ | Pentru a accesa elementele dintr-o listă nested, folosim sintaxa asemănătoare: | ||
+ | <code terraform> | ||
+ | output "nestedlist" { | ||
+ | value = var.nestedlist[1][1] | ||
+ | } | ||
+ | </code> | ||
- | kubectl scale deploy/my-apache --replicas2 | + | Maps: |
+ | <code terraform> | ||
+ | variable mymap { | ||
+ | default = { | ||
+ | us = "United States" | ||
+ | eu = "Europe" | ||
+ | apac = "Asia/Pacific" | ||
+ | } | ||
+ | } | ||
+ | output "my_region_map" { | ||
+ | value = var.mymap | ||
+ | } | ||
+ | </code> | ||
- | kubectl scale deployment my-apache --replicas2 | + | Pentru a accesa elementele dintr-un map, folosim functia lookup, mai multe detalii gasiți în link-ul: https://developer.hashicorp.com/terraform/language/functions/lookup |
+ | <code terraform> | ||
+ | output "oneMapElement" { | ||
+ | value = lookup(var.mymap, "us") | ||
+ | } | ||
+ | </code> | ||
+ | ==== Organizarea codului Terraform ==== | ||
+ | Având în vedere că deja devine greu de urmărit codul nostru, avem nevoie de o refactorizare. | ||
- | kubectl get all | + | Best practices Terraform recomandă să avem fișiere separate pentru variabile și outputs. Simplu spus, toate variabilele stau într-un fișier ''variables.tf'', toate output-urile stau într-un fișier ''outputs.tf''. |
- | + | ||
- | ## Inspectarea obiectelor Kubernetes | + | |
- | + | ||
- | kubectl get pods | + | |
- | + | ||
- | kubectl logs deployment/my-apache | + | |
- | + | ||
- | kubectl logs deployment/my-apache --follow --tail 1 | + | |
- | + | ||
- | kubectl logs -l run=my-apache | + | |
- | + | ||
- | kubectl get pods | + | |
- | + | ||
- | kubectl describe pod/my-apache-<pod id> | + | |
- | + | ||
- | kubectl get pods -w | + | |
- | + | ||
- | kubectl delete pod/my-apache-<pod id> | + | |
- | + | ||
- | kubectl get pods | + | |
- | + | ||
- | kubectl delete deployment my-apache | + | |
- | </code> | + | |
- | Gasiti cateva exemple de fisiere declarative in [[https://gitlab.com/mobylab-cc/laborator-4|repository-ul laboratorului]]. |