Een developer-vriendelijk Kubernetes platform creëren met GitOps

auteursafbeelding
Jos van Bakel
26 mei 2023 Clock 8 min

Dit artikel is oorspronkelijk gepubliceerd op Devhouse Spindle op 4 augustus 2022. Wil je graag de Engelse versie lezen, bekijk dan de blog op onze Engelse site.

Na de eerste masterclass van ons dev event was het tijd om onze kennis over GitOps te delen. Om alle developers in staat te stellen met het microservices platform te werken, heeft ons infra team een template gemaakt waarmee ontwikkelaars zelf makkelijk een nieuwe service kunnen maken en deployen zonder tussenkomst van infra. In dit artikel lees je hoe we dit hebben gedaan en hoe we de complexiteit van Kubernetes voor developers hiermee hebben verhuld.

Wat is GitOps?

GitOps lijkt op DevOps, maar GitOps wordt gebruikt voor infrastructuur. Deze infrastructuur wordt volledig beschreven door configuratiebestanden. Om de huidige staat van de infrastructuur te vergelijken met de gewenste staat (zoals die beschreven staat in de configuratiebestanden), wordt een tool gebruikt. Deze tool voert een aantal acties uit om de gewenste en de huidige toestand op elkaar af te stemmen. Dit wordt gewoonlijk “infrastructuur als code” genoemd, aangezien de configuratiebestanden kunnen worden gerepresenteerd of gegenereerd door code.

De voordelen van infrastructuur als code

Waarom zou je al die moeite doen om je infrastructuur zo op te zetten? Omdat infrastructuur als code een groot aantal voordelen heeft:

  • Consistentie: de echte infrastructuur kan worden gecontroleerd – en afgestemd – op wat er in code is geschreven.
  • Reproduceerbaar: het is heel eenvoudig om de infrastructuur te repliceren naar een andere locatie.
  • Schaalbaarheid: als gevolg van de reproduceerbaarheid kan opschaling makkelijker zijn (afhankelijk van de usecase).
  • Modulair: best practices van programmeren kunnen worden toegepast, zoals het gebruik van modules om gemeenschappelijke patronen te abstraheren.
  • Samenwerking: meerdere mensen kunnen samenwerken aan een verandering (in code).
  • Codeerstandaarden: syntax highlighting, formattering, linting, testen, code reviews, etc.
  • Documentatie: moeilijke delen van de infrastructuur kunnen worden gedocumenteerd, met bijvoorbeeld de reden voor een keuze, of het uitleggen van een moeilijke flow.
  • CI/CD: wijzigingen kunnen worden getest in CI in een testomgeving, en CD kan worden gebruikt om wijzigingen automatisch uit te rollen naar de echte omgeving.

De code opslaan in een Git repository

GitOps is niet alleen infrastructuur als code. Zoals de naam al aangeeft, heeft het ook iets te maken met Git. Het is misschien triviaal, maar het idee is dat de infrastructuur van code wordt opgeslagen in een Git repository. Dit zorgt ervoor dat er een geschiedenis is van veranderingen aan de infrastructuur en het biedt een solide manier om samen te werken. Meer specifiek dicteert GitOps dat elke verandering wordt gemaakt (gedeployed) door gewoon een git commit te doen. De hele pijplijn van testen, reviewen, etc. tot de uiteindelijke implementatie moet worden geautomatiseerd met CI/CD. Het idee is dat de enige ingang om veranderingen in de infrastructuur aan te brengen Git is.

Wat we bedoelen met GitOps

In ons microservice platform gebruiken we het woord GitOps niet alleen om de workflow te beschrijven zoals hierboven is uitgelegd, we gebruiken het om het hele microservice platform te beschrijven. Het microservice platform is een platform-as-a-service (PaaS), gebouwd met in gedachten developers zonder kennis van infrastructuur of operations. We wilden een platform bouwen met moderne technologieën, zonder de gebruikers van het platform te belasten met het leren van al deze technologieën. We deden dit door niet alleen GitOps te gebruiken voor de infrastructuur zelf, maar ook voor de diensten die op het platform worden ingezet.

