Kubernetes: De eerste applicatie deployen
Praktische gids om een applicatie te deployen op Kubernetes. Van minikube-installatie tot Deployments, Services en ConfigMaps met concrete voorbeelden.

Kubernetes (K8s) is uitgegroeid tot de de facto standaard voor container-orchestratie. Ontworpen door Google en momenteel onderhouden door de CNCF, automatiseert Kubernetes het deployen, schalen en beheren van gecontaineriseerde applicaties. Deze gids loopt door het opzetten van een lokaal cluster en het deployen van een eerste applicatie.
Basiskennis van Docker wordt aanbevolen voordat dieper in Kubernetes wordt gedoken. Containers zijn de fundamentele bouwstenen die Kubernetes orkestreert. De Docker-gids vooraf lezen maakt de begrippen die hier worden gepresenteerd veel eenvoudiger te begrijpen.
De Kubernetes-architectuur begrijpen
Kubernetes berust op een master-worker-architectuur. De Control Plane neemt de globale beslissingen over het cluster, terwijl de Nodes de workloads uitvoeren.
# Simplified Kubernetes Architecture
┌─────────────────────────────────────────────────────────────┐
│ CONTROL PLANE │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ API Server │ │ Scheduler │ │ Controller Manager │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ etcd ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ NODE 1 │ │ NODE 2 │ │ NODE 3 │
│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │
│ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │
│ ├───────────┤ │ │ ├───────────┤ │ │ ├───────────┤ │
│ │ kube-proxy│ │ │ │ kube-proxy│ │ │ │ kube-proxy│ │
│ ├───────────┤ │ │ ├───────────┤ │ │ ├───────────┤ │
│ │ Pods │ │ │ │ Pods │ │ │ │ Pods │ │
│ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │
└─────────────────┘ └─────────────────┘ └─────────────────┘De API Server is het toegangspunt voor alle commando's. etcd slaat de clusterstatus op. De Scheduler wijst Pods toe aan Nodes. De Controllers houden de gewenste systeemstatus in stand.
De lokale omgeving opzetten
Voor het experimenteren met Kubernetes op lokale machines bestaan verschillende opties: minikube, kind, k3d of Docker Desktop. Minikube blijft de populairste oplossing om mee te leren.
# terminal
# Install kubectl (Kubernetes client)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
# Verify installation
kubectl version --client
# Client Version: v1.31.0
# Install minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Start the local cluster
minikube start --driver=docker --cpus=2 --memory=4096
# Check status
minikube status
# minikube: Running
# cluster: Running
# kubectl: ConfiguredMinikube creëert een Kubernetes-cluster met één node binnen een virtuele machine of een Docker-container. De toegewezen resources (CPU, geheugen) kunnen worden aangepast aan de behoefte.
# terminal
# Access the Kubernetes dashboard (web interface)
minikube dashboard
# Check cluster nodes
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 5m v1.31.0
# Detailed cluster information
kubectl cluster-infoKind (Kubernetes in Docker) start sneller en past beter bij CI/CD-tests. K3d gebruikt k3s, een lichte Kubernetes-distributie. Docker Desktop integreert Kubernetes direct, maar verbruikt meer resources.
Pods: de basiseenheid
Een Pod is de kleinste deploybare eenheid in Kubernetes. Een Pod omvat een of meer containers die hetzelfde netwerk en dezelfde opslag delen.
# pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:
# Unique Pod name within the namespace
name: nginx-pod
# Labels for organization and selection
labels:
app: nginx
environment: development
spec:
containers:
# Main container definition
- name: nginx
# Docker image to use
image: nginx:1.25-alpine
# Ports exposed by the container
ports:
- containerPort: 80
# Container resource allocation
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"Dit YAML-manifest declareert een Pod die één enkele nginx-container bevat. Labels maken het mogelijk om Pods te identificeren en te selecteren. Resources definiëren de minimumgaranties (requests) en maximale limieten (limits).
# terminal
# Create the Pod
kubectl apply -f pod-simple.yaml
# pod/nginx-pod created
# List Pods
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-pod 1/1 Running 0 30s
# Full Pod details
kubectl describe pod nginx-pod
# Container logs
kubectl logs nginx-pod
# Execute a command inside the Pod
kubectl exec -it nginx-pod -- /bin/sh
# Delete the Pod
kubectl delete pod nginx-podPods zijn van nature kortstondig. Bij een crash of verwijdering worden ze niet automatisch opnieuw aangemaakt door Kubernetes. Deployments lossen deze beperking op.
Deployments: declaratief beheer
Een Deployment definieert de gewenste status voor een set identieke Pods. Kubernetes onderhoudt deze status automatisch door Pods aan te maken, bij te werken of te verwijderen wanneer dat nodig is.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment name
name: webapp-deployment
labels:
app: webapp
spec:
# Desired number of replicas
replicas: 3
# Selector to identify managed Pods
selector:
matchLabels:
app: webapp
# Template for Pod creation
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
# Liveness probe: restarts container on failure
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
# Readiness probe: removes Pod from Service on failure
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5Het Deployment maakt een ReplicaSet aan dat 3 identieke Pods in stand houdt. Probes controleren de status van de containers en stellen Kubernetes in staat om automatisch te reageren op problemen.
# terminal
# Create the Deployment
kubectl apply -f deployment.yaml
# deployment.apps/webapp-deployment created
# Verify the Deployment
kubectl get deployments
# NAME READY UP-TO-DATE AVAILABLE AGE
# webapp-deployment 3/3 3 3 1m
# List Pods created by the Deployment
kubectl get pods -l app=webapp
# NAME READY STATUS RESTARTS AGE
# webapp-deployment-7d9f8b6c4-abc12 1/1 Running 0 1m
# webapp-deployment-7d9f8b6c4-def34 1/1 Running 0 1m
# webapp-deployment-7d9f8b6c4-ghi56 1/1 Running 0 1m
# Manual scaling
kubectl scale deployment webapp-deployment --replicas=5
# Deployment history
kubectl rollout history deployment webapp-deploymentHet verwijderen van een Pod activeert automatisch het aanmaken van een nieuwe Pod om het gewenste aantal replicas te behouden.
Klaar om je DevOps gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Services: netwerkblootstelling
Pods hebben kortstondige IP-adressen. Services bieden een stabiel adres om toegang te krijgen tot een set Pods, met ingebouwde load balancing.
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
# Service type: ClusterIP (internal), NodePort, LoadBalancer
type: ClusterIP
# Selector to identify target Pods
selector:
app: webapp
ports:
# Port exposed by the Service
- port: 80
# Target container port
targetPort: 80
# Protocol (TCP by default)
protocol: TCPDeze ClusterIP-Service is alleen toegankelijk vanuit het cluster. Verzoeken naar webapp-service:80 worden verdeeld over de Pods met het label app: webapp.
# terminal
# Create the Service
kubectl apply -f service.yaml
# service/webapp-service created
# List Services
kubectl get services
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# webapp-service ClusterIP 10.96.123.456 <none> 80/TCP 30s
# Test from a temporary Pod
kubectl run curl-test --rm -it --image=curlimages/curl -- curl webapp-service
# Detailed Service description
kubectl describe service webapp-serviceOm de applicatie buiten het cluster bloot te stellen, is een NodePort- of LoadBalancer-type vereist.
# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp-nodeport
spec:
type: NodePort
selector:
app: webapp
ports:
- port: 80
targetPort: 80
# Port on each Node (30000-32767)
nodePort: 30080Met minikube opent het commando minikube service webapp-nodeport automatisch de browser op de juiste URL.
ConfigMaps: geëxternaliseerde configuratie
ConfigMaps scheiden configuratie van code. Waarden worden geïnjecteerd als omgevingsvariabelen of gemount als bestanden.
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
data:
# Simple key-value pairs
APP_ENV: "production"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
# Multiline configuration (complete file)
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
}ConfigMaps slaan niet-gevoelige gegevens op. Voor geheimen (wachtwoorden, tokens) zijn Kubernetes Secrets geschikter.
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-configured
spec:
replicas: 2
selector:
matchLabels:
app: webapp-configured
template:
metadata:
labels:
app: webapp-configured
spec:
containers:
- name: webapp
image: nginx:1.25-alpine
ports:
- containerPort: 80
# Inject environment variables
envFrom:
- configMapRef:
name: webapp-config
# Or individual variables
env:
- name: SPECIFIC_VAR
valueFrom:
configMapKeyRef:
name: webapp-config
key: LOG_LEVEL
# Mount configuration file
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: webapp-configDeze configuratie injecteert omgevingsvariabelen en mount het bestand nginx.conf in de container.
# terminal
# Apply resources
kubectl apply -f configmap.yaml
kubectl apply -f deployment-with-config.yaml
# Verify environment variables
kubectl exec deployment/webapp-configured -- printenv | grep APP_ENV
# APP_ENV=production
# Verify mounted file
kubectl exec deployment/webapp-configured -- cat /etc/nginx/conf.d/default.confHet wijzigen van een ConfigMap herstart de Pods niet automatisch. Om de wijzigingen toe te passen is een handmatige herstart nodig: kubectl rollout restart deployment webapp-configured. Tools zoals Reloader automatiseren dit proces.
Secrets: gevoelige gegevens
Secrets slaan gevoelige informatie op zoals wachtwoorden, tokens of SSH-sleutels. Hoewel ze base64-gecodeerd zijn, worden ze standaard niet versleuteld in rust.
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: webapp-secrets
type: Opaque
# Values must be base64-encoded
data:
# echo -n 'admin' | base64
username: YWRtaW4=
# echo -n 'supersecretpassword' | base64
password: c3VwZXJzZWNyZXRwYXNzd29yZA==
---
# Alternative: stringData accepts plain text values
apiVersion: v1
kind: Secret
metadata:
name: webapp-secrets-plain
type: Opaque
stringData:
username: admin
password: supersecretpasswordSecrets worden op dezelfde manier geïnjecteerd als ConfigMaps.
# deployment-with-secrets.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-secure
spec:
replicas: 1
selector:
matchLabels:
app: webapp-secure
template:
metadata:
labels:
app: webapp-secure
spec:
containers:
- name: webapp
image: nginx:1.25-alpine
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: webapp-secrets
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: webapp-secrets
key: password# terminal
# Create the Secret
kubectl apply -f secret.yaml
# List Secrets (values are not displayed)
kubectl get secrets
# NAME TYPE DATA AGE
# webapp-secrets Opaque 2 10s
# Decode a value
kubectl get secret webapp-secrets -o jsonpath='{.data.password}' | base64 -d
# supersecretpasswordNamespaces: logische isolatie
Namespaces partitioneren een cluster in geïsoleerde virtuele omgevingen. Deze scheiding maakt het mogelijk om meerdere teams of omgevingen op hetzelfde cluster te beheren.
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: development
---
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: stagingElke resource kan worden aangemaakt in een specifieke namespace.
# terminal
# Create namespaces
kubectl apply -f namespace.yaml
# List namespaces
kubectl get namespaces
# NAME STATUS AGE
# default Active 1d
# development Active 10s
# staging Active 10s
# Create a resource in a specific namespace
kubectl apply -f deployment.yaml -n development
# List Pods in a namespace
kubectl get pods -n development
# Change default namespace
kubectl config set-context --current --namespace=developmentResources uit verschillende namespaces zijn standaard van elkaar geïsoleerd. Communicatie tussen namespaces verloopt via de interne DNS: service-name.namespace.svc.cluster.local.
Volledige applicatie: de resources samenstellen
Hieronder een volledige applicatie die alle gepresenteerde concepten combineert.
# complete-app.yaml
---
# Dedicated Namespace
apiVersion: v1
kind: Namespace
metadata:
name: myapp
---
# ConfigMap for configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: myapp
data:
APP_NAME: "MyApp"
LOG_LEVEL: "info"
---
# Secret for sensitive data
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: myapp
type: Opaque
stringData:
api-key: "sk-1234567890abcdef"
---
# Deployment with 3 replicas
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx:1.25-alpine
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: myapp-config
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: myapp-secrets
key: api-key
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
# Service for internal exposure
apiVersion: v1
kind: Service
metadata:
name: myapp-service
namespace: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- port: 80
targetPort: 80
---
# NodePort Service for external access (development)
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: myapp
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 80
targetPort: 80
nodePort: 30100Dit ene bestand deployt een volledige applicatie met geëxternaliseerde configuratie, secrets, hoge beschikbaarheid en netwerkblootstelling.
# terminal
# Deploy the complete application
kubectl apply -f complete-app.yaml
# Verify all resources
kubectl get all -n myapp
# NAME READY STATUS RESTARTS AGE
# pod/myapp-7d9f8b6c4-abc12 1/1 Running 0 30s
# pod/myapp-7d9f8b6c4-def34 1/1 Running 0 30s
# pod/myapp-7d9f8b6c4-ghi56 1/1 Running 0 30s
#
# NAME TYPE CLUSTER-IP PORT(S) AGE
# service/myapp-service ClusterIP 10.96.123.456 80/TCP 30s
# service/myapp-nodeport NodePort 10.96.123.789 80:30100/TCP 30s
#
# NAME READY UP-TO-DATE AVAILABLE AGE
# deployment.apps/myapp 3/3 3 3 30s
# Access the application with minikube
minikube service myapp-nodeport -n myappUpdates en rollbacks
Kubernetes vergemakkelijkt geleidelijke updates en rollbacks.
# terminal
# Update the Deployment image
kubectl set image deployment/myapp myapp=nginx:1.26-alpine -n myapp
# Track deployment in real-time
kubectl rollout status deployment/myapp -n myapp
# Waiting for deployment "myapp" rollout to finish: 1 out of 3 new replicas updated
# Waiting for deployment "myapp" rollout to finish: 2 out of 3 new replicas updated
# deployment "myapp" successfully rolled out
# Revision history
kubectl rollout history deployment/myapp -n myapp
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 <none>
# Rollback to previous revision
kubectl rollout undo deployment/myapp -n myapp
# Rollback to a specific revision
kubectl rollout undo deployment/myapp --to-revision=1 -n myappDe standaard updatestrategie (RollingUpdate) vervangt de oude Pods geleidelijk door nieuwe en garandeert zo een continue beschikbaarheid.
Essentiële kubectl-commando's
# terminal
# ========================================
# General Information
# ========================================
kubectl cluster-info # Cluster info
kubectl get nodes -o wide # Nodes with details
kubectl api-resources # List resource types
# ========================================
# Resource Management
# ========================================
kubectl get all # All namespace resources
kubectl get pods -A # Pods from all namespaces
kubectl get pods -o wide # Pods with IP and Node
kubectl get pods -w # Watch mode (real-time)
# ========================================
# Inspection and Debugging
# ========================================
kubectl describe pod <name> # Full details
kubectl logs <pod> -f # Streaming logs
kubectl logs <pod> -c <container> # Specific container logs
kubectl exec -it <pod> -- /bin/sh # Interactive shell
kubectl port-forward <pod> 8080:80 # Local tunnel to Pod
# ========================================
# Editing and Deletion
# ========================================
kubectl edit deployment <name> # Live editing (vi)
kubectl delete -f manifest.yaml # Delete via file
kubectl delete pod <name> --force # Force deletionConclusie
Kubernetes transformeert het beheer van gecontaineriseerde applicaties door een declaratief, veerkrachtig en uitbreidbaar framework te bieden. De fundamentele concepten die hier worden gepresenteerd vormen de basis voor productieklaar deployments.
Checklist voor een eerste Kubernetes-deployment
- ✅ Werkend lokaal cluster (minikube, kind of k3d)
- ✅ kubectl geïnstalleerd en geconfigureerd
- ✅ Deployment met replicas en health probes
- ✅ Service voor netwerkblootstelling
- ✅ ConfigMap voor geëxternaliseerde configuratie
- ✅ Secret voor gevoelige gegevens
- ✅ Namespace voor isolatie
- ✅ Resourcelimieten gedefinieerd (requests/limits)
- ✅ Updatestrategie en rollback beheerst
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Kubernetes beheersen opent de deur naar schaalbare cloud-native architecturen. Volgende stappen omvatten het verkennen van Ingress Controllers voor HTTP-routing, PersistentVolumes voor opslag en Helm voor pakketbeheer. Kubernetes wordt een belangrijke troef tijdens DevOps- en SRE-sollicitatiegesprekken.
Tags
Delen
Gerelateerde artikelen

Kubernetes Sollicitatiegesprek: Pods, Services en Deployments Uitgelegd
De drie fundamentele Kubernetes-bouwstenen — Pods, Services en Deployments — met productie-YAML, netwerk-internals en veelgestelde interviewvragen.

Essentiële DevOps Interviewvragen: Complete Gids 2026
Bereid je voor op DevOps-interviews met onmisbare vragen over CI/CD, Kubernetes, Docker, Terraform en SRE-praktijken. Gedetailleerde antwoorden inbegrepen.

Docker: van ontwikkeling naar productie
Complete Docker-gids voor het containeriseren van applicaties. Dockerfile, Docker Compose, multi-stage builds en productie-deployment met praktische voorbeelden.