- Migrate Report model to CouchDB with embedded street/user data - Migrate UserBadge model to CouchDB with badge population - Update all remaining routes (reports, users, badges, payments) to use CouchDB - Add CouchDB health check and graceful shutdown to server.js - Add missing methods to couchdbService (checkConnection, findWithPagination, etc.) - Update Kubernetes deployment manifests for CouchDB support - Add comprehensive CouchDB setup documentation All core functionality now uses CouchDB as primary database while maintaining MongoDB for backward compatibility during transition period. 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
415 lines
11 KiB
Markdown
415 lines
11 KiB
Markdown
# 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 <none> 5000/TCP 5m
|
|
# adopt-a-street-frontend ClusterIP 10.43.x.x <none> 80/TCP 5m
|
|
# adopt-a-street-couchdb ClusterIP None <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 <pod-name> -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 <pod-name> -n adopt-a-street
|
|
|
|
# Check logs
|
|
kubectl logs <pod-name> -n adopt-a-street
|
|
|
|
# Check previous logs (if pod crashed)
|
|
kubectl logs <pod-name> -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 <backend-pod-name> -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 <pod-name> -n adopt-a-street`
|
|
2. Check events: `kubectl get events -n adopt-a-street`
|
|
3. Describe resources: `kubectl describe <resource> -n adopt-a-street`
|
|
4. Review application logs in the backend
|