Een van de doelen van ons microservice platform is om teams in staat te stellen hun eigen DevOps te doen. Het creëren en inzetten van een nieuwe dienst vereist weinig kennis van de onderliggende technologieën en – ook belangrijk – vereist nul interactie met het infrateam. Andere aspecten van DevOps zoals monitoring, alerting, dashboarding, loginspectie en meer, worden allemaal automatisch geconfigureerd door de GitOps workflow. Ontwikkelaars hebben zelf toegang tot de tooling. Dit stelt teams in staat om eigenaar te zijn van hun dienst, van ontwikkeling tot inzet en onderhoud. Het vermindert ook de werkdruk op het infrateam en neemt hen gedeeltelijk weg als knelpunt, zodat de ontwikkeling van het platform niet wordt vertraagd.

Een overzicht van het microservice platform

De volgende afbeelding geeft een high level overzicht van het microservice platform:

De basis

Het huidige platform is gebouwd op de AWS-cloud. We hebben geprobeerd het platform zo cloud agnostisch mogelijk te bouwen, zodat we de flexibiliteit hebben om naar een andere cloud over te stappen of het platform zelfs on-premise te verplaatsen (wat uiteindelijk ons doel is).

Kubernetes draait bovenop de cloud, of on-premise infrastructuur. Voorlopig gebruiken we AWS EKS. Naast Kubernetes zijn er de nodige netwerkcomponenten (load balancers) en optionele databases die niet op Kubernetes worden gehost.

ArgoCD en Vault worden bovenop Kubernetes geleverd, en samen met wat andere kerncomponenten (Ingress-NGINX, cert-manager, etc.) vormt dit het basisplatform. Terraform wordt gebruikt om de basis te leveren en te onderhouden, het kan de infrastructuur vanaf het begin leveren (op een paar handmatige handelingen na, in verband met privacy en DNS). Dit stelt ons in staat om snel op te schalen naar andere regio’s, of in rampscenario’s de hele infrastructuur te slopen en opnieuw op te bouwen.

Platformdiensten

ArgoCD – geleverd in de basislaag – kan het nu overnemen van Terraform bij het leveren van verdere platformdiensten. Iets verderop zal ik uitleggen wat ArgoCD is, zie het voor nu maar als Terraform op Kubernetes.

In deze laag worden alle aanvullende platformdiensten – die niet nodig zijn bij het bootstrappen – geprovisioned. Dit omvat, maar is niet beperkt tot:

  • Prometheus (monitoring)
  • Grafana en Kiali (dashboarding)
  • Istio (service mesh)
  • Jaeger (tracing)
  • Crossplane (beheerde databases buiten Kubernetes)
  • NATS (central messaging bus)
  • Vault (geheimen)

Voor deze diensten heeft provisioning met ArgoCD om meerdere redenen de voorkeur boven Terraform:

  • Dezelfde GitOps flow wordt gebruikt voor platform- en eindgebruikersdiensten
  • De feedbackcyclus is veel korter
  • ArgoCD heeft geen Terraform state
  • ArgoCD draait continu

Kubernetes begrijpelijk maken

Kubernetes is gebouwd met een eenvoudig idee: je vertelt het welke resources je gedefinieerd wilt hebben in YAML-bestanden, en Kubernetes zorgt ervoor dat de resources er ook daadwerkelijk zijn en blijven. Een resource kan van alles zijn. Kubernetes is voornamelijk gebouwd rond containerorkestratie, dus de belangrijkste resources zijn dingen in en rond containers. Kubernetes is echter niet beperkt tot deze resources. Door Custom Resource Definitions (CRD’s) te definiëren en controllers in te zetten, kan Kubernetes worden uitgebreid met vrijwel elke resource. Hoewel het idee eenvoudig is, kan het bouwen van dingen in Kubernetes complex zijn. Dat komt omdat je domeinkennis nodig hebt om de resources te schrijven. En om het nog ingewikkelder te maken, kan het domein worden uitgebreid met CRD’s. Die last willen we developers niet opleggen.

Kubectl is het nieuwe ssh. Beperk de toegang en gebruik het alleen voor deployments als er geen betere tooling beschikbaar is.

Kelsey Hightower

Helm is een nuttige abstractie over Kubernetes YAML’s om het modulair en meer DRY te maken. Het probleem blijft echter dat je nog steeds domeinkennis van Kubernetes-resources nodig hebt. Helm code kan ook erg lastig zijn om goed te krijgen: fouten maken in YAML, uitgebreid met Go templating, is maar al te gemakkelijk.

De oplossing die we voor dit probleem hebben ontwikkeld is een holodeck-service Helm template (chart).

Een Helm-template voor developers

