# 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
