# Deployment Guide

This guide covers deploying rdev API to the k3s cluster.

## Prerequisites

```bash
# REQUIRED: Set kubeconfig before any kubectl command
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
```

- k3s cluster (orchard9-k3sf)
- kubectl configured with correct kubeconfig
- PostgreSQL database
- Container registry access (ghcr.io/orchard9)

## Quick Deploy

```bash
# Release + deploy (recommended)
./scripts/release.sh v0.10.1 "Description of changes" --deploy

# Or manual deploy
kubectl apply -f deployments/k8s/base/rdev-api.yaml
kubectl rollout restart -n rdev deployment/rdev-api

# Verify deployment
kubectl -n rdev get pods
kubectl -n rdev get svc
```

## Configuration

### Environment Variables

| Variable | Description | Required | Default |
|----------|-------------|----------|---------|
| `PORT` | HTTP server port | No | 8080 |
| `POSTGRES_HOST` | Database host | Yes | - |
| `POSTGRES_PORT` | Database port | No | 5432 |
| `POSTGRES_USER` | Database user | Yes | - |
| `POSTGRES_PASSWORD` | Database password | Yes | - |
| `POSTGRES_DB` | Database name | No | rdev |
| `RDEV_NAMESPACE` | K8s namespace for pods | No | default |
| `RATE_LIMIT_RPS` | Requests per second | No | 10 |
| `CONCURRENT_COMMANDS` | Max concurrent commands | No | 5 |

### Secrets

Create a secret for database credentials:

```bash
kubectl -n rdev create secret generic rdev-api-secrets \
  --from-literal=postgres-password=your-password
```

Or use the manifest:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: rdev-api-secrets
  namespace: rdev
type: Opaque
stringData:
  postgres-password: your-secure-password
```

### ConfigMap

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: rdev-api-config
  namespace: rdev
data:
  POSTGRES_HOST: "postgres.databases.svc"
  POSTGRES_DB: "rdev"
  RDEV_NAMESPACE: "rdev"
  RATE_LIMIT_RPS: "10"
  CONCURRENT_COMMANDS: "5"
```

## Kubernetes Manifests

### Namespace

```yaml
apiVersion: v1
kind: Namespace
metadata:
  name: rdev
  labels:
    app.kubernetes.io/name: rdev
```

### Deployment

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rdev-api
  namespace: rdev
spec:
  replicas: 2
  selector:
    matchLabels:
      app: rdev-api
  template:
    metadata:
      labels:
        app: rdev-api
    spec:
      serviceAccountName: rdev-api
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
      containers:
        - name: rdev-api
          image: your-registry/rdev-api:latest
          ports:
            - containerPort: 8080
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: rdev-api-secrets
                  key: postgres-password
          envFrom:
            - configMapRef:
                name: rdev-api-config
          securityContext:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
```

### Service

```yaml
apiVersion: v1
kind: Service
metadata:
  name: rdev-api
  namespace: rdev
spec:
  selector:
    app: rdev-api
  ports:
    - port: 80
      targetPort: 8080
```

### Ingress

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rdev-api
  namespace: rdev
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
spec:
  ingressClassName: traefik
  rules:
    - host: rdev.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: rdev-api
                port:
                  number: 80
  tls:
    - hosts:
        - rdev.example.com
      secretName: rdev-tls
```

### RBAC

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rdev-api
  namespace: rdev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rdev-api-role
  namespace: rdev
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rdev-api-binding
  namespace: rdev
subjects:
  - kind: ServiceAccount
    name: rdev-api
roleRef:
  kind: Role
  name: rdev-api-role
  apiGroup: rbac.authorization.k8s.io
```

### Pod Disruption Budget

```yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: rdev-api-pdb
  namespace: rdev
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: rdev-api
```

### Network Policy

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: rdev-api-policy
  namespace: rdev
spec:
  podSelector:
    matchLabels:
      app: rdev-api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: databases
      ports:
        - protocol: TCP
          port: 5432
```

## Database Setup

### Create Database

```sql
CREATE DATABASE rdev;
CREATE USER rdev_user WITH PASSWORD 'secure-password';
GRANT ALL PRIVILEGES ON DATABASE rdev TO rdev_user;
```

### Migrations

Migrations run automatically on startup. To run manually:

```bash
# Connect to pod
kubectl -n rdev exec -it deployment/rdev-api -- sh

# Check migration status
psql $DATABASE_URL -c "SELECT * FROM schema_migrations;"
```

## Scaling

### Horizontal Pod Autoscaler

```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: rdev-api-hpa
  namespace: rdev
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: rdev-api
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
```

## Upgrading

### Rolling Update

```bash
# Update image
kubectl -n rdev set image deployment/rdev-api \
  rdev-api=your-registry/rdev-api:new-version

# Watch rollout
kubectl -n rdev rollout status deployment/rdev-api
```

### Rollback

```bash
# Rollback to previous version
kubectl -n rdev rollout undo deployment/rdev-api

# Rollback to specific revision
kubectl -n rdev rollout undo deployment/rdev-api --to-revision=2
```

## Health Checks

### Liveness

```bash
curl http://rdev-api/health
```

Returns `200 OK` if the service is running.

### Readiness

```bash
curl http://rdev-api/ready
```

Returns `200 OK` if database and K8s are connected.

## Troubleshooting

### Pod Not Starting

```bash
# Check pod events
kubectl -n rdev describe pod -l app=rdev-api

# Check logs
kubectl -n rdev logs -l app=rdev-api
```

### Database Connection Failed

1. Check secret is mounted correctly
2. Verify database host is reachable
3. Check network policy allows egress

### K8s API Errors

1. Verify ServiceAccount has correct RBAC
2. Check namespace configuration
3. Verify API server connectivity
