# 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 # Check: Storage class available? PV provisioned? ``` **Pod crash looping:** ```bash kubectl logs -n dyn-ddns --previous # 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