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
- Install cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
- 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.