Skip to main content

Kubernetes Deployment

Pengenalan

Kubernetes adalah platform orchestration untuk containerized applications yang menyediakan automated deployment, scaling, dan management. Pada bagian ini kita akan membahas konfigurasi Kubernetes manifests untuk deployment aplikasi Docusaurus.

Arsitektur Deployment

┌─────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Ingress Controller │ │
│ │ (nginx/traefik/istio) │ │
│ └──────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────▼─────────────────────────────────┐ │
│ │ Service │ │
│ │ (LoadBalancer/ClusterIP) │ │
│ └──────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────▼─────────────────────────────────┐ │
│ │ Deployment │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ Pod │ │ Pod │ │ Pod │ (ReplicaSet) │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ConfigMap / Secrets │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PersistentVolume (optional) │ │
│ └─────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────┘

Directory Structure

k8s/
├── namespace.yaml # Namespace definition
├── deployment.yaml # Application deployment
├── service.yaml # Service definition
├── ingress.yaml # Ingress rules
├── configmap.yaml # Configuration
├── secrets.yaml # Sensitive data
├── hpa.yaml # Horizontal Pod Autoscaler
└── pdb.yaml # Pod Disruption Budget

1. Namespace

File: k8s/namespace.yaml

Namespace untuk isolasi resources.

apiVersion: v1
kind: Namespace
metadata:
name: gitea-docs
labels:
name: gitea-docs
app: documentation
environment: production

Penjelasan:

  • Isolasi logical untuk resources
  • Memudahkan management dan RBAC
  • Namespace per environment (dev, staging, production)

2. Deployment

File: k8s/deployment.yaml

Main deployment configuration untuk aplikasi Docusaurus.

apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-docs
namespace: gitea-docs
labels:
app: gitea-docs
version: v1.0.0
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: gitea-docs
template:
metadata:
labels:
app: gitea-docs
version: v1.0.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
prometheus.io/path: "/metrics"
spec:
# Security context
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
seccompProfile:
type: RuntimeDefault

# Anti-affinity untuk high availability
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- gitea-docs
topologyKey: kubernetes.io/hostname

containers:
- name: gitea-docs
image: docker.io/username/gitea-docs:latest
imagePullPolicy: Always

ports:
- name: http
containerPort: 80
protocol: TCP

# Environment variables
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "80"

# Resource limits
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"

# Liveness probe
livenessProbe:
httpGet:
path: /health
port: http
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3

# Readiness probe
readinessProbe:
httpGet:
path: /health
port: http
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3

# Startup probe
startupProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 12

# Security context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1001
capabilities:
drop:
- ALL

# Volume mounts
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run

# Volumes
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
- name: run
emptyDir: {}

# Image pull secrets (jika menggunakan private registry)
# imagePullSecrets:
# - name: regcred

Penjelasan Deployment

Replicas

replicas: 3
  • Menjalankan 3 pods untuk high availability
  • Load distribution across pods
  • Zero-downtime deployments

Rolling Update Strategy

strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
  • Update pods secara bertahap
  • Tidak ada downtime
  • Rollback capability

Health Checks

  • Liveness: Restart pod jika unhealthy
  • Readiness: Remove pod dari service jika not ready
  • Startup: Grace period untuk aplikasi startup

Security

  • Non-root user
  • Read-only filesystem
  • Drop all capabilities
  • Security profiles

3. Service

File: k8s/service.yaml

Service untuk expose aplikasi.

apiVersion: v1
kind: Service
metadata:
name: gitea-docs
namespace: gitea-docs
labels:
app: gitea-docs
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: gitea-docs
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800

Service Types

ClusterIP (Default)

type: ClusterIP
  • Internal access only
  • Digunakan dengan Ingress

NodePort

type: NodePort
ports:
- port: 80
nodePort: 30080
  • Expose pada node IP:port
  • Development/testing

LoadBalancer

type: LoadBalancer
  • Cloud provider load balancer
  • External access
  • Production ready

4. Ingress

File: k8s/ingress.yaml

Ingress untuk HTTP/HTTPS routing.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-docs
namespace: gitea-docs
annotations:
# Nginx Ingress annotations
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

