Elk platform team vraagt zich uiteindelijk af: moeten we een Internal Developer Platform bouwen?

Het antwoord is waarschijnlijk ja. De vraag is hoe.

Ik heb platforms gezien die miljoenen kostten en nooit geadopteerd werden. Ik heb ook scrappy interne tools gezien die developer productiviteit van de ene op de andere dag transformeerden. Het verschil is geen budget of technologie — het is aanpak.

Wat Is een Internal Developer Platform?

Een Internal Developer Platform (IDP) is een self-service laag die infrastructuur complexiteit abstraheert van developers. In plaats van Kubernetes YAML te schrijven, beschrijven developers wat ze nodig hebben. Het platform regelt hoe.

flowchart TD
    subgraph before["Zonder Platform"]
        D1["Developer"] --> K8s["Kubernetes YAML"]
        D1 --> CI["CI Pipeline"]
        D1 --> Sec["Security Config"]
        D1 --> Mon["Monitoring Setup"]
    end

    subgraph after["Met Platform"]
        D2["Developer"] --> IDP["Platform API"]
        IDP --> K8s2["Kubernetes"]
        IDP --> CI2["CI/CD"]
        IDP --> Sec2["Security"]
        IDP --> Mon2["Monitoring"]
    end

Het platform is de interface tussen developer intentie en infrastructuur realiteit.

Waarom Platforms Falen

Gebouwd in Isolatie

Platform team bouwt wat ze denken dat developers nodig hebben. Developers gebruiken het niet. Platform team geeft developers de schuld dat ze de visie niet begrijpen.

Te Veel Te Snel

Beginnen met een compleet platform — service catalogus, self-service alles, custom UI. Zes maanden later, nog steeds niet productie-ready.

Verkeerd Abstractieniveau

Platform is of te low-level (gewoon Kubernetes met extra stappen) of te high-level (geen escape hatches wanneer je ze nodig hebt).

Geen Migratiepad

Bestaande services kunnen niet migreren. Platform is alleen voor greenfield. Team onderhoudt nu twee systemen voor altijd.

Begin Met Problemen, Niet Oplossingen

Voordat je iets bouwt, begrijp:

  1. Waar verliezen developers tijd?

    • Wachten op infrastructuur requests?
    • Boilerplate configuratie schrijven?
    • Deployment failures debuggen?
    • Productie toegang krijgen?
  2. Waar vragen ze steeds om?

    • Check je ticketing systeem
    • Kijk naar Slack vragen
    • Praat met mensen (revolutionair, ik weet het)
  3. Waar ontstaan incidenten?

    • Verkeerd geconfigureerde services?
    • Ontbrekende security policies?
    • Incorrecte resource limits?

De antwoorden onthullen wat je platform eerst moet automatiseren.

Het Minimaal Viable Platform

Begin met drie componenten:

1. Golden Paths

Opinionated templates die best practices coderen:

# service-template/
├── deployment.yaml      # Standaard deployment patroon
├── service.yaml         # Service met verstandige defaults
├── networkpolicy.yaml   # Security by default
├── servicemonitor.yaml  # Automatische monitoring
└── values.yaml          # Customization punten

Developers krijgen een werkende setup by default. Ze customizen alleen wat anders is aan hun service.

2. Self-Service Deployment

Push code, krijg deployment. Geen tickets, geen wachten.

Met GitOps:

# Application definitie in Git
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-service
  namespace: argocd
spec:
  source:
    repoURL: https://gitlab.internal/my-service
    path: deploy
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: my-service
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Developer merged naar main, ArgoCD deployt. Geen platform UI nodig initieel.

3. Guardrails

Kyverno policies die fouten voorkomen:

# Vereis resource limits
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-limits
      match:
        resources:
          kinds:
            - Pod
      validate:
        message: "CPU en memory limits zijn vereist"
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    cpu: "?*"
                    memory: "?*"

Developers kunnen niet deployen zonder limits. Het platform dwingt standaarden automatisch af.

Bouwstenen

Service Templates met Helm

Maak een base chart die teams uitbreiden:

# base-service/Chart.yaml
apiVersion: v2
name: base-service
version: 1.0.0
description: Standaard service template

# base-service/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.name }}
spec:
  replicas: {{ .Values.replicas | default 2 }}
  selector:
    matchLabels:
      app: {{ .Values.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.name }}
      annotations:
        prometheus.io/scrape: "true"
    spec:
      containers:
        - name: {{ .Values.name }}
          image: {{ .Values.image }}
          ports:
            - containerPort: {{ .Values.port | default 8080 }}
          resources:
            requests:
              cpu: {{ .Values.resources.requests.cpu | default "100m" }}
              memory: {{ .Values.resources.requests.memory | default "128Mi" }}
            limits:
              cpu: {{ .Values.resources.limits.cpu | default "500m" }}
              memory: {{ .Values.resources.limits.memory | default "512Mi" }}
          readinessProbe:
            httpGet:
              path: {{ .Values.healthPath | default "/health" }}
              port: {{ .Values.port | default 8080 }}

Teams gebruiken het:

# my-service/values.yaml
name: my-service
image: registry.internal/my-service:v1.2.3
replicas: 3
port: 8080
resources:
  requests:
    cpu: 200m
    memory: 256Mi
  limits:
    cpu: 1
    memory: 1Gi

Namespace als Grens

Elk team krijgt een namespace met alles vooraf geconfigureerd:

