Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- deploying.md: Add Woodpecker CI section, update constraints - releasing.md: Add automated releases via Woodpecker, Zot registry - RELEASE_CHECKLIST.md: Update build/deploy commands - CLAUDE.md: Update quick reference for automated deploys Images now at registry.threesix.ai/rdev/* instead of ghcr.io Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.3 KiB
5.3 KiB
Deploying to k3s
When to use: Deploying rdev-api or claudebox pods to the k3s cluster.
Prerequisites
- Access to orchard9 k3s cluster
- kubectl installed
- kubeconfig file at
~/.kube/orchard9-k3sf.yaml
Quick Deploy
# CRITICAL: Always set kubeconfig first
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
# Deploy all resources
kubectl apply -k deployments/k8s/base
# Verify deployment
kubectl get pods -n rdev
kubectl get svc -n rdev
What Gets Deployed
The Kustomize base deploys:
| Resource | Name | Purpose |
|---|---|---|
| Namespace | rdev |
Isolation |
| Deployment | rdev-api |
API server |
| StatefulSet | claudebox |
Claude Code pods |
| Service | rdev-api |
Internal service |
| ServiceAccount | rdev-api |
RBAC identity |
| Role/RoleBinding | rdev-api |
Namespace permissions |
| ClusterRole/Binding | rdev-api |
Cluster-wide permissions |
| PVC | workspace-pvc |
Shared workspace volume |
| Secret | claude-credentials |
Claude auth (manual) |
Deployment Steps
1. Set Kubeconfig
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
# Verify connection
kubectl cluster-info
2. Create Secrets (First Time Only)
# Claude credentials secret
kubectl create secret generic claude-credentials \
-n rdev \
--from-file=credentials.json=/path/to/credentials.json
# Database credentials (if using external postgres)
kubectl create secret generic rdev-db \
-n rdev \
--from-literal=host=postgres.example.com \
--from-literal=password=secret
3. Apply Manifests
# Full deployment
kubectl apply -k deployments/k8s/base
# Or apply individually
kubectl apply -f deployments/k8s/base/namespace.yaml
kubectl apply -f deployments/k8s/base/rdev-api.yaml
kubectl apply -f deployments/k8s/base/claudebox.yaml
4. Verify
# Check pods
kubectl get pods -n rdev
# Expected: rdev-api-xxx Running, claudebox-0 Running
# Check logs
kubectl logs -n rdev deployment/rdev-api
# Test API
kubectl port-forward -n rdev svc/rdev-api 8080:8080
curl http://localhost:8080/health
Updating Deployments
Rolling Update
# Update image tag in manifests, then:
kubectl apply -k deployments/k8s/base
# Or force rollout
kubectl rollout restart deployment/rdev-api -n rdev
Watch Rollout
kubectl rollout status deployment/rdev-api -n rdev
Manifest Structure
deployments/k8s/
└── base/
├── kustomization.yaml # Kustomize config
├── namespace.yaml # rdev namespace
├── rdev-api.yaml # API deployment + RBAC
├── claudebox.yaml # StatefulSet for Claude pods
└── pvc-workspace.yaml # Shared workspace PVC
RBAC Permissions
rdev-api requires:
- Namespace-scoped: Pod exec, ConfigMap read
- Cluster-scoped: Deployments, Services, Ingresses (for project deployment feature)
Woodpecker CI Deployer RBAC
The woodpecker-deployer-rbac.yaml manifest grants Woodpecker CI permission to deploy projects. Without this, deploy steps fail with permission errors.
Why it's needed: Woodpecker pipeline steps run as the default ServiceAccount in the threesix namespace, but need to kubectl set image on deployments in the projects namespace.
Permissions granted:
get,list,patchondeployments(apps API group)
This follows least-privilege principles - only the minimum permissions needed for kubectl set image to work.
Troubleshooting
Pod not starting
kubectl describe pod -n rdev <pod-name>
kubectl logs -n rdev <pod-name> --previous
Permission denied
Check RBAC:
kubectl auth can-i exec pods -n rdev --as=system:serviceaccount:rdev:rdev-api
Image pull error
Verify registry access:
kubectl get events -n rdev --sort-by='.lastTimestamp'
Database connection failed
Check secret and network policy:
kubectl get secret rdev-db -n rdev -o yaml
kubectl exec -n rdev deployment/rdev-api -- env | grep DB_
Automated CI/CD via Woodpecker
rdev now uses Woodpecker CI for automated builds and deploys:
git push → Gitea → Woodpecker → kaniko → registry.threesix.ai → kubectl deploy
How It Works
- Push to
git.threesix.ai/jordan/rdevtriggers Woodpecker - Woodpecker runs
.woodpecker.yml:- Tests with
go test ./... - Builds images via
woodpeckerci/plugin-kaniko - Pushes to
registry.threesix.ai/rdev/{api,worker,claudebox} - Deploys via
kubectl set image
- Tests with
Manual Deploy (if needed)
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
kubectl apply -f deployments/k8s/base/rdev-api.yaml
kubectl rollout restart -n rdev deployment/rdev-api
Image Registry
Images are stored in Zot at registry.threesix.ai/rdev/:
rdev/api:latest- API serverrdev/worker:latest- Worker poolrdev/claudebox:latest- Claude Code container
Constraints
- ON-PREM k3s - Not GKE/EKS, always use local kubeconfig
- Kustomize only - No ArgoCD or Helm
- Woodpecker CI - Automated builds on push to main
Related
- Releasing - Build and publish new versions
- Database Guide
- Kubernetes Adapter
- External Health Diagnostics - Debug registry/CI/git issues