Alle diensten die op ons microservice platform worden ontwikkeld, gebruiken de holodeck-service Helm template. De template stelt ontwikkelaars in staat om configuratievariabelen in te stellen (via omgevingsvariabelen), geheimen in te laden (vanuit Vault), een database-instantie aan te vragen (via Crossplane), en nog veel meer. Het enige wat developers moeten weten zijn de beschikbare parameters in de Helm template. De template genereert de benodigde Kubernetes YAML voor de dienst. De complexiteit van Kubernetes wordt nu voor de ontwikkelaar verborgen door de abstractie. Ons infrateam heeft kennis van Kubernetes en diverse andere infrastructuurcomponenten. Met deze kennis onderhouden en voegen ze functies toe aan de Helm template, waardoor functies via parameters beschikbaar komen voor developers.

global:
domain: services
service: python-example

holodeck-service:
secrets:
enabled: true
envVarsFromVault:
WEATHER_API_KEY: WEATHER_API_KEY
FASTSTREAM_CREDS: FASTSTREAM_CREDS

envVars:
SENTRY_DSN:
value: ""
WEATHER_BASE_URL:
value: "<https://api.openweathermap.org>"

ingress:
rewrite: true

postgres:
enabled: true
storage: 10 # GiB

migrate:
command: ["alembic", "upgrade", "head"]

redis:
enabled: true

helm/values.yaml

ArgoCD als de oplossing

Diensten kunnen nu worden ingezet op Kubernetes met Helm. Concreet konden we vanuit de GitLab CI-pijplijn Helm upgrade aanroepen om te deployen. We kwamen een paar problemen tegen met deze aanpak:

  • De CI heeft referenties nodig naar Kubernetes en naar onze private Helm repository.
  • De meeste implementaties moeten in verschillende stappen gebeuren (bijvoorbeeld eerst de database deployen, dan de migraties uitvoeren, dan de nieuwe versie van de applicatie implementeren). Helm ondersteunt dit soort multi-stage deployments niet (op het moment van schrijven).
  • Geen overzicht van welke versie in elke omgeving draait.
  • De toegangscontrole van Kubernetes is niet geweldig.

ArgoCD is een geweldige tool die een aantal van deze problemen kon oplossen, en meer! ArgoCD is “Declarative GitOps voor Kubernetes“. Het monitort één of meer Git repositories. Bij elke commit zal het de resources in Kubernetes bijwerken (via Helm of native YAML’s).

We hebben ArgoCD ingesteld om een “single source of truth” repository te monitoren, genaamd services-root. De repository bevat een JSON-bestand per dienst, per omgeving. De JSON beschrijft welke git commit (en Docker image tag) van de service repository live moet staan in de omgeving. Bijvoorbeeld:

   { 
"cluster": "staging",
"service": "python-example",
"imageTag": "a2a7d76d9f6af65f96fd46cc92bcee7f065d8514",
"targetRevision": "a2a7d76d9f6af65f96fd46cc92bcee7f065d8514"
}

Een ApplicationSet is geconfigureerd om wijzigingen in de services-root repository te bekijken. Voor elk JSON-bestand wordt een Application resource aangemaakt. De Application resource triggert ArgoCD om een git commit van de repository te checken, en de Helm chart toe te passen op Kubernetes, wat resulteert in de deployment van de dienst.

Gebruiksgemak van het platform

We hebben ons gericht op het gebruiksgemak van het platform voor developers: het verbergen van de complexiteit van Kubernetes en een heleboel andere tools die nodig zijn om een solide PaaS te bouwen. Tijdens de masterclass deed ik een demo die de stappen liet zien die een ontwikkelaar zou moeten nemen om een nieuwe dienst te maken en te deployen. Deze stappen zijn:

  • Creëer een git repository op GitLab
  • Kloon de python-template met copier
  • git commit && git push
  • Staging wordt automatisch uitgerold
  • Klik handmatig op deploy-production in Gitlab

Kijkend naar deze stappen zijn we zeker geslaagd in ons doel om developers in staat te stellen het platform te gebruiken zonder hulp van het infrateam. Missie volbracht!

Meer verhalen lezen?

In de afgelopen jaren hebben we veel geschreven over ondernemen, zelfsturend werken, de handigste tools en nog veel meer. Dus leef je uit!

Van 3 augustus 2023

Zo pakken we Product Development aan bij Voys

Van 26 mei 2023

Met deze technieken ontwikkelden wij onze nieuwe microservice platformarchitectuur