apiVersion: v1
kind: Namespace
metadata:
  name: team-payments
  labels:
    team: payments
    environment: production
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: team-payments
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: team-payments
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Teams ownen hun namespace. Platform biedt de grenzen.

Self-Service via GitOps

Developers wijzigen hun namespace config via pull requests:

infrastructure/
├── teams/
│   ├── payments/
│   │   ├── namespace.yaml
│   │   ├── applications/
│   │   │   ├── api.yaml
│   │   │   └── worker.yaml
│   │   └── secrets/
│   │       └── external-secret.yaml
│   ├── orders/
│   └── ...

Pull request triggert review. Merge triggert ArgoCD sync. Geen tickets.

Progressieve Uitbreiding

Fase 1: Templates en Guardrails

  • Helm charts voor veelvoorkomende patronen
  • Kyverno policies voor veiligheid
  • GitOps voor deployment
  • Basis documentatie

Resultaat: Developers kunnen veilig deployen zonder Kubernetes diep te begrijpen.

Fase 2: Observability Integratie

Resultaat: Developers krijgen visibility zonder configuratie.

Fase 3: Developer Portal

Voeg een UI laag toe (Backstage, custom, of vergelijkbaar):

flowchart TD
    Portal["Developer Portal"] --> Catalog["Service Catalogus"]
    Portal --> Templates["Maak van Template"]
    Portal --> Docs["Documentatie"]
    Portal --> Status["Service Status"]

    Templates --> Git["Git Repository"]
    Git --> ArgoCD["ArgoCD"]
    ArgoCD --> K8s["Kubernetes"]

Resultaat: Developers hebben een single entry point.

Fase 4: Geavanceerde Mogelijkheden

  • Secret management integratie (Vault)
  • Database provisioning
  • Environment cloning
  • Kosten visibility

Resultaat: Echte self-service voor de meeste behoeften.

Wat Niet Te Bouwen

Custom YAML DSL

Verzin geen configuratietaal. Gebruik bestaande tools (Helm, Kustomize, cdk8s).

Ticket-Gebaseerde Workflows

Als developers nog steeds tickets maken, heb je niet genoeg geautomatiseerd.

One-Size-Fits-All

Bied golden paths, maar sta afwijking toe. Expert teams moeten lager niveau kunnen gaan.

Feature Factory

Platform moet stabiel zijn. Continue feature churn betekent dat je verkeerde problemen oplost.

Succes Meten

Tijd naar Productie

Hoe lang van “nieuwe service idee” naar “draait in productie”?

  • Weken → Platform werkt niet
  • Dagen → Op weg
  • Uren → Succes

Ticket Volume

Platform requests moeten afnemen over tijd:

Voor: 50 infrastructuur tickets/week
Na: 10 infrastructuur tickets/week (alleen edge cases)

Developer NPS

Vraag developers: “Zou je dit platform aanbevelen aan een collega?”

Incident Correlatie

Hebben platform-deployed services minder incidenten dan handmatig geconfigureerde?

Team Structuur

Platform Team Grootte

Vuistregel: 1 platform engineer per 10-15 applicatie developers.

Te klein → Platform evolueert niet Te groot → Platform team bouwt features die niemand nodig heeft

Verantwoordelijkheden

Platform team:

  • Onderhoudt templates en tools
  • Schrijft policies
  • Handelt platform incidenten af
  • Biedt migratie ondersteuning

Applicatie teams:

  • Ownen hun services
  • Deployen hun code
  • Definiëren hun resource behoeften
  • First responders voor service incidenten

Embedded vs Centralized

Begin gecentraliseerd. Als platform matuur wordt, embed platform engineers part-time in product teams om echte behoeften te begrijpen.

Real-World Voorbeeld

Mijn homelab platform gebruikt:

Golden path:

# Standaard service template
dependencies:
  - base-service  # Helm dependency
values:
  name: my-app
  image: registry/my-app:latest

Self-service:

  • Push naar main → ArgoCD deployt
  • PR voor namespace wijzigingen → Auto-merged na review

Guardrails:

  • Kyverno dwingt limits, labels, security context af
  • NetworkPolicy default deny

Observability:

  • ServiceMonitor auto-gemaakt
  • Grafana dashboard gegenereerd

Totaal custom code: ~500 regels Helm templates en Kyverno policies. Al het andere is configuratie van bestaande tools.

Veelgemaakte Fouten

Beginnen met de Portal

Bouw geen UI tot workflows bewezen zijn. Test eerst met GitOps en CLI.

Bestaande Services Negeren

Platform moet migratie ondersteunen, niet alleen greenfield. Anders onderhoud je twee systemen.

Over-Engineering Security

Blokkeer niet elke edge case. Begin permissive, verscherp gebaseerd op incidenten.

Alle Complexiteit Verbergen

Sommige developers willen begrijpen. Bied escape hatches en documentatie.

Waarom Dit Ertoe Doet

Developer tijd is duur. Elk uur besteed aan vechten met infrastructuur is een uur niet besteed aan product bouwen.

Een goed platform vermenigvuldigt productiviteit:

  • Junior developers deployen veilig op dag één
  • Senior developers focussen op moeilijke problemen
  • Operations last verschuift van repetitief naar interessant

Begin klein. Los echte problemen op. Groei gebaseerd op feedback.

Het beste platform is onzichtbaar — developers denken alleen “deployen is makkelijk hier.”


Een platform is geen product. Het is de afwezigheid van frictie.