# Adopt-a-Street Deployment This directory contains deployment configurations for the Adopt-a-Street application on Kubernetes (Raspberry Pi cluster). ## Directory Structure ``` deploy/ ├── k8s/ # Kubernetes manifests │ ├── namespace.yaml # Namespace definition │ ├── configmap.yaml # Environment configuration │ ├── secrets.yaml.example # Secret template (COPY TO secrets.yaml) │ ├── couchdb-statefulset.yaml # CouchDB StatefulSet with PVC │ ├── couchdb-configmap.yaml # CouchDB configuration │ ├── backend-deployment.yaml # Backend Deployment + Service │ ├── frontend-deployment.yaml # Frontend Deployment + Service │ └── ingress.yaml # Ingress for routing ├── README.md # This file └── scripts/ # Deployment helper scripts ``` ## Prerequisites ### Cluster Requirements - Kubernetes cluster with 3 nodes: - 2x Raspberry Pi 5 (8GB RAM) - ARM64 - 1x Raspberry Pi 3B+ (1GB RAM) - ARMv7 - kubectl configured to access your cluster - Container registry accessible from cluster - Ingress controller installed (Traefik or NGINX Ingress) - Persistent storage provisioner (local-path, NFS, or Longhorn) ### Local Requirements - Docker with buildx for multi-arch builds - kubectl CLI tool - Access to container registry (Docker Hub, GitHub Container Registry, or private registry) - Bun runtime for local development and testing ## Quick Start ### 1. Build Multi-Arch Docker Images Build images for both ARM64 (Pi 5) and ARMv7 (Pi 3B+): ```bash # From project root cd /home/will/Code/adopt-a-street # Create buildx builder (one-time setup) docker buildx create --use --name multiarch-builder # Build and push backend docker buildx build --platform linux/arm64,linux/arm/v7 \ -t your-registry/adopt-a-street-backend:latest \ --push ./backend # Build and push frontend docker buildx build --platform linux/arm64,linux/arm/v7 \ -t your-registry/adopt-a-street-frontend:latest \ --push ./frontend ``` **Note:** Replace `your-registry` with your actual registry (e.g., `docker.io/username` or `ghcr.io/username`) ### 2. Configure Secrets ```bash # Copy secrets template cp deploy/k8s/secrets.yaml.example deploy/k8s/secrets.yaml # Edit secrets with your actual values nano deploy/k8s/secrets.yaml # IMPORTANT: Add secrets.yaml to .gitignore if not already there echo "deploy/k8s/secrets.yaml" >> .gitignore ``` **Required Secrets:** - `JWT_SECRET` - Strong random string for JWT signing - `CLOUDINARY_CLOUD_NAME` - Your Cloudinary cloud name - `CLOUDINARY_API_KEY` - Your Cloudinary API key - `CLOUDINARY_API_SECRET` - Your Cloudinary API secret ### 3. Update Image References Update the image references in deployment files: ```bash # Update backend image reference nano deploy/k8s/backend-deployment.yaml # Change: image: your-registry/adopt-a-street-backend:latest # Update frontend image reference nano deploy/k8s/frontend-deployment.yaml # Change: image: your-registry/adopt-a-street-frontend:latest ``` ### 4. Configure CouchDB ```bash # Apply CouchDB configuration kubectl apply -f deploy/k8s/couchdb-configmap.yaml # Deploy CouchDB kubectl apply -f deploy/k8s/couchdb-statefulset.yaml # Wait for CouchDB to be ready kubectl wait --for=condition=ready pod -l app=couchdb -n adopt-a-street --timeout=120s ``` ### 4. Update Domain Name Update the ingress host: ```bash nano deploy/k8s/ingress.yaml # Change: host: adopt-a-street.local # To your actual domain or IP ``` ### 5. Deploy to Kubernetes ```bash # Create namespace kubectl apply -f deploy/k8s/namespace.yaml # Create secrets (IMPORTANT: Make sure you've edited secrets.yaml!) kubectl apply -f deploy/k8s/secrets.yaml # Create ConfigMap kubectl apply -f deploy/k8s/configmap.yaml # Deploy CouchDB (already done in step 4) # Wait for CouchDB to be ready (this may take 1-2 minutes) kubectl wait --for=condition=ready pod -l app=couchdb -n adopt-a-street --timeout=120s # Deploy backend kubectl apply -f deploy/k8s/backend-deployment.yaml # Wait for backend to be ready kubectl wait --for=condition=ready pod -l app=backend -n adopt-a-street --timeout=120s # Deploy frontend kubectl apply -f deploy/k8s/frontend-deployment.yaml # Deploy ingress kubectl apply -f deploy/k8s/ingress.yaml # Check deployment status kubectl get all -n adopt-a-street ``` ## Verification ### Check Pod Status ```bash # View all resources kubectl get all -n adopt-a-street # Check pod status kubectl get pods -n adopt-a-street # Expected output: # NAME READY STATUS RESTARTS AGE # adopt-a-street-backend-xxxxxxxxxx-xxxxx 1/1 Running 0 5m # adopt-a-street-backend-xxxxxxxxxx-xxxxx 1/1 Running 0 5m # adopt-a-street-frontend-xxxxxxxxx-xxxxx 1/1 Running 0 5m # adopt-a-street-frontend-xxxxxxxxx-xxxxx 1/1 Running 0 5m # adopt-a-street-couchdb-0 1/1 Running 0 10m ``` ### Check Logs ```bash # Backend logs kubectl logs -f deployment/adopt-a-street-backend -n adopt-a-street # Frontend logs kubectl logs -f deployment/adopt-a-street-frontend -n adopt-a-street # CouchDB logs kubectl logs -f adopt-a-street-couchdb-0 -n adopt-a-street ``` ### Check Services ```bash kubectl get svc -n adopt-a-street # Expected output: # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE # adopt-a-street-backend ClusterIP 10.43.x.x 5000/TCP 5m # adopt-a-street-frontend ClusterIP 10.43.x.x 80/TCP 5m # adopt-a-street-couchdb ClusterIP None 5984/TCP 10m ``` ### Check Ingress ```bash kubectl get ingress -n adopt-a-street # Get ingress details kubectl describe ingress adopt-a-street-ingress -n adopt-a-street ``` ### Access the Application ```bash # Port forward for testing (if ingress not working) kubectl port-forward svc/adopt-a-street-frontend 3000:80 -n adopt-a-street # Then open http://localhost:3000 in your browser ``` ## Resource Allocation The deployment is optimized for Raspberry Pi hardware: ### CouchDB (Pi 5 nodes only) - **Requests:** 512Mi RAM, 250m CPU - **Limits:** 2Gi RAM, 1000m CPU - **Storage:** 10Gi persistent volume - **Additional:** 64Mi RAM, 50m CPU for metrics exporter ### Backend (prefers Pi 5 nodes) - **Requests:** 256Mi RAM, 100m CPU - **Limits:** 512Mi RAM, 500m CPU - **Replicas:** 2 pods ### Frontend (any node) - **Requests:** 64Mi RAM, 50m CPU - **Limits:** 128Mi RAM, 200m CPU - **Replicas:** 2 pods ### Total Cluster Requirements - **Minimum RAM:** ~3.6 GB (1.5GB CouchDB + 1GB backend + 200MB frontend + 800MB system) - **Recommended:** 2x Pi 5 (8GB each) handles this comfortably ## Scaling ### Scale Deployments ```bash # Scale backend kubectl scale deployment adopt-a-street-backend --replicas=3 -n adopt-a-street # Scale frontend kubectl scale deployment adopt-a-street-frontend --replicas=3 -n adopt-a-street ``` **Note:** CouchDB is a StatefulSet with 1 replica. Scaling CouchDB requires configuring clustering. ## Updating ### Update Images ```bash # Build and push new version docker buildx build --platform linux/arm64,linux/arm/v7 \ -t your-registry/adopt-a-street-backend:v2.0 \ --push ./backend # Update deployment kubectl set image deployment/adopt-a-street-backend \ backend=your-registry/adopt-a-street-backend:v2.0 \ -n adopt-a-street # Check rollout status kubectl rollout status deployment/adopt-a-street-backend -n adopt-a-street ``` ### Rollback ```bash # Rollback to previous version kubectl rollout undo deployment/adopt-a-street-backend -n adopt-a-street # Rollback to specific revision kubectl rollout undo deployment/adopt-a-street-backend --to-revision=2 -n adopt-a-street ``` ## Monitoring ### Resource Usage ```bash # Node resource usage kubectl top nodes # Pod resource usage kubectl top pods -n adopt-a-street ``` ### Events ```bash # View recent events kubectl get events -n adopt-a-street --sort-by='.lastTimestamp' ``` ### Describe Resources ```bash # Describe pod (useful for troubleshooting) kubectl describe pod -n adopt-a-street # Describe deployment kubectl describe deployment adopt-a-street-backend -n adopt-a-street ``` ## Troubleshooting ### Pod Not Starting ```bash # Check pod events kubectl describe pod -n adopt-a-street # Check logs kubectl logs -n adopt-a-street # Check previous logs (if pod crashed) kubectl logs -n adopt-a-street --previous ``` ### Image Pull Errors - Verify image exists in registry - Check image name and tag in deployment - Verify cluster can access registry - Check if imagePullSecrets are needed ### CouchDB Connection Issues ```bash # Shell into backend pod kubectl exec -it -n adopt-a-street -- sh # Test CouchDB connection curl -f http://adopt-a-street-couchdb:5984/_up # Test authentication curl -u $COUCHDB_USER:$COUCHDB_PASSWORD http://adopt-a-street-couchdb:5984/_session ``` ### Persistent Volume Issues ```bash # Check PVCs kubectl get pvc -n adopt-a-street # Check PVs kubectl get pv # Describe PVC kubectl describe pvc mongodb-data-adopt-a-street-mongodb-0 -n adopt-a-street ``` ## Cleanup ### Delete Everything ```bash # Delete all resources in namespace kubectl delete namespace adopt-a-street # Or delete resources individually kubectl delete -f deploy/k8s/ingress.yaml kubectl delete -f deploy/k8s/frontend-deployment.yaml kubectl delete -f deploy/k8s/backend-deployment.yaml kubectl delete -f deploy/k8s/couchdb-statefulset.yaml kubectl delete -f deploy/k8s/couchdb-configmap.yaml kubectl delete -f deploy/k8s/configmap.yaml kubectl delete -f deploy/k8s/secrets.yaml kubectl delete -f deploy/k8s/namespace.yaml # Note: This will also delete the persistent volume data! ``` ## Security Best Practices 1. **Never commit secrets.yaml** - Always use secrets.yaml.example 2. **Use strong JWT_SECRET** - Generate with: `openssl rand -base64 32` 3. **Use strong CouchDB passwords** - Generate with: `openssl rand -base64 32` 4. **Enable TLS/HTTPS** - Uncomment TLS section in ingress.yaml and use cert-manager 5. **Restrict ingress** - Use network policies to limit pod communication 6. **Use image digests** - Pin images to specific SHA256 digests for production 7. **Enable RBAC** - Create service accounts with minimal permissions 8. **Scan images** - Use tools like Trivy to scan for vulnerabilities ## Performance Optimization 1. **Use imagePullPolicy: IfNotPresent** - After initial deployment to save bandwidth 2. **Implement HPA** - Horizontal Pod Autoscaler for dynamic scaling 3. **Add Redis** - For caching to reduce CouchDB load 4. **Use CDN** - For frontend static assets 5. **Enable compression** - Nginx already configured with gzip 6. **Monitor resources** - Use Prometheus + Grafana for metrics (CouchDB exporter included) ## Additional Resources - [Kubernetes Documentation](https://kubernetes.io/docs/) - [Raspberry Pi Kubernetes Guide](https://github.com/alexellis/k8s-on-raspbian) - [Helm Charts](https://helm.sh/) - Consider migrating to Helm for easier management - [ArgoCD](https://argoproj.github.io/cd/) - GitOps continuous delivery for Kubernetes ## Support For issues or questions: 1. Check pod logs: `kubectl logs -n adopt-a-street` 2. Check events: `kubectl get events -n adopt-a-street` 3. Describe resources: `kubectl describe -n adopt-a-street` 4. Review application logs in the backend