docs: update build/deploy docs for Woodpecker CI
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
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>
This commit is contained in:
parent
2fd52dcfed
commit
96c9389c97
215
.claude/guides/ops/deploying.md
Normal file
215
.claude/guides/ops/deploying.md
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
|
||||||
|
|
||||||
|
# Verify connection
|
||||||
|
kubectl cluster-info
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Secrets (First Time Only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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`, `patch` on `deployments` (apps API group)
|
||||||
|
|
||||||
|
This follows least-privilege principles - only the minimum permissions needed for `kubectl set image` to work.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Pod not starting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl describe pod -n rdev <pod-name>
|
||||||
|
kubectl logs -n rdev <pod-name> --previous
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission denied
|
||||||
|
|
||||||
|
Check RBAC:
|
||||||
|
```bash
|
||||||
|
kubectl auth can-i exec pods -n rdev --as=system:serviceaccount:rdev:rdev-api
|
||||||
|
```
|
||||||
|
|
||||||
|
### Image pull error
|
||||||
|
|
||||||
|
Verify registry access:
|
||||||
|
```bash
|
||||||
|
kubectl get events -n rdev --sort-by='.lastTimestamp'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database connection failed
|
||||||
|
|
||||||
|
Check secret and network policy:
|
||||||
|
```bash
|
||||||
|
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
|
||||||
|
|
||||||
|
1. Push to `git.threesix.ai/jordan/rdev` triggers Woodpecker
|
||||||
|
2. 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`
|
||||||
|
|
||||||
|
### Manual Deploy (if needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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 server
|
||||||
|
- `rdev/worker:latest` - Worker pool
|
||||||
|
- `rdev/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](./releasing.md) - Build and publish new versions
|
||||||
|
- [Database Guide](./database.md)
|
||||||
|
- [Kubernetes Adapter](../services/kubernetes.md)
|
||||||
|
- [External Health Diagnostics](./external-health-diagnostics.md) - Debug registry/CI/git issues
|
||||||
135
.claude/guides/ops/releasing.md
Normal file
135
.claude/guides/ops/releasing.md
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# Releasing rdev-api
|
||||||
|
|
||||||
|
**When to use:** Creating a new versioned release with changelog, container image, and git tag.
|
||||||
|
|
||||||
|
## Automated Releases (Recommended)
|
||||||
|
|
||||||
|
Push to main branch triggers Woodpecker CI to build and deploy automatically:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Just push - Woodpecker handles the rest
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# Or push to both remotes
|
||||||
|
GITEA_TOKEN=$(kubectl get secret rdev-credentials -n rdev -o jsonpath='{.data.GITEA_TOKEN}' | base64 -d)
|
||||||
|
git push https://jordan:${GITEA_TOKEN}@git.threesix.ai/jordan/rdev.git main
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Images are built via kaniko and pushed to `registry.threesix.ai/rdev/*`.
|
||||||
|
|
||||||
|
## Prerequisites (Manual Releases)
|
||||||
|
|
||||||
|
- Go installed (for local binary builds if needed)
|
||||||
|
- KUBECONFIG set: `export KUBECONFIG=~/.kube/orchard9-k3sf.yaml`
|
||||||
|
- Access to Gitea (`git.threesix.ai/jordan/rdev`)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Release and deploy in one command
|
||||||
|
./scripts/release.sh v0.8.1 "Fix worker ID config bug" --deploy
|
||||||
|
|
||||||
|
# Release only (no deploy)
|
||||||
|
./scripts/release.sh v0.8.1 "Fix worker ID config bug"
|
||||||
|
```
|
||||||
|
|
||||||
|
## What the Release Script Does
|
||||||
|
|
||||||
|
The script (`scripts/release.sh`) performs these steps in order:
|
||||||
|
|
||||||
|
1. **Creates changelog** - Writes `changelog/<version>.md` with date and message
|
||||||
|
2. **Updates deployment** - Patches `deployments/k8s/base/rdev-api.yaml` with new image tag
|
||||||
|
3. **Commits and pushes** - Commits changelog and deployment changes to main
|
||||||
|
4. **Builds binary** - Cross-compiles for linux/amd64 with version embedded
|
||||||
|
5. **Builds container** - Creates `ghcr.io/orchard9/rdev-api:<version>` image
|
||||||
|
6. **Pushes image** - Uploads to GitHub Container Registry
|
||||||
|
7. **Tags release** - Creates annotated git tag and pushes it
|
||||||
|
|
||||||
|
With `--deploy` flag, it also:
|
||||||
|
8. **Runs migrations** - Executes all SQL migrations as `rdev` superuser
|
||||||
|
9. **Applies manifest** - `kubectl apply` the deployment YAML
|
||||||
|
10. **Restarts deployment** - Triggers rollout with new image
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/release.sh <version> "<changelog message>" [--deploy]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Argument | Description | Example |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `version` | Semver tag (with or without `v` prefix) | `v0.8.1` or `0.8.1` |
|
||||||
|
| `message` | Changelog entry describing the release | `"Add worker pool support"` |
|
||||||
|
| `--deploy` | Also run migrations and deploy to k3s | (optional flag) |
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full release + deploy (recommended)
|
||||||
|
./scripts/release.sh v0.9.0 "Add project templates" --deploy
|
||||||
|
|
||||||
|
# Bug fix release + deploy
|
||||||
|
./scripts/release.sh v0.8.2 "Fix nil pointer in command handler" --deploy
|
||||||
|
|
||||||
|
# Release only (deploy later manually)
|
||||||
|
./scripts/release.sh v0.8.3 "Update dependency versions"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Deploy (if not using --deploy)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
|
||||||
|
kubectl apply -f deployments/k8s/base/rdev-api.yaml
|
||||||
|
kubectl rollout restart -n rdev deployment/rdev-api
|
||||||
|
```
|
||||||
|
|
||||||
|
## Artifacts Created
|
||||||
|
|
||||||
|
| Artifact | Location |
|
||||||
|
|----------|----------|
|
||||||
|
| Changelog | `changelog/<version>.md` |
|
||||||
|
| Container images | `registry.threesix.ai/rdev/{api,worker,claudebox}:<commit-sha>` |
|
||||||
|
| Git tag | `<version>` (annotated) |
|
||||||
|
| Updated deployment | `deployments/k8s/base/rdev-api.yaml` |
|
||||||
|
|
||||||
|
## Image Registry
|
||||||
|
|
||||||
|
Images are now stored in Zot (`registry.threesix.ai`) instead of ghcr.io:
|
||||||
|
|
||||||
|
| Image | Path |
|
||||||
|
|-------|------|
|
||||||
|
| API server | `registry.threesix.ai/rdev/api:latest` |
|
||||||
|
| Worker | `registry.threesix.ai/rdev/worker:latest` |
|
||||||
|
| Claudebox | `registry.threesix.ai/rdev/claudebox:latest` |
|
||||||
|
|
||||||
|
Tags: `latest` and `${CI_COMMIT_SHA:0:8}` (8-char commit hash)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Docker push fails
|
||||||
|
|
||||||
|
Ensure you're authenticated to ghcr.io:
|
||||||
|
```bash
|
||||||
|
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build fails
|
||||||
|
|
||||||
|
Check Go environment:
|
||||||
|
```bash
|
||||||
|
go version
|
||||||
|
go env GOOS GOARCH
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git push rejected
|
||||||
|
|
||||||
|
Ensure you have push access and main is up to date:
|
||||||
|
```bash
|
||||||
|
git pull origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [Deploying to k3s](./deploying.md)
|
||||||
|
- [Credentials Management](./credentials.md)
|
||||||
12
CLAUDE.md
12
CLAUDE.md
@ -93,18 +93,14 @@ go run ./cmd/rdev-api
|
|||||||
# Run tests
|
# Run tests
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|
||||||
# Release + deploy (one command)
|
# Automated deploy (push triggers Woodpecker CI)
|
||||||
./scripts/release.sh v0.10.1 "Description of changes" --deploy
|
git push origin main # Builds and deploys automatically via Woodpecker
|
||||||
|
|
||||||
# Release only (no deploy)
|
# Manual deploy (if Woodpecker unavailable)
|
||||||
./scripts/release.sh v0.10.1 "Description of changes"
|
|
||||||
|
|
||||||
# Manual deploy (if needed)
|
|
||||||
kubectl apply -f deployments/k8s/base/rdev-api.yaml
|
kubectl apply -f deployments/k8s/base/rdev-api.yaml
|
||||||
kubectl rollout restart -n rdev deployment/rdev-api
|
kubectl rollout restart -n rdev deployment/rdev-api
|
||||||
|
|
||||||
# Deploy claudebox worker (when Dockerfile changes)
|
# Images are at registry.threesix.ai/rdev/{api,worker,claudebox}
|
||||||
./scripts/build-push.sh v0.4.0 claudebox && kubectl apply -f deployments/k8s/base/claudebox.yaml && kubectl rollout restart -n rdev statefulset/claudebox
|
|
||||||
|
|
||||||
# Verify pods
|
# Verify pods
|
||||||
kubectl get pods -n rdev
|
kubectl get pods -n rdev
|
||||||
|
|||||||
@ -48,29 +48,30 @@ Note: Some coverage targets not met, but core functionality is well-tested.
|
|||||||
|
|
||||||
## Release
|
## Release
|
||||||
|
|
||||||
### Build
|
### Automated (Recommended)
|
||||||
|
|
||||||
|
Push to main triggers Woodpecker CI to build and deploy:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build binary
|
# Push to both remotes - Woodpecker builds and deploys automatically
|
||||||
GOOS=linux GOARCH=amd64 go build -o rdev-api ./cmd/rdev-api
|
git push origin main
|
||||||
|
GITEA_TOKEN=$(kubectl get secret rdev-credentials -n rdev -o jsonpath='{.data.GITEA_TOKEN}' | base64 -d)
|
||||||
# Build Docker image
|
git push https://jordan:${GITEA_TOKEN}@git.threesix.ai/jordan/rdev.git main
|
||||||
docker build -t ghcr.io/orchard9/rdev-api:1.0.0 .
|
|
||||||
|
|
||||||
# Push image
|
|
||||||
docker push ghcr.io/orchard9/rdev-api:1.0.0
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Images are built via kaniko and pushed to `registry.threesix.ai/rdev/*`.
|
||||||
|
|
||||||
### Tag
|
### Tag
|
||||||
```bash
|
```bash
|
||||||
git tag -a v1.0.0 -m "Release v1.0.0"
|
git tag -a v1.0.0 -m "Release v1.0.0"
|
||||||
git push origin v1.0.0
|
git push origin v1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Deploy
|
### Manual Deploy (if needed)
|
||||||
```bash
|
```bash
|
||||||
# Update image tag in kustomization
|
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
|
||||||
# Apply to cluster
|
kubectl apply -f deployments/k8s/base/rdev-api.yaml
|
||||||
kubectl apply -k deployments/k8s/overlays/prod
|
kubectl rollout restart -n rdev deployment/rdev-api
|
||||||
|
|
||||||
# Verify deployment
|
# Verify deployment
|
||||||
kubectl -n rdev rollout status deployment/rdev-api
|
kubectl -n rdev rollout status deployment/rdev-api
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user