Differences

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

Link to this comparison view

cc:laboratoare:05 [2021/11/15 10:02]
alexandru.hogea [Deployment folosind Kubernetes]
cc:laboratoare:05 [2022/11/11 23:12] (current)
florin.mihalache
Line 1: Line 1:
-===== Laboratorul 05 - Kubernetes & Kubectl=====+====== Laboratorul 05 - Terraform + AWS ======
  
-==== Introducere ​====+===== Deployments & virtual machines în AWS ===== 
 +În cadrul acestui laborator veți învăța cum să creați mașini virtuale în cadru AWS (Amazon Web Services), care reprezintă o platformă care furnizează servicii de tip cloud computing, baze de date, stocare de fișiere, device farms, etc.
  
-In acest laborator ​vom parcurge crearea ​de **pods** folosind comanda **kubectl**Activitatea este echivalenta cu pornirea mai multor containere de Docker folosind **docker run**.+Pentru ​acest laborator ​presupunem că avem deja Terraform instalat ​de la laboratorul precedentDacă nu aveți Terraform instalat, puteți urma pașii din laboratorul anterior.
  
-==== Aplicatia Propusa ====+Pe langa Terraform, avem nevoie de AWS CLI instalat. Pentru a instala, urmati pasii de [[https://​docs.aws.amazon.com/​cli/​latest/​userguide/​getting-started-install.html | aici]].
  
-Va propunem o mini aplicatie formata din 4 componente:​ +Pe lângă asta, avem nevoie ​de un cont pentru Amazon AWS. După ce ați făcut pașii pentru a avea propriul cont AWS, vrem sa conectăm AWS CLI la consola ​de AWS.
-  - un API webserver +
-  - un script care proceseaza informatii +
-  - o baza de date +
-  - un broker ​de rabbitMQ +
-{{:​cc:​laboratoare:​schema_cod.png?800|}}+
  
-Aplicatia reprezinta un model simplificat de [[https://​martinfowler.com/​bliki/​CQRS.html|CQRS]]. ​ +Pentru a face asta, mergem în AWS și intrăm în secțiunea IAM
-<note tip>​CQRS ​Command and Query Responsibility Segregation se refera la despartirea logica intre cereri si actiuni care modifica starea dintr-un sistem</​note>​+{{ :​cc:​laboratoare:​lab-5-image3.png?​700 |}}
  
-Fluxul este urmatorul+Apoi mergem la "My security credentials"​
-  * Serverul **API** accepta doua __cereri HTTP__un POST si un GET +{{ :cc:​laboratoare:​lab-5-image1.png?700 |}}
-  * Cererile de tip POST sunt trimise catre **Procesator**Procesatorul adauga un timestamp si apoi scrie intrarea in baza de date +
-  * Cererile de tip GET sunt procesate direct de API care trage informatia din baza de date+
  
-Codul este accesibil ​pe [[https://​gitlab.com/​mobylab-cc/laborator-k8s|repo-ul nostru]].+Următorul pas este să mergem la "​Access Keys" și să apăsăm ​pe butonul de ''​Create New Access Key'':​ 
 +{{ :cc:​laboratoare:​lab-5-image5.png?700 |}}
  
-==== Deployment folosind Kubernetes ====+Păstrați fișierul generat. Rulați comanda ''​aws configure''​ și introduceți datele generate în fisierul creat anterior (''​AWSAccessKeyId''​ și ''​AWSSecretKey''​).
  
-In codul sursa aveti un exemplu de **docker-compose.yml**,​ pentru ​avea perspectiva familiara asupra cum va arata deploymentul local. In Kubernetes, fiecare serviciu va fi reprezentat ​de un Pod.+Pentru ​crea instanță simplă de EC2 (o mașina virtuală) folosim următorul ​fișier de Terraform:​ 
 +<code terraform>​ 
 +terraform { 
 + ​required_providers { 
 +   aws = { 
 +     ​source ​ = "​hashicorp/​aws"​ 
 +     ​version = "~> 4.16" 
 +   } 
 + } 
 +  
 + ​required_version = ">= 1.2.0"​ 
 +
 +  
 +provider "​aws"​ { 
 + ​region = "​us-west-2"​ # regiunea in care o sa se faca deploy la resurse 
 +
 +  
 +resource "​aws_instance"​ "​app_server"​ { 
 + ​ami ​          = "​ami-830c94e3"​ # tipul de masina folosita (ami = Amazon Machine Image) 
 + ​instance_type = "​t2.micro"​ # tipul de instanta (resursele pe care le are masina) 
 +  
 + tags = { 
 +   Name = "​labAwsTerraform"​ 
 + } 
 +
 +</​code>​
  
-In continuare vom folosi ​comenzile ​de Kubectl, prezentate la laboratorul trecut, ​pentru a porni fiecare Pod independent. +Rulați ​comenzile ​cunoscute ​pentru a face deployment acestei infrastructuri:​ 
-<note tip>La laboratorul urmator vom face deployment folosind configuratie declarativa yaml</note>+<code bash> 
 +terraform init 
 +terraform fmt 
 +terraform plan 
 +terraform apply 
 +</code>
  
-Vom lucra cu urmatoarele concepte+Pentru a verifica ca mașina virtuală a fost deployed, căutăm serviciul EC2
-  * Pods vor fi 4 (api, db, rabbitmq, procesator) +{{ :​cc:​laboratoare:​lab-5-image7.png?700 |}}
-  * ClusterIP Service - vor fi 3 (pentru api, rabbitmq si db). Rolul lor este sa expuna porturile **pod**-urilor in reteaua **interna** kubernetes +
-  * NodePort Service - va fi 1 (pentru api). Rolul sau este sa expuna portul **pod**-ului in reteaua **de pe host**.+
  
-<note important>​Atentie la modul in care sunt mapate porturile. Ordinea este inversata fata de DockerIn docker, porturile sunt mapate EXTERN:INTERN. In kubernetes, ele sunt **INTERN:EXTERN**</​note>​+Ajungem în pagina următoare în care vedem că nu avem nicio instanță up and running, ​deși planul nostru de Terraform a fost executat cu succesDe ce? 
 +{{ :cc:laboratoare:​lab-5-image4.png?​700 |}}
  
-Mai jos puteti regasi comenzile care vor fi efectuate pentru rezolvarea laboratorului:​ +Observați diferența de regiuni (Frankfurt, în cazul din imaginea anterioară,​ față de us-west-2 în Terraform). Pentru a modifica regiunea în care facem deployment la resurse modificăm codul Terraform. În cazul de față, putem să facem click pe Frankfurt și să selectăm us-west-2 (Oregon). În acest moment putem vedea că avem o instanță up and running: 
-<code bash> +{{ :​cc:​laboratoare:​lab-5-image2.png?​700 |}}
-kubectl run db --image=axonedge/​lab-k8s-database --env="​POSTGRES_USER=student"​ --env="​POSTGRES_PASSWORD=student"​ --env="​POSTGRES_DB=library"​ +
-kubectl expose pod db --port=5432 --target-port=5432 --name=db-cluster-ip-service+
  
-kubectl run rabbitmq ​--image=rabbitmq:​3 --port=5672 +<note tip> 
-kubectl expose pod rabbitmq --port=5672 --target-port=5672 --name=rabbitmq-cluster-ip-service+În codul Terraform modificați numele masinii din ''​labAwsTerraform''​ în ''​testUpdate''​. 
 +Rulatț comenzile obișnuite pentru a vedea planul. 
 +Observați că această modificare nu implică distrugerea mașinii existente, ci doar modificarea in-place. 
 +</​note>​
  
-kubectl describe pod rabbitmq +{{ :​cc:​laboratoare:​lab-5-image6.png?​700 |}}
-kubectl describe service rabbitmq-cluster-ip-service+
  
-kubectl run procesator --image=axonedge/​lab-k8s-procesator --env="​PGHOST=db-cluster-ip-service"​ --env="​PGDATABASE=library"​ --env="​PGPORT=5432" --env="​PGUSER=student"​ --env="​PGPASSWORD=student"​ --env="​AMQPURL=amqp://​rabbitmq-cluster-ip-service"​+===== Cluster Kubernetes în AWS ===== 
 +Pentru a face deployment unui cluster de Kubernetes în AWS avem 2 opțiuni. 
 +  ​Facem deploy la mai multe mașini virtuale și instalăm și configurăm un cluster ​de mână. 
 +  ​Folosim serviciul AWS special conceput pentru clusters de Kubernetes, AWS EKS Cluster
  
-kubectl logs procesator+În cazul acestui laborator, o să facem deployment la un cluster folosind EKS.
  
-kubectl run api --image=axonedge/​lab-k8s-api --env="​PORT=8000"​ --env="​PGHOST=db-cluster-ip-service"​ --env="​PGDATABASE=library"​ --env="​PGPORT=5432"​ --env="​PGUSER=student"​ --env="​PGPASSWORD=student"​ --env="​AMQPURL=amqp://​rabbitmq-cluster-ip-service"​ +Pentru a urma best practices recomandate de hashicorp, o să spargem codul în mai multe fișiere.
-kubectl expose pod api --port=8000 --name=api-nodeport-service --type=NodePort+
  
-kubectl delete --all pods +Fișierul ''​variables.tf''​ o sa conțină o simplă variabilă în care definim zona în care vrem să facem deployment: 
-kubectl delete ​--all services+<code terraform>​ 
 +variable "​region"​ { 
 + ​description = "AWS region"​ 
 + ​type ​       = string 
 + ​default ​    = "us-west-2" 
 +}
 </​code>​ </​code>​
-==== Testare ==== 
  
-Pentru a testa aplicatia va recomandam sa folositi ​[[https://www.postman.com/|Postman]].+Mai departe avem nevoie de un VPC, deci vom crea un nou fisier ''​vpc.tf''​. Mai multe despre ce este un VPC: [[https://docs.aws.amazon.com/vpc/​latest/​userguide/​what-is-amazon-vpc.html ​aici]]. 
 +<​code>​ 
 +module "​vpc"​ { 
 + ​source ​ = "​terraform-aws-modules/​vpc/​aws"​ 
 + ​version = "​3.14.2"​ 
 +  
 + name = "​cc-vpc"​ 
 +  
 + cidr = "​10.0.0.0/​16"​ 
 + ​azs ​ = slice(data.aws_availability_zones.available.names,​ 0, 3) 
 +  
 + ​private_subnets = ["​10.0.1.0/​24",​ "​10.0.2.0/​24",​ "​10.0.3.0/​24"​] 
 + ​public_subnets ​ = ["​10.0.4.0/​24",​ "​10.0.5.0/​24",​ "​10.0.6.0/​24"​] 
 +  
 + ​enable_nat_gateway ​  = true 
 + ​single_nat_gateway ​  = true 
 + ​enable_dns_hostnames = true 
 +  
 + ​public_subnet_tags = { 
 +   "​kubernetes.io/​cluster/​${local.cluster_name}"​ = "​shared"​ 
 +   "​kubernetes.io/​role/​elb" ​                     = 1 
 + } 
 +  
 + ​private_subnet_tags = { 
 +   "​kubernetes.io/​cluster/​${local.cluster_name}"​ = "​shared"​ 
 +   "​kubernetes.io/​role/​internal-elb" ​            = 1 
 + } 
 +
 +</​code>​
  
-Testarea se realizeaza in felul urmator: +Mai multe detalii despre modulul ​de Terraform pentru VPC: [[https://registry.terraform.io/providers/hashicorp/aws/​latest/​docs/​resources/​vpc | aici]]. 
-  * Adaugati o intrare, trimitand o cerere ​de tip POST pe linkul **http://localhost:​PORT_ALES/api/v1/books** ​cu urmatorul body+ 
-<​code ​json+În continuare avem nevoie de 2 security groups, pe care o să le folosească cluster-ul nostru. Așadar creăm un nou fișier cu numele ''​securityGroups.tf'' ​cu următorul conținut
-+<​code>​ 
-    "name""De ce iubim femeile?", +resource "​aws_security_group"​ "​node_group_one" ​
-    "author""Mircea Cartarescu", + name_prefix = "node_group_one" 
-    "price": 69, + ​vpc_id ​     = module.vpc.vpc_id 
-    "description""Autoironie"+  
 + ​ingress { 
 +   ​from_port = 22 
 +   ​to_port ​  = 22 
 +   ​protocol ​ = "tcp" 
 +  
 +   ​cidr_blocks = [ 
 +     "​10.0.0.0/​8", 
 +   ] 
 + } 
 +
 +  
 +resource ​"aws_security_group" "node_group_two" ​{ 
 + name_prefix = "node_group_two
 + vpc_id ​     = module.vpc.vpc_id 
 +  
 + ​ingress { 
 +   ​from_port = 22 
 +   ​to_port ​  = 22 
 +   ​protocol ​ = "tcp" 
 +  
 +   ​cidr_blocks = [ 
 +     "192.168.0.0/​16"
 +   ] 
 + }
 } }
 </​code>​ </​code>​
-  * Vizualizati intrarea, trimitand o cerere ​de tip GET pe acelasi link+ 
-<note tip>Observati ca intrarea va avea campul **insertedAt** adaugat</note+Ne putem gândi la un security group ca la un firewall. Mai multe detalii în [[https://​aviatrix.com/​learn-center/​cloud-security/​aws-security-groups/​ | documentație]]. Documentația unui security group de AWS în Terraform: [[https://​registry.terraform.io/​providers/​hashicorp/​aws/​latest/​docs/​resources/​security_group | aici]]. 
-{{:cc:laboratoare:post.png?800|}}+ 
 + 
 +Până acum am definit doar componentele de care o să ne folosim în momentul în care configurăm cluster-ul nostru. Pentru a face asta, avem un nou fișier ''​cluster.tf''​ cu următoarea configurație:​ 
 +<code> 
 +module "​eks"​ { 
 + ​source ​ = "​terraform-aws-modules/​eks/​aws"​ 
 + ​version = "​18.26.6"​ 
 +  
 + ​cluster_name ​   = local.cluster_name 
 + ​cluster_version = "​1.22"​ 
 +  
 + ​vpc_id ​    = module.vpc.vpc_id 
 + ​subnet_ids = module.vpc.private_subnets 
 +  
 + ​eks_managed_node_group_defaults = { 
 +   ​ami_type = "​AL2_x86_64"​ 
 +  
 +   ​attach_cluster_primary_security_group = true 
 +  
 +   # Disabling and using externally provided security groups 
 +   ​create_security_group = false 
 + } 
 +  
 + ​eks_managed_node_groups = { 
 +   one = { 
 +     name = "​node-group-1"​ 
 +  
 +     ​instance_types = ["​t3.small"​] 
 +  
 +     ​min_size ​    = 1 
 +     ​max_size ​    = 3 
 +     ​desired_size = 2 
 +  
 +     ​pre_bootstrap_user_data = <<​-EOT 
 +     echo 'foo bar' 
 +     EOT 
 +  
 +     ​vpc_security_group_ids = [ 
 +       ​aws_security_group.node_group_one.id 
 +     ] 
 +   } 
 +  
 +   two = { 
 +     name = "​node-group-2"​ 
 +  
 +     ​instance_types = ["​t3.medium"​] 
 +  
 +     ​min_size ​    = 1 
 +     ​max_size ​    = 2 
 +     ​desired_size = 1 
 +  
 +     ​pre_bootstrap_user_data = <<​-EOT 
 +     echo 'foo bar' 
 +     EOT 
 +  
 +     ​vpc_security_group_ids = [ 
 +       ​aws_security_group.node_group_two.id 
 +     ] 
 +   } 
 + } 
 +
 +</code
 + 
 +Mai avem doar de creat un fișier ''​main.tf''​ cu următoarea configurație:​ 
 +<​code>​ 
 +provider "​kubernetes" ​{ 
 + ​host ​                  = module.eks.cluster_endpoint 
 + ​cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) 
 +
 +  
 +provider "​aws" ​{ 
 + ​region = var.region 
 +
 +  
 +data "​aws_availability_zones"​ "​available"​ {} 
 +  
 +locals { 
 + ​cluster_name = "cc-eks-${random_string.suffix.result}"​ 
 +
 +  
 +resource "​random_string"​ "​suffix"​ { 
 + ​length ​ = 8 
 + ​special = false 
 +
 +</​code>​ 
 + 
 +Pentru a afișa câteva informații legate de infrastructura noastră avem nevoie de câteva outputs. Așa cum am învățat data trecută, facem un fișier separat în care definim acest outputs: 
 +<​code>​ 
 +output "​cluster_id"​ { 
 + ​description = "EKS cluster ID" 
 + ​value ​      = module.eks.cluster_id 
 +
 +  
 +output "​cluster_endpoint"​ { 
 + ​description = "​Endpoint for EKS control plane"​ 
 + ​value ​      = module.eks.cluster_endpoint 
 +
 +  
 +output "​cluster_security_group_id"​ { 
 + ​description = "​Security group ids attached to the cluster control plane"​ 
 + ​value ​      = module.eks.cluster_security_group_id 
 +
 +  
 +output "​region"​ { 
 + ​description = "AWS region"​ 
 + ​value ​      = var.region 
 +
 +  
 +output "​cluster_name"​ { 
 + ​description = "​Kubernetes Cluster Name"​ 
 + ​value ​      = local.cluster_name 
 +
 +</​code>​  
 + 
 +Rulăm comenzile obișnuite pentru a crea infrastructura. Observați ca sunt foarte multe resurse care urmează să se construiască. 
 + 
 +In cazul in care ați realizat ca lipsește ceva (nu am definit niciunde ce versiuni ale provider-ilor vrem să folosim), best practices recomandă să avem un fișier numit ''​terraform.tf''​ care să conțină această configurație: 
 +<​code>​ 
 +terraform { 
 + ​required_providers { 
 +   aws = { 
 +     ​source ​ = "​hashicorp/​aws"​ 
 +     ​version = "~> 4.15.0"​ 
 +   } 
 +  
 +   ​random = { 
 +     ​source ​ = "​hashicorp/​random"​ 
 +     ​version = "~> 3.1.0"​ 
 +   } 
 +  
 +   tls = { 
 +     ​source ​ = "​hashicorp/​tls"​ 
 +     ​version = "~> 3.4.0"​ 
 +   } 
 +  
 +   ​cloudinit = { 
 +     ​source ​ = "​hashicorp/​cloudinit"​ 
 +     ​version = "~> 2.2.0"​ 
 +   } 
 +  
 +   ​kubernetes = { 
 +     ​source ​ = "​hashicorp/​kubernetes"​ 
 +     ​version = "~> 2.12.1"​ 
 +   } 
 + } 
 +
 +</​code>​ 
 + 
 +Asteptați ca planul să se termine de rulat sș verificați infrastructura creată în AWS (o să dureze în jur de 15-20 minute). Apoi, pentru a ne conecta la cluster-ul nostru proaspăt creat de Kubernetes, folosim următoarea comandă: 
 +<code bash> 
 +aws eks --region $(terraform output -raw region) update-kubeconfig \ 
 +    --name $(terraform output -raw cluster_name) 
 +</​code>​ 
 + 
 +Verificați conexiunea cu următoarea comandă: ''​kubectl cluster-info''​ 
 + 
 +În acest moment avem un cluster configurat în AWS EKS și suntem conectați la el. Orice comandă de kubectl rulată o să fie executată pe cluster-ul nostru. 
 + 
cc/laboratoare/05.1636963358.txt.gz · Last modified: 2021/11/15 10:02 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