Infrastructure as Code wint in rap tempo aan populariteit. Dit principe houdt in dat je de infrastructuur van je service aanstuurt vanuit bestanden in de service of direct gekoppeld aan de service. Voordelen hiervan zijn dat de configuratie inzichtelijk wordt gemaakt, dat deze gemakkelijk kan worden aangepast en dat de volledige infrastructuur vrij eenvoudig kan worden gemigreerd naar een andere cloud provider.
Bij Humanoids maken we ook graag gebruik van dit principe en bij voorkeur doen we dat met behulp van Kubernetes. In dit artikel laten we zien hoe je een eigen Kubernetes infrastructuur bij DigitalOcean kan opzetten.
Docker, Kubernetes en DigitalOcean
De volgende technieken komen allemaal aan bod om de cloud infrastructuur te realiseren. Voor de volledigheid vatten we iedere techniek hier kort samen.
Docker
Met Docker kunnen we een 'image' maken. Deze image wordt gemaakt via een Dockerfile. Dit is een set aan instructies waar stapsgewijs alle benodigdheden aan bod komen om de service te kunnen draaien; van het gebruik van een (klein) besturingssysteem als basis, tot het installeren van alle packages en zowel het bouwen, als opstarten van de service.
De image bevat dus alle bouwstenen en instructies die nodig zijn om een service mee te creëren. Je kan het daarom ook goed voorstellen als de template voor een service. De service die met het template wordt gebouwd leeft vervolgens in een Docker container. Vanuit deze container kan de service worden opgestart.
Kubernetes
Kubernetes stelt ons in staat om "containers te orkestreren". Het is een systeem voor deployment, automatische op- en afschaling en beheer van gecontaineriseerde apps.
Bij het gebruik van Kubernetes worden meestal drie componenten gedefinieerd: een 'deployment', een 'service' en een 'ingress'. Deze configuratiebestanden die worden opgeslagen zorgen dat 'pods', dat waar containers in worden opgeslagen, gecontaineriseerd worden in een 'node'. Dat is een server. En last but not least: een cluster. Dit is een verzameling nodes en ook hetgeen waar we alle eerder genoemde onderdelen in opzetten.
DigitalOcean
DigitalOcean is een cloud provider, vergelijkbaar met Amazon Web Services of Microsoft Azure. DigitalOcean is zeer populair omdat ze veel ‘value for money’ bieden en het gebruik van de diensten straightforward is. Zo kun je in een paar handelingen een Kubernetes cluster configureren.
Benodigdheden
Om aan de slag te gaan hebben we de volgende zaken nodig:
- een DigitalOcean account;
- Homebrew voor MacOS gebruikers of Chocolatey voor Windows voor het installeren van de verschillende CLI's;
- doctl CLI voor het beheren van het cluster;
- kubectl CLI om Kubernetes mee aan te sturen.
In DigitalOcean een Kubernetes Cluster opzetten
Allereerst gaan we een Kubernetes Cluster opzetten. Dit gaan we via de terminal doen. Hiervoor hebben we nog wel een Access token nodig van DigitalOcean. Eerst loggen we in bij DigitalOcean:
doctl auth init --access-token=<ACCESS_TOKEN>
Om onze eerste cluster te creëren gebruiken we het volgende in de terminal:
doctl kubernetes cluster create humanoids-k8s --region ams3
We hebben het cluster op deze manier humanoids-k8s genoemd en als regio hebben we ams3 (Amsterdam) gebruikt. Om lokaal onze configuratie op te slaan en de context aan te passen gebruiken we het volgende:
doctl kubernetes cluster kubeconfig save humanoids-k8s
Om de bestaande nodes te zien in de cluster gebruiken we:
kubectl get nodes
Nu hebben we iets om naartoe te deployen (het cluster op DigitalOcean). Als dit gebeurt is, moeten we ervoor zorgen dat we de bestanden die nodig zijn gaan creëren om alles binnen het cluster te organiseren.
Namespace
We geven een namespace mee, zodat we makkelijk voor verschillende omgevingen kunnen ontwikkelen. Deze is lekker kort:
# /kubernetes/namespace.prod.yamlapiVersion: v1kind: Namespacemetadata:name: production
Pas vervolgens de Namespace configuratie toe door het volgende te typen in de terminal:
kubectl apply -f ./kubernetes/namespace.prod.yaml -n production
Deployment file
Een 'deployment' is een instructie waarmee Kubernetes onze service gaat opzetten. We vertellen het waar het onze image kan vinden, zodat Kubernetes er containers van kan maken. Voor de scope van dit artikel gaan we de open source Nginx webserver image ophalen uit de Docker registry. Zo kunnen we direct testen of al onze Kubernetes instellingen goed staan.
# /kubernetes/deployment.prod.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: hello-humanoidsnamespace: productionlabels:app: hello-humanoidsspec:replicas: 1selector:matchLabels:app: hello-humanoidstemplate:metadata:labels:app: hello-humanoidsspec:containers:- image: nginxname: hello-humanoidsports:- containerPort: 80imagePullPolicy: Always
Er gebeurt hier niet zoveel spannends. De imagePullPolicy is ingesteld op 'Always' om ervoor te zorgen dat de containers die in production worden uitgevoerd, worden bijgewerkt bij elke nieuwe update van de image. Verder maakt iedere replica een nieuwe pod aan. Daar worden dus de Docker containers in opgeslagen.
Let op; de container port moet altijd overeenkomen met de port die je exposet in je Docker image
Pas de deployment configuratie toe:
kubectl apply -f ./kubernetes/deployment.prod.yaml -n production
Service
Een 'service' brengt de belasting voor pods in evenwicht. Het leidt gebruikers naar specifieke pods. Dus als een pod bezet is en er een andere pod beschikbaar is, zal de ingress het verkeer naar die pod leiden. Een service kan meerdere pods 'servicen', of slechts één.
# /kubernetes/service.prod.yamlapiVersion: v1kind: Servicemetadata:labels:app: hello-humanoidsname: hello-humanoidsnamespace: productionspec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: hello-humanoids
Dit maakt pods toegankelijk voor de ingress, nadat we deze hebben toegepast op onze cluster:
kubectl apply -f ./kubernetes/service.prod.yaml -n production
Ingress
Een 'ingress' bepaalt hoe het verkeer van de buitenwereld naar de services moet stromen. Je kunt bijvoorbeeld een front-end en een back-end-service opzetten, en de ingress zal het inkomende verkeer omleiden naar de juiste service.
Om de Ingress te laten functioneren moet er een Nginx Ingress Controller aangemaakt worden. Dat is het onderdeel dat achter de schermen zorgt voor deze routing. Installeer de Nginx Ingress Controller in onze cluster met behulp van Helm. Helm is een package manager voor Kubernetes services. MacOS gebruikers doen dit via het HomeBrew commando brew install helm en in Windows kan dit via het Chocolatey commando choco install kubernetes-helm.
Vervolgens configureren we deze en installeren we de controller:
helm repo add stable https://kubernetes-charts.storage.googleapis.comhelm install nginx-ingress stable/nginx-ingress --set controller.publishService.enabled=true
Nu kunnen we onze Ingress toepassen:
# /kubernetes/ingress.prod.yamlapiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:annotations:kubernetes.io/ingress.class: nginxnginx.ingress.kubernetes.io/rewrite-target: /$2name: hello-humanoids-guidenamespace: productionspec:rules:- host: voorbeeld.nl # Vul hier je eigen domeinnaam inhttp:paths:- backend:serviceName: hello-humanoidsservicePort: 80 # Port exposed by servicepath: /()(.*)
En pas deze configuratie dan weer toe toe via:
kubectl apply -f ./kubernetes/ingress.prod.yaml -n production
Als dit goed gaat zul je op je DigitalOcean dashboard zien dat er een nieuwe load balancer is aangemaakt. Door in het dashboard de load balancer te selecteren en op de titel te klikken kun je deze een herkenbare naam meegeven.
Als je nu via doctl een lijst opvraagt van de actieve clusters zul je zien dat het cluster dat we zojuist hebben aangemaakt hier tussen staat!
doctl kubernetes cluster list
Je service online zetten
Als laatste stap moet een DNS record worden aangemaakt zodat we een (sub)domein kunnen koppelen aan het Kubernetes cluster. Hiervoor moeten we het IP-adres van de load balancer weten. Je kunt deze achterhalen door het volgende commando uit te voeren:
kubectl -n production get ingress
Het IP-adres vind je onder het kopje “External IP”.
Nu je het IP-adres weet kan het DNS record worden toegevoegd. Ga hiervoor naar de beheeromgeving van je domein. Bij de DNS instellingen voeg je een A-record toe. Voer het (sub)domein in uit je ingress configuratie en laat deze verwijzen naar het IP-adres van de load balancer. Na het opslaan kan het even duren voordat de wijziging is doorgevoerd, verwijder eventueel je DNS cache. That’s all!