Neem contact op

Kubernetes Guide: DigitalOcean

Een guide die van A tot Z beschrijft hoe je een Kubernetes cluster in DigitalOcean opzet en services hiernaar deployt.

August 17, 2020
Cover image

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:

1doctl auth init --access-token=<ACCESS_TOKEN>

Om onze eerste cluster te creëren gebruiken we het volgende in de terminal:

1doctl 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:

1doctl kubernetes cluster kubeconfig save humanoids-k8s

Om de bestaande nodes te zien in de cluster gebruiken we:

1kubectl 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.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: production

Pas vervolgens de Namespace configuratie toe door het volgende te typen in de terminal:

1kubectl 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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-humanoids
  namespace: production
  labels:
    app: hello-humanoids
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-humanoids
  template:
    metadata:
      labels:
        app: hello-humanoids
    spec:
      containers:
        - image: nginx
          name: hello-humanoids
          ports:
            - containerPort: 80
          imagePullPolicy: 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:

1kubectl 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.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: hello-humanoids
  name: hello-humanoids
  namespace: production
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: hello-humanoids

Dit maakt pods toegankelijk voor de ingress, nadat we deze hebben toegepast op onze cluster:

1kubectl 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.com
2helm install nginx-ingress stable/nginx-ingress --set controller.publishService.enabled=true

Nu kunnen we onze Ingress toepassen:

# /kubernetes/ingress.prod.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: hello-humanoids-guide
  namespace: production
spec:
  rules:
    - host: voorbeeld.nl # Vul hier je eigen domeinnaam in
      http:
        paths:
          - backend:
              serviceName: hello-humanoids
              servicePort: 80 # Port exposed by service
18            path: /()(.*)

En pas deze configuratie dan weer toe toe via:

1kubectl 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!

1doctl 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:

1kubectl -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!



Ruben Werdmuller

Developer @Humanoids