Add Kubernetes/K3s deployment manifests and documentation

- Complete k8s manifests with Kustomize support
- Production and staging overlays
- ConfigMap/Secret management
- Ingress with TLS (Traefik/NGINX)
- Persistent storage for SQLite
- Comprehensive k8s README with operations guide
- Updated main README with k8s deployment instructions
- Gitignore for k8s secrets

Usage:
  kubectl apply -k k8s/overlays/production
This commit is contained in:
2026-02-01 16:40:16 -05:00
parent 2470f121e2
commit f3f1c0a0c8
16 changed files with 692 additions and 1 deletions

365
k8s/README.md Normal file
View File

@@ -0,0 +1,365 @@
# Kubernetes Deployment
This directory contains Kubernetes manifests for deploying the DWS Dynamic DNS service on K3s, Kubernetes, or any K8s-compatible platform.
## Directory Structure
```
k8s/
├── base/ # Base manifests (don't edit directly)
│ ├── deployment.yaml # Deployment, Service, PVC
│ ├── configmap.yaml # Non-sensitive configuration
│ ├── secrets.yaml # Sensitive configuration (placeholders)
│ ├── ingress.yaml # Ingress with TLS
│ └── kustomization.yaml # Base kustomization
├── overlays/
│ ├── production/ # Production environment
│ │ ├── kustomization.yaml # Production-specific settings
│ │ ├── deployment-patch.yaml # Resource adjustments
│ │ ├── namespace.yaml # Production namespace
│ │ ├── secrets.yaml # Production secrets (gitignored)
│ │ └── secrets.example.yaml # Example secrets template
│ │
│ └── staging/ # Staging environment
│ ├── kustomization.yaml # Staging-specific settings
│ ├── deployment-patch.yaml # Single replica, lower resources
│ ├── namespace.yaml # Staging namespace
│ ├── secrets.yaml # Staging secrets (gitignored)
│ └── secrets.example.yaml # Example secrets template
└── README.md # This file
```
## Quick Start
### Prerequisites
- Kubernetes 1.21+ or K3s cluster
- kubectl configured with cluster access
- cert-manager installed (for TLS certificates)
- Ingress controller (Traefik, NGINX, etc.)
- Storage class for persistent volumes
### Production Deployment
```bash
# 1. Clone and enter directory
git clone https://git.dws.rip/DWS/dyn.git
cd dyn/k8s
# 2. Create production secrets
cp overlays/production/secrets.example.yaml overlays/production/secrets.yaml
# 3. Edit secrets with your Technitium credentials
# Replace 'your-production-api-token-here' with actual token
nano overlays/production/secrets.yaml
# 4. Deploy to production
kubectl apply -k overlays/production
# 5. Verify deployment
kubectl get pods -n dyn-ddns
kubectl get svc -n dyn-ddns
kubectl get ingress -n dyn-ddns
# 6. Check logs
kubectl logs -n dyn-ddns -l app.kubernetes.io/name=dyn-ddns -f
```
### Staging Deployment
```bash
# Similar process for staging
cp overlays/staging/secrets.example.yaml overlays/staging/secrets.yaml
# Edit with staging credentials
kubectl apply -k overlays/staging
```
## Configuration
### Secrets (Required)
Create `overlays/production/secrets.yaml`:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: dyn-ddns-secrets
type: Opaque
stringData:
# Choose ONE authentication method:
# Method 1: API Token (recommended)
TECHNITIUM_TOKEN: "your-actual-api-token-here"
# Method 2: Username/Password
# TECHNITIUM_USERNAME: "admin"
# TECHNITIUM_PASSWORD: "your-password"
# Optional: Trusted proxies
# TRUSTED_PROXIES: "10.0.0.0/8,172.16.0.0/12"
```
**Important:** Never commit secrets.yaml to git. It's already in .gitignore.
### ConfigMap (Optional Overrides)
Edit `overlays/production/kustomization.yaml`:
```yaml
configMapGenerator:
- name: dyn-ddns-config
behavior: merge
literals:
- TECHNITIUM_URL=https://dns.dws.rip
- BASE_DOMAIN=dws.rip
- SPACE_SUBDOMAIN=space
- RATE_LIMIT_PER_IP=10
- RATE_LIMIT_PER_TOKEN=1
```
### Ingress Customization
By default, the ingress is configured for **Traefik** with cert-manager:
```yaml
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
```
For **NGINX** ingress, change annotations in `base/ingress.yaml`:
```yaml
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
```
## Architecture
### Components
1. **Deployment** - Runs the DDNS bridge container
- Replicas: 2 (production), 1 (staging)
- Resource limits configurable per overlay
- Health checks (liveness & readiness probes)
2. **Service** - ClusterIP exposing port 80
3. **Ingress** - TLS termination at edge
- Host: dyn.dws.rip (customize as needed)
- Automatic certificate via cert-manager
4. **PersistentVolumeClaim** - SQLite database storage
- Size: 1Gi (adjustable)
- AccessMode: ReadWriteOnce
### Resource Requirements
**Production:**
- CPU: 200m request / 1000m limit
- Memory: 128Mi request / 512Mi limit
- Replicas: 2
**Staging:**
- CPU: 100m request / 500m limit
- Memory: 64Mi request / 256Mi limit
- Replicas: 1
## Operations
### View Logs
```bash
# All pods
kubectl logs -n dyn-ddns -l app.kubernetes.io/name=dyn-ddns
# Specific pod
kubectl logs -n dyn-ddns -f deployment/prod-dyn-ddns
# Previous container logs (after restart)
kubectl logs -n dyn-ddns --previous deployment/prod-dyn-ddns
```
### Scale Deployment
```bash
# Scale to 3 replicas
kubectl scale deployment -n dyn-ddns prod-dyn-ddns --replicas=3
# Edit deployment directly
kubectl edit deployment -n dyn-ddns prod-dyn-ddns
```
### Database Backup
The SQLite database is stored in the persistent volume at `/data/dyn.db`:
```bash
# Find the pod
POD=$(kubectl get pod -n dyn-ddns -l app.kubernetes.io/name=dyn-ddns -o jsonpath='{.items[0].metadata.name}')
# Copy database locally
kubectl cp dyn-ddns/$POD:/data/dyn.db ./dyn-backup-$(date +%Y%m%d).db
# Or exec into pod
kubectl exec -it -n dyn-ddns $POD -- sh
# Then: sqlite3 /data/dyn.db "SELECT * FROM spaces;"
```
### Update Deployment
```bash
# Update to latest image
kubectl rollout restart deployment -n dyn-ddns prod-dyn-ddns
# Or set specific image tag
kubectl set image deployment -n dyn-ddns prod-dyn-ddns dyn-ddns=git.dws.rip/DWS/dyn:v1.0.0
# Monitor rollout
kubectl rollout status deployment -n dyn-ddns prod-dyn-ddns
```
### Troubleshooting
**Pod stuck in Pending:**
```bash
kubectl describe pod -n dyn-ddns <pod-name>
# Check: Storage class available? PV provisioned?
```
**Pod crash looping:**
```bash
kubectl logs -n dyn-ddns --previous <pod-name>
# Check: Secrets configured? Technitium URL reachable?
```
**Ingress not working:**
```bash
kubectl describe ingress -n dyn-ddns prod-dyn-ddns
kubectl get certificate -n dyn-ddns
# Check: DNS pointing to ingress controller? Cert-manager working?
```
## Advanced Usage
### Multi-Environment Setup
Deploy to multiple environments:
```bash
# Staging
kubectl apply -k overlays/staging
# Production
kubectl apply -k overlays/production
# Verify both
kubectl get pods --all-namespaces -l app.kubernetes.io/name=dyn-ddns
```
### Custom Overlay
Create your own overlay for specific needs:
```bash
mkdir overlays/custom
cat > overlays/custom/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: my-namespace
configMapGenerator:
- name: dyn-ddns-config
behavior: merge
literals:
- TECHNITIUM_URL=https://my-dns-server.example.com
- RATE_LIMIT_PER_IP=5
EOF
kubectl apply -k overlays/custom
```
### Monitoring
The deployment exposes standard metrics. Add Prometheus scraping:
```yaml
# Add to deployment-patch.yaml
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
```
## Security Considerations
1. **Secrets Management**
- Never commit secrets to git
- Consider using external secrets operator (Vault, Sealed Secrets)
- Rotate Technitium API tokens regularly
2. **Network Policies**
```yaml
# Example network policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dyn-ddns-netpol
namespace: dyn-ddns
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: dyn-ddns
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to: [] # Allow all egress (for Technitium API)
```
3. **Pod Security**
- Container runs as non-root (in Dockerfile)
- Read-only root filesystem recommended
- Drop all capabilities
## Maintenance
### Regular Tasks
1. **Backup database weekly**
2. **Monitor rate limit metrics**
3. **Review access logs**
4. **Update base image for security patches**
### Version Upgrades
1. Update image tag in overlay kustomization
2. Apply changes: `kubectl apply -k overlays/production`
3. Verify rollout: `kubectl rollout status ...`
4. Monitor for errors in logs
## Support
For issues specific to Kubernetes deployment:
1. Check pod logs: `kubectl logs ...`
2. Describe resources: `kubectl describe ...`
3. Check ingress controller logs
4. Verify cert-manager is issuing certificates