# Rate limiting
nginx.ingress.kubernetes.io/limit-rps: "100"

# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"

# Security headers
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Client body size
nginx.ingress.kubernetes.io/proxy-body-size: "10m"

# Timeouts
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
spec:
tls:
- hosts:
- docs.example.com
- www.docs.example.com
secretName: gitea-docs-tls
rules:
- host: docs.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-docs
port:
number: 80
- host: www.docs.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-docs
port:
number: 80

TLS/SSL Configuration

Menggunakan Cert-Manager

  1. Install cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
  1. Create ClusterIssuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx

5. ConfigMap

File: k8s/configmap.yaml

Configuration management.

apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-docs-config
namespace: gitea-docs
data:
# Nginx configuration
nginx.conf: |
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}

# Application config
app-config.json: |
{
"apiUrl": "https://api.example.com",
"environment": "production",
"features": {
"search": true,
"analytics": true
}
}

6. Secrets

File: k8s/secrets.yaml

Sensitive data management.

apiVersion: v1
kind: Secret
metadata:
name: gitea-docs-secrets
namespace: gitea-docs
type: Opaque
data:
# Base64 encoded values
api-key: <base64-encoded-api-key>
db-password: <base64-encoded-password>
stringData:
# Plain text (akan di-encode otomatis)
environment: production

Create Secrets via kubectl

# From literal values
kubectl create secret generic gitea-docs-secrets \
--from-literal=api-key=myapikey123 \
--from-literal=db-password=mypassword \
-n gitea-docs

# From file
kubectl create secret generic gitea-docs-secrets \
--from-file=api-key.txt \
--from-file=credentials.json \
-n gitea-docs

# Docker registry secret
kubectl create secret docker-registry regcred \
--docker-server=docker.io \
--docker-username=myusername \
--docker-password=mypassword \
--docker-email=email@example.com \
-n gitea-docs

7. Horizontal Pod Autoscaler

File: k8s/hpa.yaml

Auto-scaling berdasarkan metrics.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: gitea-docs-hpa
namespace: gitea-docs
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: gitea-docs
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 2
periodSeconds: 30
selectPolicy: Max

Custom Metrics (Optional)

metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"

8. Pod Disruption Budget

File: k8s/pdb.yaml

Maintain availability during disruptions.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: gitea-docs-pdb
namespace: gitea-docs
spec:
minAvailable: 2
selector:
matchLabels:
app: gitea-docs

9. NetworkPolicy

File: k8s/networkpolicy.yaml

Network security rules.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: gitea-docs-netpol
namespace: gitea-docs
spec:
podSelector:
matchLabels:
app: gitea-docs
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 80
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53

Deployment Commands

Apply All Manifests

# Apply semua manifests
kubectl apply -f k8s/

# Apply specific file
kubectl apply -f k8s/deployment.yaml

# Apply dengan validation
kubectl apply -f k8s/ --dry-run=client
kubectl apply -f k8s/ --dry-run=server

Verify Deployment

# Check pods
kubectl get pods -n gitea-docs
kubectl describe pod <pod-name> -n gitea-docs

# Check deployment
kubectl get deployment -n gitea-docs
kubectl describe deployment gitea-docs -n gitea-docs

# Check services
kubectl get svc -n gitea-docs
kubectl describe svc gitea-docs -n gitea-docs

# Check ingress
kubectl get ingress -n gitea-docs
kubectl describe ingress gitea-docs -n gitea-docs

# Check events
kubectl get events -n gitea-docs --sort-by='.lastTimestamp'

View Logs

# Logs dari specific pod
kubectl logs <pod-name> -n gitea-docs

# Follow logs
kubectl logs -f <pod-name> -n gitea-docs

# Logs dari semua pods dengan label
kubectl logs -l app=gitea-docs -n gitea-docs --tail=100

# Previous container logs (jika restart)
kubectl logs <pod-name> -n gitea-docs --previous

Update Deployment

# Update image
kubectl set image deployment/gitea-docs \
gitea-docs=docker.io/username/gitea-docs:v2.0.0 \
-n gitea-docs

# Scale deployment
kubectl scale deployment/gitea-docs --replicas=5 -n gitea-docs

