Differences

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

Link to this comparison view

cc:laboratoare:02 [2020/10/19 08:25]
radu.ciobanu
cc:laboratoare:02 [2022/10/15 20:16] (current)
florin.mihalache
Line 1: Line 1:
-===== Laboratorul 02 - Elemente adiționale ​în Docker ​=====+====== Laboratorul 02 - Introducere ​în Kubernetes ======
  
-==== Publicarea unei imagini într-un registru ​====+==== Despre Kubernetes ​====
  
-În [[cc:​laboratoare:​01|laboratorul 1]], am creat o imagine de Docker pe care am rulat-o local într-un container. Pentru a putea rula imaginea creată în orice alt sistem, ​este necesar să o publicămdeci să o urcăm într-un registru pentru ​putea să facem deploy ​de containere cu imaginea noastră în producție. Un registru este o colecție de repository-uri,​ iar un repository este o colecție de imagini (similar cu GitHub, cu diferența că, într-un registru Docker, codul este deja construit șse rețin modificările făcute în straturile imaginilor ​de Docker, nu în cod). Există numeroase registre pentru imagini Docker ​(Docker HubGitlab Registryetc.), iar la laborator vom folosi registrul public Docker, pentru că este gratuit și pre-configurat.+Kubernetes (prescurtat K8s) este cel mai popular orchestratorfolosit la scara largă și oferit ca și CaaS (Container as Service) ​de toți vendorii ​de infrastructură (AmazonGoogleMicrosoft)Este considerat standard în materie de deployment al serviciilor orchestrate.
  
-Pentru exemplificare,​ vom porni de la aplicația prezentată în laboratorul 1care afișează o poză aleatoare într-o pagină Web și pe care o puteți găsi în {{:​cc:​laboratoare:​lab1.zip|această arhivă}}. Primul pas în publicarea unei imagini este crearea unui cont la [[https://​hub.docker.com]]. Mai departelogarea ​în registru ​de pe mașina locală se realizează prin următoarea comandă:+Varianta originală este dezvoltată ​de Googleeste open source ​și face parte din Cloud Native Foundation (CNF)Fiecare vendor adaugă pachete ​în plus, pentru a îl adapta ​la ecosistemul proprietar (de exempluAzure adaugă comenzi și straturi ​în plus peste varianta ​de baza).
  
-<code bash> +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)).
-$ docker login+
  
-Login with your Docker ​ID to push and pull images from Docker HubIf you don't have a Docker IDhead over to https://hub.docker.com to create one. +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 boxFaptul că este customizabil implicăbineînțeles,​ și un factor de dificultate mai mareKubernetes este mai greu de învățat decât Swarm, dar are și mai multe capabilități.
-Username:  +
-Password:  +
-Login Succeeded +
-</​code>​+
  
-Putem specifica numele de utilizator și parola direct în comandă, iar varianta generică a acesteia este (unde serverul implicit, dacă alegem să omitem acel parametru, este Docker Hub):+==== Instalare ====
  
-<code bash> +Kubernetes se poate seta în multe moduri:
-$ docker login [–u <​UTILIZATOR>​ –p <​PAROLĂ>​] [SERVER] +
-</​code>​+
  
-Înainte de a publica imaginea în registru, ea trebuie tag-uită după formatul **//​username/​repository:​tag//​**. Tag-ul este opțional, dar este util pentru că denotă versiunea unei imagini Docker. Se folosește următoarea comandă pentru tag-uirea unei imagini (în exemplul de mai jos, unde vrem să tag-uim imaginea pe care am creat-o în laboratorul anterior, utilizatorul se numește **//​raduioanciobanu//​**,​ repository-ul este **//​cloudcomputing//​**,​ iar tag-ul este **//​example//​**):​+=== Bootstrap la propriul cluster ===
  
