Skip to main content

Kubernetes: oefening 2

In de eerste oefening lag de focus op het werken met een aantal van de basis-features in kubernetes. Je zou daardoor al een behoorlijk goed zicht moeten hebben op de verschillende entiteiten die je kan aanmaken, zoals deployments, services, persistent storage.

Eén van de features die Kubernetes zo geliefd maakt, zijn de vele deploymentopties én mogelijkheden zoals rolling updates. Daarmee kan je updates geleidelijk over je infrastructuur verspreiden. In dit lab demonstreren we dit.

De setup die we maken is er één waarbij we een triviale webapp deployen die gelinkt is aan een source repository. We bouwen daarbij ook een heel eenvoudige CI stap: elke push met nieuwe code zal een nieuwe container genereren.

De bezoeker van onze eenvoudige site zal connecteren met een http(s) load balancer en via die weg op de website terecht komen.

Schematisch:

graph TD; A([user]) --> NLB[Load balancer /ingress]; NLB --> SVC[service]; SVC --> DEPLOYMENT[deployment]; DEPLOYMENT --> AR; REPO[source repository]-->|cloud build trigger|AR[artefact registry];

Om dit mogelijk te maken is eerst wat setup nodig, die we stap voor stap zullen doorlopen.

Een overzicht van de stappen:

Stap 1 tem 4 deed je vermoedelijk al eerder in het lab rond terraform en moet je dus niet herhalen.

  • Stap1: kloon de helloGhent repository die je op GitLab kan vinden naar je lokale pc.
  • Stap2: maak een cloud source repository aan in je Google cloud project.
  • Stap3: koppel een remote aan je lokale repository die je toelaat om te pushen naar Google Cloud source repositories
  • Stap4: activeer en configureer je artifact registry
  • Stap5: maak een cloudbuild configuratie aan
  • Stap6: maak een trigger aan in CloudBuild zodat een push resulteert in een nieuwe docker image
  • Stap7: maak een K8S deployment
  • Stap8: maak en expose de service via een ingress object
  • Stap9: test/demonstreer autoscaling door zelf load te veroorzaken. Dat kan je doen met een éénvoudig scriptje of met bvb Locust.
  • Stap10: test/demonstreer rolling updates
tip

In de opgave gaan we de cloud source repositories gebruiken van Google. Die vormen een heel erg basic manier om broncode te beheren. Platformen als GitHub zijn een pak uitgebreider, en kunnen ook gekoppeld worden. Voor de eenvoud van de opgave doen we dat niet...

Stap1 Kloon de app-repo naar je eigen pc

Dit behoeft weinig uitleg, je vindt de repository op gitlab.com/ikdoeict/

Stap2 & 3: Maak & koppel een cloud source repository

Stap 2: maak een cloud source repository

We maken nu een git repository aan in Google Cloud. Dit kan je vergelijken met een project in Gitlab, maar dan gehost door Google Cloud.

Cloud source repo

Stap 3: koppel een remote aan je lokale repository.

Het spreekt voor zich dat je je lokale (public!) ssh key zal moeten importeren in het Google Cloud project. Volg de instructies daarvoor aandachtig..

Je zal dus een remote moeten toevoegen aan je lokale repository.

Als dat lukt, zou het mogelijk moeten zijn om te pushen vanop je lokale computer naar je nieuwe repository...

PS C:\Users\RoelVanSteenberghe\GIT\helloghent> git push google main
Enter passphrase for key '/c/Users/RoelVanSteenberghe/.ssh/id_rsa':
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 16 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), 1.24 KiB | 636.00 KiB/s, done.
Total 10 (delta 0), reused 0 (delta 0), pack-reused 0
To ssh://ikdoeict.be@source.developers.google.com:2022/p/labkubernetes-331108/r/hello-ghent
* [new branch] main -> main

Stap4: activeer en configureer de artefact registry

Een andere schakel die we nodig hebben is een artefact registry. Dat is een private 'repository' binnen Google Cloud waar je bijvoorbeeld gebouwde docker containers kan plaatsen. (maar ook bijvoorbeeld RPM packages, DEB packages, ...)

Activeer daarvoor eerst en vooral de api op (via deze link)

Maak daarna binnen de registry een repository aan van het type docker. Projectnaam mag je uiteraard kiezen, locatie wordt europe-west-1.

Stap5: Maak een cloudbuild config aan

Net zoals je in Gitlab gitlab-ci.yml files kan aanmaken om een ci/cd pipeline op te starten, kan je dit ook doen in Google Cloud. Helaas is er nog geen standaard voor de syntax daarvan, dus die wijkt sterk af voor bijvoorbeeld Gitlab, GitHub en dus ook Google Cloud.

Bij Google Cloud zal je een cloudbuild.yml file moeten toevoegen.

Met onderstaand voorbeeld kan je vermoedelijk verder; vergeet niet om de id van je project aan te passen...

steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'europe-west1-docker.pkg.dev/labkubernetes-331108/helloghent/main:v1', '.' ]
images:
- 'europe-west1-docker.pkg.dev/labkubernetes-331108/helloghent/main:v1'

Stap 6: maak een build trigger aan

Met de net aangemaakte CloudBuild configuratie én de artefact registry kunnen we aan de slag: bij elke push naar onze repository willen we een container bouwen en plaatsen in de registry. Daarvoor hebben we Google Cloud Build nodig.

Maak daar een trigger aan. Let op de details (vb juiste branch naam, extensie van cloudbuild(.yml vs .yaml))

Add trigger

Test dit uiteraard goed. Een push naar de repository moet ook een nieuwe container bouwen.

::⚠️ De kans is groot dat je build zal falen omdat rechten nog niet overal goed ingesteld staan. Bekijk de melding aandachtig, en los dit probleem uiteraard ook op vooraleer je verder gaat. :::

Stap 7: maak een deployment

Maak in je cluster een nieuwe deployment aan. Dat kan terug met kubectl, maar het is ook mogelijk om dit met de cloud console te doen. Je krijgt dan een wizard te zien die je door de mogelijkheden gidst én de resulterende yaml genereert.

deploy workload

Maak deze deployment in een nieuwe namespace helloghent.

Stap 8: maak en expose de service

Dit komt vermoedelijk niet onverwacht: na het aanmaken van de deployment, is het ook nodig om die extern bereikbaar te maken. Deze keer doen we dat wel via de regels van de kunst: via een ingress object.

Eerst moet dus wel nog een service voorzien worden:

---
apiVersion: "v1"
kind: "Service"
metadata:
name: "helloghent-main-service"
namespace: "helloghent"
labels:
app: "helloghent-main"
spec:
ports:
- protocol: "TCP"
port: 80
targetPort: 80
selector:
app: "helloghent-main"
type: "NodePort"

Bemerk dat we deze van het type "nodeport" maken. Deze zal dus bereikbaar zijn buiten de cluster. We willen ook specifiek een http(s) load balancer, waarvoor een ingress object nodig is.

Maak dus ook zo'n ingress object aan. (alweer, dit kan zowel grafisch als via kubectl) Daarmee zal een http load balancer aangemaakt worden in gcp. Dat kan een poosje duren. De load balancer zal dan steeds kijken welke services actief zijn om de load te verdelen.

De kans is groot dat dit in eerste instantie faalt, omdat de backend als 'not healthy' gerapporteerd wordt. Dat is uiteraard wel zo, maar de firewall blokkeert die health checks by default. Die zal je dus nog moeten openen. In de documentatie vind je hoe je dat kan doen.

Ga niet verder voordat je service extern bereikbaar is.

Stap 9: test autoscaling

de webapplicatie die we gebruikten heeft een endpoint /calculatepi die voor een vertraging van 1 seconde zorgt bij een request. Werk zelf een scenario uit waarmee je kunstmatig load gaat toevoegen (daar zijn tools voor zoals jmeter, ab) om autoscaling te testen.

Dit commando kan je ongetwijfeld helpen:

kubectl autoscale deployment shell --min=2 --max=10 --cpu-percent=10
horizontalpodautoscaler.autoscaling/shell autoscaled
tip

Maak uitgebreid notities van hoe je dit testte. Dit zal namelijk ook moeten gedemonstreerd worden op het evaluatiemoment.

Stap 10: rolling updates

Schaal de webservice naar 10 pods. Pas daarna de app aan en voer een rolling update uit.

tip

Kies voor een visuele wijziging (wijziging tekst of kleur in output), zodat je heel snel verschillende versies kan onderscheiden. In je browser kom je door te refreshen steeds weer (round-robin) op andere nodes. Door snel te refreshen zal je de wijzigingen dus ook live kunnen zien doorvoeren.

Alweer enkele commando's om je op weg te zetten:

kubectl set image deployment/xxxx xxxx
kubectl rollout status <xxx> -n xxxx

Stel dat er toch problemen bemerkt worden met de rollout, met welk commando kan je dan de vorige image terugzetten?

tip

Ook hier: maak uitgebreid notities van hoe je dit testte. Dit zal namelijk ook moeten gedemonstreerd worden op het evaluatiemoment.