# Edit deployment
kubectl edit deployment gitea-docs -n gitea-docs

Rollout Management

# Check rollout status
kubectl rollout status deployment/gitea-docs -n gitea-docs

# View rollout history
kubectl rollout history deployment/gitea-docs -n gitea-docs

# Rollback ke revision sebelumnya
kubectl rollout undo deployment/gitea-docs -n gitea-docs

# Rollback ke specific revision
kubectl rollout undo deployment/gitea-docs --to-revision=2 -n gitea-docs

# Pause rollout
kubectl rollout pause deployment/gitea-docs -n gitea-docs

# Resume rollout
kubectl rollout resume deployment/gitea-docs -n gitea-docs

Monitoring dan Debugging

Resource Usage

# Pod resource usage
kubectl top pods -n gitea-docs

# Node resource usage
kubectl top nodes

# Detailed resource info
kubectl describe node <node-name>

Debug Pod

# Execute command in pod
kubectl exec -it <pod-name> -n gitea-docs -- /bin/sh

# Port forward untuk testing
kubectl port-forward <pod-name> 8080:80 -n gitea-docs

# Copy files from pod
kubectl cp gitea-docs/<pod-name>:/path/to/file ./local-file

# Copy files to pod
kubectl cp ./local-file gitea-docs/<pod-name>:/path/to/file

Network Debugging

# Test service connectivity
kubectl run debug --image=nicolaka/netshoot -it --rm -- /bin/bash

# Inside debug pod:
curl http://gitea-docs.gitea-docs.svc.cluster.local
nslookup gitea-docs.gitea-docs.svc.cluster.local
ping gitea-docs.gitea-docs.svc.cluster.local

Production Best Practices

1. Resource Management

resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"

2. Multiple Replicas

replicas: 3  # Minimum untuk HA

3. Health Checks

livenessProbe:
httpGet:
path: /health
port: 80
readinessProbe:
httpGet:
path: /health
port: 80

4. Security

  • Use non-root user
  • Read-only filesystem
  • Network policies
  • Pod security policies
  • RBAC

5. Monitoring

  • Prometheus metrics
  • Logging aggregation
  • Alerting rules
  • Dashboard (Grafana)

6. Backup Strategy

# Backup all resources
kubectl get all -n gitea-docs -o yaml > backup.yaml

# Backup specific resources
kubectl get deployment,service,ingress -n gitea-docs -o yaml > backup.yaml

Troubleshooting

Pod Tidak Start

Cek:

kubectl describe pod <pod-name> -n gitea-docs
kubectl logs <pod-name> -n gitea-docs

Common issues:

  • Image pull errors
  • Resource constraints
  • Invalid configuration
  • Missing secrets/configmaps

CrashLoopBackOff

Debug:

kubectl logs <pod-name> -n gitea-docs --previous
kubectl describe pod <pod-name> -n gitea-docs

Solutions:

  • Fix application errors
  • Adjust resource limits
  • Fix health check endpoints
  • Check dependencies

Service Tidak Accessible

Verify:

# Check service endpoints
kubectl get endpoints gitea-docs -n gitea-docs

# Check pod labels match service selector
kubectl get pods -n gitea-docs --show-labels

Ingress Not Working

Check:

# Verify ingress controller
kubectl get pods -n ingress-nginx

# Check ingress rules
kubectl describe ingress gitea-docs -n gitea-docs

# Test DNS resolution
nslookup docs.example.com

Cleanup

# Delete specific resources
kubectl delete -f k8s/deployment.yaml

# Delete all resources in namespace
kubectl delete all --all -n gitea-docs

# Delete namespace (will delete all resources)
kubectl delete namespace gitea-docs

Kesimpulan

Deployment Kubernetes untuk Docusaurus mencakup:

  • ✅ High availability dengan multiple replicas
  • ✅ Auto-scaling dengan HPA
  • ✅ Zero-downtime deployment
  • ✅ Security best practices
  • ✅ Monitoring dan logging
  • ✅ Network policies
  • ✅ TLS/SSL support

Konfigurasi ini memberikan foundation yang solid untuk production-grade deployment dengan reliability, scalability, dan security yang tinggi.