-<code bash> +Este metoda cea mai dificilă, în care se leagă mai multe mașini în rețea folosind [[https://​kubernetes.io/​docs/​setup/​production-environment/​tools/​kubeadm/​create-cluster-kubeadm/​|Kubeadm]]. Se folosește pentru a crea un cluster de la 0 și necesită un nivel de cunoștințe mediu-avansat.
-$ docker tag testapp raduioanciobanu/​cloudcomputing:example +
-</code>+
  
-<code bash> +=== Folosirea unui cluster deja setat ===
-$ docker images +
-REPOSITORY ​                      ​TAG ​                IMAGE ID            CREATED ​             SIZE +
-testapp ​                         latest ​             74254b15e6ba ​       About a minute ago   ​62.9MB +
-raduioanciobanu/​cloudcomputing ​  ​example ​            ​74254b15e6ba ​       About a minute ago   ​62.9MB +
-alpine ​                          ​edge ​               f96c4363411f ​       4 weeks ago          5.58MB +
-</​code>​+
  
-Odată tag-uită imagineaea poate fi publicată în registru:+Asa cum am precizat în introducere,​ sunt puține cazurile cand veți trebui să setați un cluster de la 0deoarece vendorii principali de infrastructură au versiunile lor de Kubernetes și sistemele de CaaS deja pregătite.
  
-<code bash> +=== Instalare locală ===
-$ docker push raduioanciobanu/​cloudcomputing:​example +
-</​code>​+
  
-Din acest moment, imaginea va fi vizibilă pe [[https://hub.docker.com]], de unde poate fi descărcată ​și rulată pe orice mașină, server sau sistem Cloud:+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: 
 +  * Pentru utilizatorii Windows PRO care au și Docker instalat, Kubernetes vine preinstalat 
 +  * Pentru utilizatorii Windows Non-Pro se folosește ​[[https://minikube.sigs.k8s.io/​docs/​start/​|Minikube]] 
 +  * Pentru utilizatorii Linuxse folosește [[https://​microk8s.io/​|MicroK8s]]
  
-<code bash> +==== Arhitectura Kubernetes ====
-$ docker run -p 8888:5000 raduioanciobanu/​cloudcomputing:​example+
  
-Unable to find image '​raduioanciobanu/​cloudcomputing:example'​ locally +{{:cc:laboratoare:kubernetesarhitecture.png?800|}}
-examplePulling from raduioanciobanu/​cloudcomputing +
-cc5efb633992Pull complete  +
-cd0af7ebab8a:​ Pull complete  +
-41c55a3da379:​ Pull complete  +
-a779b27637f8:​ Pull complete  +
-dfaeccf28d0c:​ Pull complete  +
-805843c75452:​ Pull complete  +
-Digest: sha256:​25af18fb4ffa9bf439e90bd4baee9adf0ab1e2999a44aeaa216ebf0454201ce8 +
-Status: Downloaded newer image for raduioanciobanu/​cloudcomputing:​example +
- * Running on http://​0.0.0.0:​5000/​ (Press CTRL+C to quit) +
-[...+
-</​code>​+
  
-Alternativîn loc să rulăm comanda de publicare a unei imagini de fiecare dată când modificăm ceva la codul sursă, putem să configurăm ​[[https://docs.docker.com/docker-hub/builds/|build-uri automate]] din contul de Docker Hub. Pașii necesari sunt descriși în continuare. +Precum Docker SwarmKubernetes este un sistem format din mai multe [[https://kubernetes.io/docs/​concepts/​overview/components/#​master-components|componente]]: 
-În primul rând, este necesară existența unui repository Docker Hub și a unui repository pe GitHub (Docker Hub funcționează și cu BitBucket, dar în acest exemplu ne vom concentra pe GitHub)Toate fișierele necesare creării unei imagini Docker (adică Dockerfile-ul și toate fișierele sursă și de configurare) trebuie să fie prezente în repository-ul GitHub. Mai departe, de pe pagina repository-ului de Docker Hubse selectează tab-ul Builds și apoi opțiunea „Configure Automated Builds”, așa cum se poate observa în imaginea de mai jos.+  - **Kubectl** - CLI pentru configurarea clusterului ​și managementului aplicațiilorAsemănător cu comanda //​docker//​ 
 +  ​**Node** - nodul fizic din cadrul unui cluster 
 +  - **Kubelet** - agentul (daemon) ​de Kubernetes care rulează pe fiecare nod 
 +  ​**Control Plane** - colecția ​de noduri care fac management la cluster. Include API Server, SchedulerController Manager, CoreDNS, Etcd. Asemănător cu nodurile "​master"​ din Docker Swarm.
  
-{{:​cc:​laboratoare:​dockerhub.png?direct&​600|}}+{{:​cc:​laboratoare:​controlplane.png?800|}}
  
-În continuare, va fi necesară completarea unor informații despre repository-ul GitHub și opțiuni de testare automată înainte de build, după care trebuie specificate regulile de build. O regulă de build conține informații despre: tipul build-ului (bazat pe un branch sau pe un tag Git), sursa (numele branch-ului sau tag-ului de pe care se face build-ul), tag-ul care va fi asignat noii imagini Docker construite, numele și adresa fișierului Dockerfile în repository-ul GitHub, calea către sursele ce vor fi compilate, opțiuni de auto-build (dacă se va face build automat la fiecare push pe branch-ul sau cu tag-ul specificat),​ opțiuni de build caching (dacă se vor cache-ui fișiere la build în cazul unor repository-uri de dimensiuni mari). În exemplul de mai jos, atunci când are loc un push pe branch-ul **//​master//​**,​ se va crea automat o imagine Docker cu tag-ul **//​latest//​** folosindu-se fișierul Dockerfile aflat în rădăcina repository-ului de GitHub.+==== Componentele unei aplicații Kubernetes ====
  
-{{:cc:​laboratoare:​dockerhub2.png?​direct&​500|}}+Kubernetes folosește o ierarhie logică de componente pentru aplicații:
  
-În continuarepe pagina de Builds ​de pe Docker ​Hub vor exista opțiuni pentru pornirea ​unui nou buildprecum ​și informații despre build-urile precedente ​și statusurile lor.+  * **Pod** - unitatea fundamentală de lucru. Un pod conține întotdeauna containere. 
 +  * **Controllere** - creeazăactualizează și menține 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 în rețea. Se atașeaza ​unui pod. Echivalentul configurației de rețea din Docker Swarm. 
 +<note tip>​Tipurile de services sunt: NodePortClusterIP ​și LoadBalancer.</​note>​ 
 +  * **Storage** ​obiecte care se ocupă de persistarea datelor. PersistentVolume (PV) și PersistentVolumeClaim (PVC). Asemanător cu Docker mounts. 
 +<note tip>​Datorită PV și PVC, în Kubernetes se poate realiza persistarea datelor chiar și între mai multe noduri. În cadrul Docker Swarm eram limitați la utilizarea unui NFS extern.</​note>​
  
-==== Networking ====+  * **Namespace** - grup de obiecte într-un cluster. Asemanător cu stack din Docker Swarm
  
-Subsistemul de networking Docker este de tip pluggable și folosește drivere. Mai multe astfel de drivere există implicit, ele oferind funcționalitate de bază pentru componenta de rețea. Driverul de rețea implicit este **bridge**, și presupune crearea unui bridge software care permite containerelor conectate la aceeași rețea ​de acest tip să comunice între ele, oferind totodată izolare față de containerele care nu sunt conectate la această rețea bridgeDriverul ​de bridge Docker instalează automat reguli pe mașina gazdă astfel încât containerele ​de pe rețele bridge diferite nu pot comunica direct unele cu altele. Rețelele de tip bridge se aplică doar containerelor care rulează pe aceeași mașină Docker.+  ​* **Configurations** - obiecte ​de configurațieExemple ​de obiecte ​de configurație: Secrets, ConfigMaps
  
-Pentru comunicație între containere care rulează pe mașini ​Docker diferite, se poate gestiona rutarea la nivel de sistem de operaresau se poate folosi o rețea de tip **overlay**. Așa cum se va detalia în [[cc:​laboratoare:​03|laboratorul 3]]rețelele de tip overlay conectează mai multe mașini Docker șpermit serviciilor dintr-un swarm să comunice între ele. Rețelele overlay se mai pot folosi șpentru a facilita comunicația între un serviciu swarm șun container ​de sine stătător, sau între două containere care rulează pe mașini Docker diferite.+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 Computingacesta ​poate fi folosit (nu este obligatoriuputeți să alegeți ce doriți). Instrucțiuni legate ​de setup-ul MicroK8s le aveți [[https://​microk8s.io/​docs/​getting-started|aici]].
  
-Alte drivere de rețea Docker mai sunt **host** (pentru containere de sine stătătoare,​ eliminând izolarea de rețea dintre container ​și gazda Docker, folosindu-se astfel infrastructura de rețea a gazdei direct), **macvlan** (permite asignarea de adrese MAC unui container, făcându-l să apară ca un dispozitiv fizic pe rețea), sau **none**.+==== Crearea ​și rularea ​unui cluster Kubernetes ====
  
-Containerele din aceeași rețea pot comunica fără să expună porturi, prin intermediul **named DNS**. Acest lucru înseamnă că putem să accesam un container nu prin IP, ci prin numele său. Pentru comunicarea cu lumea exterioară (gazda, containere din afara rețelei, etc.) trebuie expuse porturi.+Pentru pornirea unui cluster de Kubernetes pe local se poate folosi următoarea comandă: ''​minikube start''​.
  
-Pentru a demonstra modul în care funcționează rețelele ​de tip bridge în Docker, întâi vom porni două containere ce vor rula AlpineÎn mod implicit, orice container Docker nou-creat se va afla într-o rețea numită „bridge”,​ așa că, pentru ​a demonstra faptul că două containere care nu sunt în aceeași rețea nu pot comunicava trebui întâi să le scoate ​din acea rețea.+O altă modalitate ​de a crea un cluster Kubernetes este folosind ''​kind''​Instrucțiunile de setup pentru ​acest utilitar le aveți [[https://​kind.sigs.k8s.io/​ | aici]]. ''​kind''​ rulează Kubernetes ​în Dockersimulând câte un nod din cluster cu câte un container.
  
-<​code ​bash+Pentru crearea unui cluster folosind ''​kind''​ ne putem folosi de un fișier de configurare:​ 
-$ docker container run --name c1 --it alpine +<​code ​yaml
- +# Configurare de cluster cu trei noduri (dintre care doi workeri) 
-f5a8653a325e8092151614d5a6a80b04b9410ea8b8a5fcfc4028f1ad33239ad9+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
 </​code>​ </​code>​
  
-<code bash> +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.
-$ docker container run --name c2 --it alpine+
  
-b063ad1ef7bd0ae82a7385582415e78938f7df531cef9eefc33e065af09cf92c +Dacă dorim să aflăm informații despre cluster-ul curent folosim următoarea comandă: ''​kubectl cluster-info [dump]''​
-</​code>​+
  
-<code bash> +Pentru a afișa date despre componentele din cluster, folosim comanda ''​kubectl get all''​.
-$ docker network disconnect bridge c1 +
-</​code>​+
  
-<code bash> +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>''​.
-$ docker network disconnect bridge c2 +
-</code>+
  
-<note tip> +Pentru ștergerea cluster-ului în care ne aflăm folosim comanda ''​kind delete cluster''​.
-În comanda de **//docker run//** de mai sus, parametrul **//%%--%%name//** îi dă containerului un nume (sau alias) prin care îl putem referi mai ușor. +
-</​note>​+
  
-În acest moment, containerele **c1** ​și **c2** nu fac parte din nicio rețea. Mai departe, vom încerca să dăm **//​ping//​** dintr-un container în altul.+==== Crearea ​și rularea unui pod Kubernetes ====
  
-<code bash> +Putem crea și rula pod-uri în două maniereimperativă ​(prin comenzi cu parametri) și declarativă (folosind ​fișiere de configurare).
-$ docker exec -it c1 ash +
- +
-/ # ifconfig +
-lo        Link encap:Local Loopback ​  +
-          inet addr:​127.0.0.1 ​ Mask:​255.0.0.0 +
-          UP LOOPBACK RUNNING ​ MTU:​65536 ​ Metric:1 +
-          RX packets:0 errors:0 dropped:0 overruns:0 frame:0 +
-          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 +
-          collisions:​0 txqueuelen:​1000  +
-          RX bytes:​0 ​(0.0 B TX bytes:0 (0.0 B) +
- +
-/ # ping c2 +
-ping: bad address '​c2'​ +
- +
-/ # exit +
-</​code>​ +
- +
-Se poate observa mai sus că **c1** nu are decât o adresă IP loopback ​și că nu poate accesa **c2**. De asemenea, ar fi interesant de menționat faptul că ne-am atașat la container folosind comanda **//docker exec//** rulând un shell (**//​ash//​** este shell-ul ​de pe Alpine). +
- +
-Pentru a crea o rețea de tip bridge în Docker, putem folosi următoarea comandă:+
  
 +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: ​
 <code bash> <code bash>
-$ docker network create ​-d bridge c1-c2-bridge +kubectl run my-nginx --image=nginx 
- +kubectl run alpine --image=alpine
-8644b8accd2a14d10c9911c36635ca6b161449b3aa527db878a727ec1bf980d0+
 </​code>​ </​code>​
  
-Mai departe, putem vizualiza rețele existente astfel:+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''​
  
-<code bash> +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>''​
-$ docker network ls+
  
-NETWORK ID          NAME                DRIVER ​             SCOPE +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>''​
-ecd72738aa59 ​       bridge ​             bridge ​             local +
-8644b8accd2a ​       c1-c2-bridge ​       bridge ​             local +
-615363cafefa ​       host                host                local +
-1e3b8e49b20d ​       none                null                local +
-</code>+
  
-Putem adăuga un container într-o rețea fie atunci când pornim containerul,​ fie atunci când el deja a fost pornit. Pentru cazul de mai susunde **c1** și **c2** erau deja pornite, le putem adăuga în rețea astfel:+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:
 <code bash> <code bash>
-$ docker network connect c1-c2-bridge c1+kubectl exec -it <​podname>​ <​command>​ 
 +kubectl exec -it mypod ls # (mypod trebuie sa existe deja in cluster)
 </​code>​ </​code>​
  
-<code bash+<note
-$ docker network connect c1-c2-bridge c2 +Task: creați un namespace cu numele ''​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. 
-</code>+</note>
  
-Dacă **c1** și **c2** nu ar fi fost deja pornite, le-am fi putut porni deja atașate la rețeaua **c1-c2-bridge** astfel:+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 [[https://​kubernetes.io/​docs/​concepts/​overview/​working-with-objects/​kubernetes-objects/​|componente]] importante
  
-<code bash+  * **apiVersion** - versiunea de comenzi folosită (asemănător cu //version// din Docker Compose / Docker Swarm) 
-$ docker container run --name ​c2 -d -it --network=c1-c2-bridge alpine+<note important>​apiVersion diferă în funcție de kind (exemplu: în cazul deployment-ului este apps/v1, în cazul pod-ului este v1)</​note
 +  * **kind** ​tipul de obiect (e.g.: Pod, Deployment, etc...) 
 +  * **metadata** ​informatii aditionale atasate unui obiect (e.g.: ​name, labels) 
 +  * **spec** ​continutul obiectului (asemanator cu ce se scrie in directiva //service// din docker compose/​docker swarm)
  
-67dde5da9b793de63903ac85ff46574da77f0031df9b49acf44d58062687729c +Pentru a face deploy la unul (sau mai multe) obiecte dintr-un fișier YAML folosim următoarea comandă: ''​kubectl apply -f myfile.yaml''​ 
-</code>+<note tip>​Obiectul va avea tipul definit în YAML (de exemplu: cluster, pod, deployment, etc.)</​note>​ 
 +<note tip>Se pot folosi și comenzile ''​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.</​note>​ 
 +<note tip>''​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</note>
  
-<​code ​bash+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'':​ 
-$ docker container run --name c1 -d -it --network=c1-c2-bridge alpine +<​code ​yaml
- +apiVersion: v1 
-4de3e000700f81d31e0458dbd034abe90dfce6b1b992d23d760a44f748c0de0d+kind: Pod 
 +metadata:  
 +  ​name: nginx01 # numele pod-ului 
 +spec:  
 +  ​containers:​  
 +    - image: nginx 
 +      name: nginx
 </​code>​ </​code>​
  
-Putem vedea containerele dintr-o rețea astfel:+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''​.
  
-<code bash+<note
-$ docker network inspect c1-c2-bridge +Task: Creați un pod în mod declarativ folosind acest [[https://gitlab.com/mobylab-cc/​laborator-4/​-/​blob/​main/​testapp-pod.yaml|fișier de configurare]]. 
- +</note>
-[...] +
-"​Containers"​+
-    "​b063ad1ef7bd0ae82a7385582415e78938f7df531cef9eefc33e065af09cf92c":​ { +
-        "​Name":​ "​c2",​ +
-        "​EndpointID":​ "​a76463662d110804205e9211537e541eb0de2646fa90e8760d3419a6dc7d32c7",​ +
-        "​MacAddress":​ "​02:​42:​ac:​12:​00:​03",​ +
-        "​IPv4Address":​ "​172.18.0.3/16", +
-        "​IPv6Address":​ ""​ +
-    }, +
-    "​f5a8653a325e8092151614d5a6a80b04b9410ea8b8a5fcfc4028f1ad33239ad9":​ { +
-        "​Name":​ "​c1",​ +
-        "​EndpointID":​ "​95d9061b47f73f9b4cc7a82111924804bdc73d0b496549dec834216ee58c64ed",​ +
-        "​MacAddress":​ "​02:​42:​ac:​12:​00:​02",​ +
-        "​IPv4Address":​ "​172.18.0.2/16", +
-        "​IPv6Address":​ ""​ +
-    } +
-+
-[...] +
-</code> +
- +
-În acest moment, cele două containere fac parte din aceeași rețea și pot comunica:+
  
 +De asemenea, în lucrul cu pods putem face următoarele lucruri:
 <code bash> <code bash>
-$ docker exec -it c1 ash +kubectl port-forward <nume-pod> 8888:5000           # realizeaza mapare de porturi 
- +kubectl logs <​nume-pod> ​                            # afiseaza loguri 
-/ # ping -c2 c2 +kubectl exec <nume-pod> ​-- ls                       # executa o comanda intr-un pod 
-PING c2 (172.18.0.3)56 data bytes +kubectl cp file.txt <nume-pod>:/file.txt            # copiaza un fisier intr-un pod 
-64 bytes from 172.18.0.3: seq=0 ttl=64 time=6.258 ms +kubectl delete pods/<​nume-pod> ​                     ​sterge un pod
-64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.109 ms +
- +
---- c2 ping statistics --+
-2 packets transmitted,​ 2 packets received, 0% packet loss +
-round-trip min/avg/max = 0.109/​3.183/​6.258 ms +
- +
-/ # exit+
 </​code>​ </​code>​
  
-<code bash+<note
-$ docker exec -it c2 ash+Task: aplicați comenzile menționate mai sus pe pod-ul creat în task-ul anterior. 
 +</​note>​
  
-/ # ping -c2 c1 +==== Generarea de fișiere YAML ==== 
-PING c1 (172.18.0.2):​ 56 data bytes +Fișierele YAML pot fi scrise de la sau pot fi generate prin rularea //uscată// a pod-urilor.
-64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.111 ms +
-64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.268 ms+
  
---- c1 ping statistics --- +<code yaml> 
-2 packets transmitted,​ 2 packets received, 0% packet loss +#Exemplu oficial de fisier YAML 
-round-trip min/avg/max = 0.111/0.189/0.268 ms +apiVersion: v1 
- +kind: Pod 
-/ # exit+metadata: 
 +  name: nginx 
 +  labels: 
 +    run: nginx 
 +    whatever: dude 
 +spec: 
 + ​containers:​ 
 +  name: nginx 
 +    image: nginx:1.14.2 
 +    ​ports:​ 
 +    - containerPort:​ 80
 </​code>​ </​code>​
-==== Volume și bind mounts ==== 
  
-În Docker, datele dintr-un container nu sunt persistate în exterior. ​Pentru a ilustra acest lucru, putem rula un container simplu de Alpine, în care creăm un fișier apoi ieșim.+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''​
  
-<code bash> +==== Labels și Selectors ==== 
-$ docker container run --name c1 -ti alpine sh +În fișierul YAML generat de comanda anterioară,​ putem observa că în câmpul ''​metadata'',​ pe lângă atributul ''​name''​, avem și atributul ''​labels'':​ 
- +<code yaml> 
-Unable to find image 'alpine:​latest' ​locally +metadata
-latestPulling from library/​alpine +  ​creationTimestampnull 
-88286f41530ePull complete ​ +  ​labels
-Digestsha256:​f006ecbb824d87947d0b51ab8488634bf69fe4094959d935c0c103f4820a417d +    runnginx 
-Status: Downloaded newer image for alpine:latest +  name: nginx
- +
-/ # mkdir /test && echo hello > /​test/​hello.txt +
-/ # exit+
 </​code>​ </​code>​
  
-<code bash> +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 ​referi acest obiect (mai multe detalii în continuare).
-$ docker container ls -a+
  
-CONTAINER ID        IMAGE        COMMAND ​       CREATED ​            ​STATUS ​                     PORTS               NAMES +=== Label Selectors === 
-97492cd1349b ​       alpine ​      "​sh" ​          15 minutes ago      Exited (0) 15 minutes ago                       c1 +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.
-</​code>​+
  
-Odată ce un container a fost rulatchiar dacă execuția sa s-a oprit, layer-ele sale pot fi accesate până când containerul este șters ​cu comanda **//docker container rm//** (sau **//docker system prune//**)În mod implicit, Docker folosește [[https://​www.kernel.org/​doc/​Documentation/​filesystems/​overlayfs.txt|OverlayFS]] sau [[https://​www.thegeekstuff.com/​2013/​05/​linux-aufs/​|AUFS]] (ambele sisteme de fișiere de tip union) ca driver de storage pentru gestiunea imaginilorPutem verifica acest lucru folosind **//docker info//**:+Asa cum am spus anterior, cu ajutorul unor Label Selectors putem identifica numite seturi de obiecte în KubernetesUn exemplu relevant este expunerea unui pod printr-un serviciu.
  
-<code bash> +Un exemplu comun de utilizare a labels și labels selectors prin intermediul fișierelor de configurare YAML este următorul: 
-$ docker info | grep -i storage+''​kubectl run nginx --image=nginx --port=8080 --dry-run=client -o yaml >​vtest.yaml''​
  
-Storage Driveroverlay2+Adăugați podului următorul label: 
 +<code yaml> 
 +app: myapp
 </​code>​ </​code>​
  
-Pentru fiecare layer dintr-un container Docker, se vor stoca în AUFS/​OverlayFS informații despre cum arăta inițial șdespre ce fișiere s-au modificat (au fost adăugate, șterse sau schimbate). Aceste informații se găsesc în **///​var/​lib/​docker/​aufs/​diff//​** (pentru AUFS) sau **///​var/​lib/​docker/​overlay2//​** (pentru OverlayFS), unde există directoare pentru fiecare layer al fiecărui container care a fost rulat pe sistem fără să fi fost șters. Putem astfel să vedem din exteriorul containerului,​ după ce acesta a terminat de rulat, fișierul care a fost creat în interiorul containerului: +Creați pod-ul:
 <code bash> <code bash>
-$ cd /​var/​lib/​docker/​overlay2/​+kubectl apply -f test.yaml. 
 +kubectl describe pod nginx # analizate label-urile podului.
 </​code>​ </​code>​
  
-<​code ​bash+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:​ 
-$ ls -latr +<​code ​yaml
- +apiVersion: v1 
-[...] +kind: Service 
-drwx------ ​   4 root   ​root ​  4096 Oct 21 07:12 5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc-init +metadata: 
-drwx------    ​4 root   ​root ​  4096 Oct 21 07:12 5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc+  ​creationTimestamp:​ null     
 +  namenginx 
 +spec: 
 +  ports: 
 +  ​port: 80 
 +    protocol: TCP 
 +    targetPort: 80 
 +  selector: 
 +    app: myapp #select the pod/pods 
 +status: 
 +  loadBalancer{}
 </​code>​ </​code>​
  
-<code bash> +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.
-$ ls 5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc/​diff/​+
  
-root  test +==== ReplicaSets ==== 
-</​code>​ +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ă.
- +
-<code bash> +
-$ cat 5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc/​diff/​test/​hello.txt +
  
-hello+Exemplu de ReplicaSet:​ 
 +<code yaml> 
 +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
 </​code>​ </​code>​
  
-Totuși, aceste date nu sunt persistente,​ ci sunt șterse împreuna cu layer-ulAstfel, dacă se șterge containerul,​ datele vor fi pierdute: +Pentru detalii legate de ReplicaSets putem folosi următoarele comenzi: 
- +<code yaml> 
-<code bash+kubectl apply -f testapp-rs.yaml                           # creează un ReplicaSet dintr-un fisier 
-$ docker container rm 97492cd1349b+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
 </​code>​ </​code>​
  
-<code bash+<note
-$ ls 5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc/+Task: creați un ReplicaSet pe baza [[https://​gitlab.com/​mobylab-cc/​laborator-4/​-/​blob/​main/​testapp-rs.yaml|acestui fișier]]. Aplicați comenzile de mai sus. 
 +</​note>​
  
-ls5b3f2aeff7a90abd5c1a2eb50e5bbf9bde38983bda84728ab3788a12ea2399dc:​ No such file or directory +Un ReplicaSet poate fi scalat prin două moduri
-</code>+  - deschidem fișierul de configurare,​ modificăm numărul de replici și aplicăm comanda de apply asupra fișierului de configurare 
 +  - folosind comanda de scalare: ''​kubectl scale replicasets ​<nume-replicaset--replicas=4''​
  
-Pentru persistența datelor dintr-un containerîn Docker se folosesc mecanisme de persistență numite **volume**, care sunt o mapare între fișierele din cadrul unui container și fișiere de pe sistemul gazdă sau NFS (Network File Storage)Volumele Docker au câteva proprietăți și beneficii:+<​note>​ 
 +Task: scalați ReplicaSet-ul creat anterior la 4 noduri (folosind oricare din metode)apoi ștergeti ReplicaSet-ul. 
 +</​note>​
  
-  * sunt ușor de salvat și migrat +==== Deployments ==== 
-  * pot fi controlate și configurate cu comenzi CLI sau cu API-ul de Docker +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.
-  * funcționează pe containere Linux și Windows +
-  * pot fi partajate între containere +
-  * prin driverele de volume, se pot stoca date persistente pe gazde remote sau pe provideri de cloud, se pot cripta datele, etc. +
-  * conținutul unui volum nou poate fi pre-populat de un container +
-  * utilizarea unui volum nu crește dimensiunea unui container care îl foloseștepentru că un volum există în afara ciclului de viață al containerului.+
  
-Volumele se mai numesc și „named volumes” și sunt gestionate ​de Docker. Există mai multe metode pentru a defini și utiliza un volum atunci când se rulează un singur container de Linux. Dacă se creează o imagine custom, atunci volumul se poate defini în fișierul Dockerfile, prin comanda **//​VOLUME//​**. Dacă se rulează, de exemplu, un container bazat pe o imagine existentă (cum ar fi Alpine în exemplul din [[cc:laboratoare:01|laboratorul 1]]), atunci se poate defini un volum la runtime. În exemplul de mai jos, rulăm o imagine de Alpine în background care face **//​ping//​** într-un fișier localizat într-un volum **///​test//​**,​ pe care îl creăm folosind flag-ul **//-v//**+Exemplu ​de deployment (varianta declarativă): 
- +<code yaml> 
-<code bash> +apiVersion: apps/v1 
-$ docker container run --name c2 -d -v /test alpine sh -c 'ping 8.8.8.8 > /​test/​ping.txt'​+kindDeployment 
 +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.
 +       ​ports:​ 
 +       - containerPort:​ 80
 </​code>​ </​code>​
  
-<code bash+<note
-$ docker container ls+Task: 
 +  * Creați deployment-ul definit în fișierul de mai sus, știm deja cum să folosim comanda apply. 
 +  * Verificați câte noduri există: ''​kubectl get pods''​. 
 +  * Verificați câte ReplicaSets există: ''​kubectl get rs # am folosit un shortcut aici''​ 
 +  * Verificați că deployment-ul este up and running: ''​kubectl get deploy''​ 
 +</​note>​
  
-CONTAINER ID        IMAGE               ​COMMAND ​                 CREATED ​             STATUS ​             PORTS               ​NAMES +==== ConfigMaps și Secrets ====
-59d0785188a6 ​       alpine ​             "sh -c 'ping 8.8.8..." ​  About a minute ago   Up About a minute ​                      c2 +
-</​code>​+
  
-În timp ce containerul rulează, putem să îl inspectăm și observăm că este legat de o componentă de tip **//​Volume//​** cu destinația **///test//**. Astfelputem afla unde este localizat volumulDacă ne uităm în acel directorvom vedea fișierul în care se face **//​ping//​** din container:+Un ConfigMap ​este un obiect folosit pentru a stoca într-un format ​de tipul cheie-valoare date care **nu** sunt sensitiveUn pod poate consuma un ConfigMap ca o variabilă de mediuca 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țieiceea ce sporește portabilitatea aplicațiilor.
  
-<code bash> +Un exemplu simplu este separarea mediilorPentru 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ățădespre servicii în următorul laborator).
-$ docker container inspect -f "{{ json .Mounts }}" c2 | python -json.tool+
  
-+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).
-    { +
-        "​Destination":​ "/​test",​ +
-        "​Driver":​ "​local",​ +
-        "​Mode":​ "",​ +
-        "​Name":​ "​2afac5683222a3435549131a931a4c0628b775ecd3d79cb3fd597b3501418288",​ +
-        "​Propagation":​ "",​ +
-        "​RW":​ true, +
-        "​Source":​ "/​var/​lib/​docker/​volumes/​2afac5683222a3435549131a931a4c0628b775ecd3d79cb3fd597b3501418288/​_data",​ +
-        "​Type":​ "volume+
-    } +
-+
-</​code>​+
  
-<​code ​bash+Fișier pentru configurarea unui ConfigMap:​ 
-$ ls /​var/​lib/​docker/​volumes/​2afac5683222a3435549131a931a4c0628b775ecd3d79cb3fd597b3501418288/​_data +<​code ​yaml
- +apiVersion: v1 
-ping.txt+kind: ConfigMap 
 +metadata: 
 + name: game-demo 
 +data: 
 + # property-like keys; each key maps to a simple value 
 + player_initial_lives:​ "​3"​
 </​code>​ </​code>​
  
-<code bash+<note
-$ cat ping.txt ​+Task: 
 +  * aplicați ConfigMap-ul de mai sus, folosind comanda apply: ''​kubectl apply -f <​configmapfile>''​ 
 +  * verificați că a fost creat obiectul: ''​kubectl get configmap''​ 
 +</​note>​
  
-PING 8.8.8.8 (8.8.8.8): 56 data bytes +Un ConfigMap poate fi folosit într-un pod în mai multe moduri, nu doar ca în exemplul de mai sus, într-o variabilă de mediuMai 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).
-64 bytes from 8.8.8.8: seq=0 ttl=38 time=58.619 ms +
-64 bytes from 8.8.8.8: seq=1 ttl=38 time=58.498 ms +
-</​code>​+
  
-Dacă oprim și ștergem containerul,​ volumul va exista ​în continuare: +Fișier pentru configurarea unui pod folosind ConfigMap (în acest exemplu folosind ConfigMap-ul definit anterior)
- +<​code ​yaml
-<​code ​bash+apiVersion: v1 
-$ docker container stop c2 +kind: Pod 
- +metadata: 
-c2+ 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.
 </​code>​ </​code>​
  
-<code bash+<note
-$ docker container rm c2+Task: Creați acest pod-ul definit mai sus. 
 +</​note>​
  
-c2 +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.
-</​code>​+
  
-<code bash+<note
-$ ls /​var/​lib/​docker/​volumes/​2afac5683222a3435549131a931a4c0628b775ecd3d79cb3fd597b3501418288/​_data +Pentru ​verifica ​că totul mers cum ne teptam, afișați ​toate variabilele ​de mediu din interiorul podului proaspăcreat. 
- +</note>
-ping.txt +
-</​code>​ +
- +
-treia metodă de a lucra cu volume în Docker este direct prin API-ul de volume, adică prin comenzi CLI de genul **//docker volume create//**, **//docker volume ls//**, etc. Dacă vrem să creăm volume pentru o stivă de servicii, acest lucru poate fi făcut în fișierul YAML folosit pentru Docker Compose, așa cum vom vedea în [[cc:​laboratoare:​03|laboratorul 3]]. +
- +
-Pe lângă volume, mai există și noțiunea de **bind mounts**. Acestea sunt similare cu volumele, dar nu sunt gestionate de Docker, ci se pot afla oriunde în sistemul de fișiere al gazdei pe care rulăm containerele,​ și pot fi modificate extern de orice proces non-Docker. Diferența principală dintre un bind mount si un volum este că bind mount-ul este o cale fizică de pe mașina gazdă, în timp ce volumul este o entitate Docker care utilizează,​ în spate, un bind mount abstractizat. În imaginea de mai jos (preluată din [[https://​docs.docker.com/​storage/​bind-mounts/​|documentația oficială]]),​ se poate observa în mod grafic diferența dintre volume și bind mounts. +
- +
-{{:​cc:​laboratoare:​volumebind.png?​direct&​500|}} +
- +
-Atunci când pornim un container prin comanda **//docker container run//**, atât argumentul **//-v//** (sau **//​%%--%%volume//​**),​ cât și **//​%%--%%mount//​** permit utilizarea de bind mounts și volume. Totuși, în cadrul serviciilor (așa cum vom vedea în [[cc:​laboratoare:​03|laboratorul 3]]), nu putem folosi decât **//​%%--%%mount//​**. Acesta este totuși considerat oricum mai expresiv, pentru că necesită specificarea efectivă ​ tipului de legătura (volum sau bind mount). Astfel, exemplul anterior unde atașam un volum **///​test//​** containerului pe care îl rulam ar arăta în felul următor: +
- +
-<code bash> +
-$ docker container run --name c2 -d --mount source=test,​target=/​test alpine sh -c 'ping 8.8.8.8 > /​test/​ping.txt'​ +
-</​code>​ +
- +
-Pentru ​verifica efectul acestei comenzi, putem rula comanda de inspectare:​ +
- +
-<code bash> +
-$ docker container inspect -f "{{ json .Mounts }}" c2 | python -m json.tool +
- +
-+
-    { +
-        "​Destination":​ "/​test",​ +
-        "​Driver":​ "​local",​ +
-        "​Mode":​ "​z",​ +
-        "​Name":​ "​test",​ +
-        "​Propagation":​ "",​ +
-        "​RW":​ true, +
-        "​Source":​ "/​var/​lib/​docker/​volumes/​test/​_data",​ +
-        "​Type":​ "​volume"​ +
-    } +
-+
-</​code>​ +
- +
-==== Docker pe Windows ​și pe MacOS ==== +
- +
-Docker a fost creat nativ pentru Linuxutilizând componente de kernel specifice Linux, cum ar fi **//​cgroups//​** sau **//​namespaces//​**,​ folosite pentru a izola procese și alte componente ale sistemului de operare. Începând din 2016, el poate rula nativ și pe Windows, dar doar pentru versiunile Windows Server 2016 și Windows 10. De aceea, pentru a rula pe un sistem de operare desktop precum un Windows mai vechi sau MacOS, Docker necesită rularea virtualizată. +
- +
-Pe Windows, se folosește izolare Hyper-V pentru a rula un kernel Linux cu un set minimal de componente suficiente pentru a executa Docker. Pe MacOS, Docker for Mac este o aplicație nativă care conține un hypervizor bazat pe [[https://​github.com/​machyve/​xhyve|xhyve]] și o distribuție minimală de Linux, peste care rulează Docker. Astfel, se oferă o experiență mult mai apropiată de utilizarea Docker pe Linux, sistemul de operare pentru care a fost creat. +
- +
-Ca un exemplu, pentru a avea acces în mașina virtuală de Docker pentru MacOS, se poate folosi **//​screen//​** (pentru a se termina sesiunea, se folosește combinația de taste **//Ctrl+a, k//**): +
- +
-<code bash> +
-$ screen /​Users/<​UID>/​Library/​Containers/​com.docker.docker/​Data/​vms/​0/​tty +
- +
-linuxkit-025000000001:​~#​ pwd +
-/root +
-</​code>​ +
- +
-==== Comenzi utile ==== +
- +
-=== Comenzi de lucru cu un registru === +
- +
-<code bash> +
-$ docker login [–u <​UTILIZATOR>​ –p <​PAROLĂ>​] [SERVER] ​  # loghează un utilizator într-un registru +
-$ docker tag <​IMAGINE>​ <​UTILIZATOR/​REPOSITORY:​TAG> ​     # dă un tag unei imagini pentru upload în registru +
-$ docker push <​UTILIZATOR/​REPOSITORY:​TAG> ​              # uploadează o imagine în registru +
-</​code>​ +
- +
-=== Creare și interacțiune cu rețele === +
- +
-<code bash> +
-$ docker network create -d <​DRIVER>​ <​REȚEA> ​         # creează o rețea cu un driver dat +
-$ docker network ls                                  # afișează rețelele existente +
-$ docker network rm                                  # șterge o rețea +
-$ docker network connect <​REȚEA>​ <​CONTAINER> ​        # conectează un container la o rețea +
-$ docker network disconnect <​REȚEA>​ <​CONTAINER> ​     # deconectează un container de la o rețea +
-$ docker network inspect <​REȚEA> ​                    # afișează informații despre o rețea +
-$ docker container run --network=<​REȚEA>​ <​IMAGINE> ​  # pornește un container într-o rețea +
-</​code>​ +
- +
-=== Creare și interacțiune cu volume sau bind mounts === +
- +
-<code bash> +
-$ docker volume create <​VOLUM> ​                                               # creează un volum +
-$ docker volume ls                                                            # afișează volumele existente +
-$ docker volume rm <​VOLUM> ​                                                   # șterge un volum +
-$ docker container run -v <​VOLUM>​ <​IMAGINE> ​                                  # rulează un container cu un volum atașat +
-$ docker container run -v <​SURSĂ>:<​DESTINAȚIE>​ <​IMAGINE> ​                     # rulează un container cu un volum sau un bind mount atașat +
-$ docker container run --mount source=<​SURSĂ>,​target=<​DESTINAȚIE>​ <​IMAGINE> ​  # rulează un container cu un volum sau bind mount atașat +
-</​code>​ +
-==== Exerciții ==== +
- +
-Pentru exercițiile din acest laborator, veți porni de la această arhivă, care conține o aplicație NodeJS care realizează un API peste o bază de date PostgreSQL. Exercițiile de mai jos vă trec prin pașii necesari pentru ​rula un container pentru o bază de date PostgreSQL și containerul cu aplicația în aceeașrețea, având persistență la oprirea containerelor. +
- +
-  - Pe baza surselor și a fișierului Dockerfile din arhiva de laborator, construiți o imagine cu numele **api-laborator-2-image**. +
-  - Creați o rețea numită **laborator2-db-network**. +
-  - Creați un volum numit **laborator2-db-persistent-volume**. +
-  - Porniți un container pentru o bază de date cu următorii parametri:​ +
-    - se va atașa un bind mount care va face o mapare între fișierul **//​init-db.sql//​** de pe mașina locală (acesta va fi sursa la flag-ul de bind mount și se găsește în arhiva de laborator) și fișierul **///​docker-entrypoint-initdb.d/​init-db.sql//​** din containerul care se va rula (acesta va fi destinația) +
-    - se va atașa volumul **laborator2-db-persistent-volume** creat anterior (sursa) la calea **//​var/​lib/​postgresql/​data//​** din containerul care se va rula (destinația) +
-    - se va rula containerul în rețeaua **laborator2-db-network** creată anterior +
-    - se vor specifica următoarele variabile ​de mediu (într-o comandă de **//docker run//**, acest se lucru se face astfel: **//docker run -e NUME=valoare//​**):​ +
-      - variabila **//​POSTGRES_USER//​** cu valoare **//​admin//​** +
-      - variabila **//​POSTGRES_PASSWORD//​** cu valoarea **//​admin//​** +
-      - variabila **//​POSTGRES_DB//​** cu valoarea **//​books//​** +
-    - containerul rulat se va numi **//​laborator2-db//​** +
-    - se va rula imaginea **//​postgres//​** ​din registrul oficial. +
-  - Porniți un container cu imaginea **api-laborator-2-image** creată anterior, cu următorii parametri:​ +
-    - se va rula containerul în rețeaua **laborator2-db-network** ​creată anterior +
-    - se vor specifica următoarele variabile de mediu: +
-      - variabila **//​PGUSER//​** cu valoare **//​admin//​** +
-      - variabila **//​PGPASSWORD//​** cu valoarea **//​admin//​** +
-      - variabila **//​PGDATABASE//​** cu valoarea **//​books//​** +
-      - variabila **//​PGHOST//​** cu valoarea **//​laborator2-db//​** +
-      - variabila **//​PGPORT//​** cu valoarea **//​5432//​** +
-    - containerul rulat se va numi **//​laborator2-api//​** +
-    - containerul va expune portul 80 și îl va mapa la portul 5555 de pe mașina locală+
-  - Verificați că cele două containere rulează corect și au conectivitate:​ +
-    - folosind Postman sau orice altă aplicație similară, realizați cereri de GET și POST pe **//​localhost:​5555/​api/​books//​** +
-    - la cererile de POST, se așteaptă un body JSON cu formatul ''​%%{"​title":"​titlu","​author":"​autor"​}%%''​ +
-    - cererile de GET vor returna o listă de cărți adăugate prin cereri de POST. +
-  - Verificați că volumul pe care l-ați adăugat păstrează persistența datelor: +
-    - opriți și ștergeți cele două containere +
-    - reporniți cele două containere cu aceleași comenzi ca anterior +
-    - trimiteți o cerere de GET +
-    - dacă ați configurat corect, veți primi o listă cu cărțile adăugate anterior.+
cc/laboratoare/02.1603085148.txt.gz · Last modified: 2020/10/19 08:25 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