De lifecycle van een pod en debug containers
Stel, ik heb een Kubernetes Cluster draaien en al mijn pods staan op running. Maar ik ben eigenlijk ook wel benieuwd naar wat er gebeurt als de pod opstart. In deze blog gaan we in op de lifecycle van een pod.
Kubectl describe pod
'Kubectl describe pod' is het commando waarbij ontzettend veel informatie te zien is. Je krijgt hierbij ook de events van de pod te zien. Standaard zal Kubernetes één uur lang de events vasthouden, daarom zal je niet altijd wat zien. Je kan deze setting op de API server aanpassen, mits je niet in een cloud draait. Daar kun je dit niet aanpassen. Je zou dan met een event exporter kunnen werken. Een goede keuze is die van caicloud, deze zal de events doorsturen naar Prometheus. Maar in praktijk kijk je naar de events als het start. En als de pod er al langer staat, dan gooi je de pod weg en dan heb je weer een kans om te kijken.
Status pending
Stel de pod is helemaal opgestart, maar je wilt de applicatie logging zien, dan kan je kubectl logs gebruiken. Deze zal de applicatie logging weergeven mits de logging naar stdout geschreven wordt. Als een pod start, dan moet Kubernetes een plekje voor hem zoeken in het cluster. De scheduler gaat op zoek naar de juiste plek op basis van de opdrachten die mee zijn gegeven. Dit is dan de status 'pending'. In de events zal je dan zien dat hij scheduled event krijgt. Dan heeft hij nog status 'pending' als hij de containers die in de pod zitten aan het downloaden is. Hij gaat ze eerst downloaden en als ze aanwezig zijn dan krijgt hij de status 'Initialized en zal hij de init pod’s uitvoeren.
Status waiting
Soms staat de pod te lang te wachten, dan krijgt hij de status 'waiting'. Dit kan meerdere oorzaken hebben, zoals het missen van configuratie tot dat hij de container niet kan downloaden. Maar dat is nooit goed. Als het wel goed gaat, dan krijg je events voor elke container dat hij Pulling is en als ze gePulled zijn. Als de container gepulled is dan kan hij de Docker registery vinden. Nu staat de container op de node waar de pod zal starten. Hierna zal de container maken en proberen te starten met dus de events Created en Started. Als dit allemaal gelukt is dan zal de status naar 'Running' gaan. We hebben dan een werkende pod.
Status completed
Hoe kun je zien dat alles omtrent het starten van de container goed is gegaan? Dan zie je de container op 'Completed' staan, dit is een pod die een taak heeft en daarna klaar is. Dus in praktijk is dat vaak een script die op een bepaalde tijd gestart wordt. Als mijn job verkeerd gaat, kan ik dat dan zien? Zeker, in de standaard config laat hij vijf oude jobs staan, maar dit kan je natuurlijk helemaal aanpassen. Dit is natuurlijk een happy flow, dus als alles goed gaat.
Status terminated
Als het misgaat, welke meldingen krijg ik dan? Voor jobs is dit de status 'Terminated', hieraan kan je zien dat je job niet goed gegaan is. Voor pods kan je aan de volgende statussen zien dat het niet goed gaat. Als de status Failed en CrashLoopBackOff is, dan is er bij 1 of alle containers iets misgegaan. Dus kan je met Kuberctl logs kijken wat er misgegaan is. Stel het docker image is niet beschikbaar, dan zal hij de status Errimgpull geven.
Status Unknown
Welke melding krijgt de pod als de node niet meer beschikbaar is? Als een node na 5 minuten niet reageert, dan zullen alle pods op een andere node gestart worden. En dan krijgen de pods van die andere node de status 'Unknown'. Je kunt natuurlijk deze reactietijd aanpassen.
Dan heb je nog algemene Errors, dan gaat er iets mis waar geen status voor is. Als een node vol zit, wat gebeurt er dan met de containers? Een node kan op drie manieren vol zitten: op basis van de CPU, het geheugen en/of de lokale disk. Het geheugen is opgedeeld in twee soorten huge pages en het normale geheugen. Maar de huge pages moet je speciaal op een node aanzetten. Als je kijkt op een node dan zie je ephemeral-storage, dit is de lokale storage. Als deze op 80% is dan gaan pods verschuiven. Dit zie je dan terug als evicted pods. Er zijn nog meer statussen, maar dit zijn wel de belangrijkste.
Debug container en debuggen van containers
Voor de security is het slim je container niet actief te hebben als root. Maar je hebt dan meer de uitdaging dat het lastig debuggen is. Je kunt geen software installeren. En als je een distoless container hebt, dan is het helemaal niet mogelijk. Een distroless container is een container zonder extra tooling, dus daar zit alleen maar in wat precies nodig is. Maar dus dan ook geen OS of onderdelen van het OS. Google gebruikt deze manier van containers al heel lang.
Want zodra jij een zoekopdracht start, zal Google een container voor je starten. En zodra de container klaar is met een resultaat dan is de container weer weg. Omdat hij zo klein is, start hij super snel op, maar is ook weer heel snel weg. Er zijn voordelen aan het gebruik van kleine containers, zoals minder onderdelen die te hacken zijn en een lagere kans op 0-day security gaten. Het is echter niet altijd handig om een container helemaal leeg te maken en alles er zelf in te zetten, omdat dit kan leiden tot grotere containers en meer onderhoud.
Er zijn oplossingen beschikbaar om kleine containers te maken, zoals static-debian11 en alpine. Het is makkelijk om te debuggen op een cluster, maar de controle kan beperkt zijn als je werkt met een grote cloudprovider. Wat kan je niet op de grote cloud wat je in een private cloud wel kan doen? Het is lastiger om in te loggen op een node in de cloud en soms is dat onmogelijk. Je kan soms hiervoor een container starten en de disk mounten met het docker process. Maar dat gaat niet altijd goed. Soms wil je gewoon op de node inloggen. Vanuit de node kan je met een docker exec als root inloggen in je docker. En als je dan root in de container bent, en er zit een distro in de container, dan kan je software installeren zoals telnet of ping. Als je al Kubernetes al geüpgraded hebt boven versie 1.23, dan hebben we de optie om een debug container te starten. Dit is een extra container in de pod met andere rechten en andere tools. Deze komt in dezelfde "adres space", dus hij werkt vanaf hetzelfde IP adres. aangezien hij in de pod zit. Met een debug pod kan je het draaiende proces zien en interacteren. Ook kan je de disk van de andere container zien. Maar wel een beetje op een gekke plek. Deze vind je onder /proc. Als je met ps kijkt wat het proces nummer van de container die je wilt controleren. Dan kan je dus op /proc en dan proces nummer de root disk vinden. Maar het is allemaal best complex. In de praktijk gebruiken we dit weinig. Vaak stap ik gewoon in de normale container met een exec.
Starten van een debug container
Je kunt als volgt een debug container starten:
kubectl debug -it applicatie --image=busybox:1.28 --target=applicatie
Hiermee maak je een container in de pod, dat kan je met een kubectl describe zien. Als je per ongeluk uit de container valt dan kan je attachen, want het duurt even voordat die container weer weg is. Stel je wil het in dezelfde container een proces naast je huidige container starten? Je kunt in de huidige container niet een proces ernaast starten, je start dan een nieuwe pod. Waarbij de 2 processen in 1 container komen. Je kan dus direct interacteren met het proces. Dat doe je door:
kubectl debug -ti applicatie--image=busybox --share-processes=true --copy-to='applicatie'
Je start een nieuwe container met een gedeeld process, zodat je het process kan zien in de container. Soms is het nodig voor software om elkaar te zien en interactie met elkaar te hebben dus kan je in je deployment aangeven shareProcessNamespace: true onder spec zetten in de deployment, dan krijg je de volgende zaken:
1. het container process heeft niet langer pod 1
2. de processen zijn zichtbaar voor alle containers in de pod
3. je kan de andere container disk zien via /proc/$pid/rootIn de praktijk gebruik je dit bijna niet voor standaard container processen.
Sommige software werkt alleen maar op deze manier. Bijvoorbeeld bij software voor brokers, die wilden het automatiseren. Dit kon alleen maar via directe interactie met de applicatie. Dus hadden ze een extra proces hiervoor in de container nodig. Niet alles kan zomaar met debug containers. Je kan geen poorten openzetten en er zijn nog andere afhankelijkheden, zoals:
· Ze kunnen niet herstarten zoals een normale container
· Je kunt geen resources definiëren
· Er kunnen geen proces op en ook geen probes op