Kubernetes biedt een robuust platform voor het beheren van containergebaseerde applicaties, en in dit hoofdstuk behandelen we hoe Kubernetes-manifesten worden toegepast, beheerd en geüpdatet om schaalbaarheid, flexibiliteit en veiligheid te waarborgen. Het gebruik van Kubernetes stelt ontwikkelaars in staat om applicaties efficiënt te implementeren en tegelijkertijd een hoge mate van betrouwbaarheid en beschikbaarheid te behouden.
Een essentieel aspect van Kubernetes is het gebruik van YAML-manifesten om verschillende componenten van de applicatie te beschrijven, zoals Deployments, Services, Ingress, ConfigMaps en Secrets. Deze manifesten worden gecreëerd om de gewenste staat van de applicatie in de cluster te definëren. Dit maakt het eenvoudiger om nieuwe versies van de applicatie uit te rollen, configuraties te beheren en de nodige geheimen zoals API-sleutels en wachtwoorden veilig op te slaan.
Wanneer manifesten eenmaal zijn geschreven, kunnen ze worden toegepast op de Kubernetes-cluster met behulp van de kubectl-tool. Dit stelt ontwikkelaars in staat om verschillende Kubernetes-bronnen in de cluster te creëren of bij te werken, zoals bijvoorbeeld kubectl apply -f deployment.yaml. Naast het toepassen van de manifesten, kunnen ontwikkelaars de status van de implementatie bekijken met commando’s zoals kubectl get deployments of kubectl describe deployment myapp, waarmee gedetailleerde informatie over de implementatie kan worden verkregen.
Een van de krachtigste functies van Kubernetes is het vermogen om rolling updates uit te voeren. Dit betekent dat nieuwe versies van de applicatie worden uitgerold met minimale downtime. Kubernetes zorgt ervoor dat nieuwe pods worden gestart, de gezondheid van deze pods wordt gecontroleerd en de oude pods geleidelijk worden beëindigd. Als er zich problemen voordoen, zoals mislukte gezondheidscontroles, wordt de update automatisch gepauzeerd en kan deze eenvoudig worden teruggedraaid. Het bijhouden van de geschiedenis van de rolling updates kan gedaan worden met kubectl rollout history deployment/myapp, en indien nodig kan een rollback worden uitgevoerd met kubectl rollout undo deployment/myapp.
Kubernetes biedt ook de mogelijkheid om het aantal replica’s van een bepaalde applicatie handmatig aan te passen. Dit kan handig zijn wanneer je de schaal van je applicatie snel wilt vergroten of verkleinen om pieken in het verkeer te ondersteunen. Dit kan eenvoudig worden gedaan met het commando kubectl scale deployment myapp --replicas=5. Als een snelle herstart nodig is, bijvoorbeeld vanwege een configuratiewijziging, kan de toepassing opnieuw worden opgestart met kubectl rollout restart deployment/myapp.
Naarmate de applicaties complexer worden, is het ook essentieel om de manifesten goed te organiseren en versiebeheer toe te passen. Het groeperen van manifesten in mappen, bijvoorbeeld k8s/deployment.yaml, k8s/service.yaml, k8s/ingress.yaml, k8s/configmap.yaml en k8s/secret.yaml, maakt het gemakkelijker om ze te beheren, vooral als ze onderdeel zijn van een groter CI/CD-pijplijnproces. Veel teams slaan deze manifesten op in Git-repositories, waardoor wijzigingen op een gecontroleerde manier kunnen worden toegepast via pull requests en CI/CD-pijplijnen. Dit maakt de infrastructuur volledig versiebeheerd, herhaalbaar en auditbaar.
Het beheren van secrets binnen Kubernetes is van cruciaal belang voor het waarborgen van de veiligheid van de applicatie. Een voorbeeld hiervan is het gebruik van base64-gecodeerde waarden in de secret.yaml-manifesten, waarin gevoelige informatie zoals databasetoegang wordt opgeslagen. Deze informatie moet zorgvuldig worden beheerd, bijvoorbeeld door middel van het gebruik van veilige omgevingsvariabelen en de juiste encryptie-algoritmes. Kubernetes ondersteunt de encryptie van deze secrets, maar het is aan de ontwikkelaar om de juiste beveiligingsmaatregelen te implementeren om de gegevens tijdens de opslag en overdracht te beschermen.
Een ander belangrijk aspect van Kubernetes is het vermogen om de prestaties van de applicatie te monitoren. Door het gebruik van ingebouwde Kubernetes-dashboardfuncties en logaggregatie via tools zoals de ELK-stack (Elasticsearch, Logstash, Kibana), kunnen ontwikkelaars snel inzicht krijgen in de gezondheid en prestaties van hun applicaties. Logs van pods zijn direct toegankelijk, en elke verandering in de schaal of implementatie van de applicatie kan eenvoudig worden uitgevoerd door de YAML-bestanden bij te werken en opnieuw toe te passen. Dit zorgt voor een beheerbare, herhaalbare en schaalbare infrastructuur.
Het werken met Kubernetes stelt ontwikkelaars in staat om hun applicaties op een robuuste en veilige manier te schalen. Door gebruik te maken van Kubernetes-manifesten en de daarbij behorende commando’s kunnen applicaties efficiënt worden geconfigureerd en beheerd. Bovendien kunnen updates snel en zonder downtime worden uitgevoerd, terwijl de veiligheid van de applicatie wordt gewaarborgd door het zorgvuldig beheren van secrets en configuraties.
Wat belangrijk is om te begrijpen naast de basisprincipes van Kubernetes-implementaties:
-
Beveiliging van secrets: Het beheer van gevoelige gegevens zoals API-sleutels, wachtwoorden en andere vertrouwelijke informatie is cruciaal voor het waarborgen van de integriteit van de applicatie. Gebruik van encryptie voor secrets en veilige opslagmethoden is essentieel.
-
CI/CD-integratie: Het integreren van Kubernetes-manifesten in een CI/CD-pijplijn maakt het mogelijk om geautomatiseerde tests, implementaties en rollbacks uit te voeren, wat bijdraagt aan een snellere en betrouwbaardere ontwikkelingscyclus.
-
Monitoring en logging: Voor schaalbare en betrouwbare applicaties is het belangrijk om de juiste monitoring- en loggingtools te implementeren. Kubernetes biedt zelf enkele ingebouwde tools, maar het integreren van externe tools zoals de ELK-stack kan helpen bij het verkrijgen van diepere inzichten in de prestaties van de applicatie.
-
Schaalbaarheid en fouttolerantie: Kubernetes maakt het mogelijk om de applicatie snel te schalen afhankelijk van de vraag. Door gebruik te maken van automatische schaling en het beheren van resources op de juiste manier, kan een applicatie veerkrachtig blijven, zelfs onder hoge belasting.
Hoe schrijf je effectieve Pytest-functies voor een robuuste testomgeving?
Bij het schrijven van testfuncties in Pytest is het belangrijk te begrijpen hoe je pure functies test en hoe je setups en mockings effectief kunt toepassen om betrouwbare en snelle tests te creëren. Pytest is een krachtige testtool voor Python die een aantal geavanceerde mogelijkheden biedt voor zowel unit testing als integratietests, en biedt daarbij uitgebreide foutmeldingen en een flexibele manier om afhankelijkheden te mocken.
Het testen van “pure” functies, functies zonder bijwerkingen of externe afhankelijkheden, is de basis van het testen in Pytest. Pytest ontdekt automatisch alle bestanden die eindigen op test_*.py of *_test.py en zoekt naar functies die beginnen met test_. Deze testfuncties moeten normale Python-functies zijn, voorzien van reguliere assert statements. Als voorbeeld, stel je voor dat we een eenvoudige wiskundige functie willen testen uit utils/math_utils.py:
Om deze te testen, maken we een bestand aan genaamd tests/test_math_utils.py:
Wanneer je Pytest uitvoert vanaf de root van het project, worden alle tests automatisch ontdekt en uitgevoerd. Pytest rapporteert elke test met een gedetailleerde en leesbare output, en biedt uitgebreide stacktraces en variabele waarden voor mislukte assertions, waardoor het makkelijker wordt om de oorzaak van een mislukking te achterhalen.
In veel gevallen moeten tests echter interactie hebben met externe systemen, zoals een database, een bestandssysteem of een netwerkverbinding. Dit vereist extra setup en teardown logica. Pytest biedt een ingebouwd fixturesysteem waarmee je herbruikbare en parameteriseerbare setuplogica kunt definiëren die kan worden geïnjecteerd in testfuncties. Neem bijvoorbeeld de situatie waarin we een tijdelijke bestand willen creëren voor een test. We definieëren een fixture in tests/conftest.py:
Deze fixture wordt vervolgens gebruikt in de test zelf:
Pytest garandeert dat de fixture correct wordt opgezet voor de test en wordt opgeruimd na afloop, zelfs als de test faalt. Fixtures kunnen verschillende scopes hebben (functie, module, sessie), en kunnen afhankelijk zijn van andere fixtures, wat zorgt voor krachtige en flexibele setupmogelijkheden.
Wanneer je een functie test die afhankelijk is van externe diensten, zoals een API-aanroep of het verzenden van een e-mail, is het vaak gewenst om die externe afhankelijkheid te mocken. Dit zorgt ervoor dat de test snel en betrouwbaar blijft, zonder dat je afhankelijk bent van externe services die mogelijk niet beschikbaar zijn. Pytest integreert naadloos met Python’s ingebouwde unittest.mock bibliotheek. Stel dat we een e-mailfunctie hebben in utils/email_utils.py:
In de test willen we de send_email functie niet daadwerkelijk aanroepen, maar we willen wel controleren of notify_user de e-mailfunctie op de juiste manier aanroept. Dit kunnen we doen door send_email te mocken:
Hier zorgt patch ervoor dat send_email wordt vervangen door een mock gedurende de scope van de with-block. We controleren dan of de mock met de verwachte argumenten is aangeroepen, wat bevestigt dat de logica van de notify_user functie correct werkt, zonder een echte e-mail te versturen.
Wanneer we testen afhankelijkheden die met externe bronnen werken, zoals omgevingsvariabelen, tijd of willekeurige waarden, biedt Pytest de monkeypatch functie waarmee je deze waarden tijdelijk kunt aanpassen voor de duur van een test:
Naast unit tests is er een belangrijke categorie test die we moeten overwegen: integratietests. Integratietests controleren of verschillende systeemcomponenten goed samenwerken in een productieomgeving. Ze maken gebruik van echte services, zoals databases en API’s, en helpen om bugs op te sporen die alleen verschijnen wanneer gegevens door verschillende lagen gaan. Deze tests zijn doorgaans trager dan unit tests, maar ze bieden meer vertrouwen bij het uitrollen van nieuwe versies en helpen bij het opsporen van misconfiguraties of regressies.
Om een gecontroleerde en herhaalbare testomgeving voor integratietests te creëren, kunnen we gebruik maken van Docker en Docker Compose. Door testcontainers te gebruiken, kunnen we bijvoorbeeld snel een Redis-dienst starten en stoppen voor iedere testuitvoering. Met Docker Compose kunnen we een YAML-bestand definiëren, zoals docker-compose.test.yml, dat onze testomgeving opzet:
Na het opstarten van de service met docker compose -f docker-compose.test.yml up -d, kan deze verbinding maken met onze tests, en na afloop worden de services weer netjes gestopt en opgeruimd met docker compose -f docker-compose.test.yml down -v.
In veel gevallen willen we volledige API-aanroepen uitvoeren om integratietests te valideren. Hiervoor biedt FastAPI een ingebouwde TestClient, waarmee we HTTP-verzoeken kunnen doen naar de app en de resultaten kunnen controleren zonder dat we afhankelijk zijn van een werkelijke client of netwerk:
Met dergelijke integratietests kunnen we ervoor zorgen dat de verschillende onderdelen van de applicatie naadloos samenwerken zoals ze zouden doen in een echte productieomgeving.
Hoe Johann Hieronymus Schroeter de Selenografie Vormde en de Mythe van de Maansystemen Creëerde
Wat is de rol van hypocrisie in publieke debatten en besluitvorming?
Hoe werkt akoestische communicatie in vergelijking met traditionele draadloze technologieën?
Wat zijn de gevolgen van onverwachte veranderingen in het leven voor jonge mensen in stressvolle situaties?

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский