Phase 2 references for the host-agent Dune adapter, moved out of volatile /tmp
into docs/reference-repos/ (per Commander). Three upstream projects, .git +
node_modules + compiled binaries stripped (16MB source). Nested AI-instruction
files (.claude/, CLAUDE.md) removed so they don't pollute Corrosion sessions.
- icehunter/ dune-admin (Go+React) — 4 control planes; SETUP_DOCKER.md is the
closest analog to our agent's Dune docker control plane (compose
lifecycle, docker logs, RabbitMQ-via-exec, dune Postgres schema)
- adainrivers/ Rust/Tauri desktop — SSH+k8s BattleGroup control, maintenance
daemon, in-game admin console (Rust idiom reference)
- the4rchangel/ Node web UI replacing battlegroup.bat — matches the Commander's
Hyper-V self-host path + game-config schema
See docs/reference-repos/README.md for the full index + how we use each.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.1 KiB
Provider: kubectl (Kubernetes / k3s)
Use this provider when your Dune server runs inside a Kubernetes cluster (e.g. k3s on a VM) and dune-admin runs on your local machine or another host with SSH access to that VM.
All commands run over SSH — no exposed ports, no VPN.
your machine
└─ SSH tunnel → VM
├─ kubectl → battlegroup CRDs / pod logs
└─ TCP tunnel → PostgreSQL (pod IP:15432)
Prerequisites
| Requirement | Notes |
|---|---|
| Go 1.21+ | brew install go or https://go.dev/dl/ |
| SSH key | Private key authorised on the VM |
| VM access | Port 22 reachable; SSH user needs passwordless sudo kubectl |
Quick start (wizard)
# Place SSH key (checked automatically in this order):
# ./sshKey │ ~/.dune-admin/sshKey │ ~/.ssh/dune │ ~/.ssh/id_ed25519 │ ~/.ssh/id_rsa
cp /path/to/key ./sshKey && chmod 600 ./sshKey
make setup # prompts for VM host:port, discovers namespace + DB password automatically
make build # builds frontend + dune-admin binary
./dune-admin
The wizard:
- Locates your SSH key
- SSHes into the VM
- Runs
kubectl get pods -Ato find the database pod and namespace - Reads
~/.dune/<battlegroup>.yamlon the VM for DB credentials - Writes
~/.dune-admin/config.yaml
External VM deploy example (dune@192.168.0.72)
cd /Volumes/Engineering/Icehunter/dune-admin
# Pull kubeconfig from VM and point kubectl at the external cluster.
mkdir -p ~/.kube
ssh dune@192.168.0.72 "sudo cat /etc/rancher/k3s/k3s.yaml" > ~/.kube/dune-external.yaml
sed -i '' 's/127.0.0.1/192.168.0.72/g' ~/.kube/dune-external.yaml
export KUBECONFIG=~/.kube/dune-external.yaml
kubectl get nodes
# Configure dune-admin runtime values.
make setup
# Ensure these are set in ~/.dune-admin/config.yaml for container runtime:
# market_bot_enabled: true
# market_bot_item_data: /app/item-data.json
# market_bot_cache_db: /data/market-bot-cache.db
# Build local image and import it into k3s runtime on the VM.
docker buildx build --platform linux/amd64 -f deploy/Dockerfile -t dune-admin:local --load .
docker save dune-admin:local | ssh dune@192.168.0.72 "sudo k3s ctr images import -"
# Render deployment manifest from ~/.dune-admin/config.yaml and switch image tag.
make render-k8s
sed -i '' 's#ghcr.io/icehunter/dune-admin:latest#dune-admin:local#g' deploy/k8s/dune-admin.rendered.yaml
# Deploy and wait for readiness.
kubectl apply -f deploy/k8s/dune-admin.rendered.yaml
kubectl -n dune-admin rollout status deploy/dune-admin
kubectl -n dune-admin get pods,svc
# Verify API and bot from inside the cluster.
kubectl -n dune-admin run curl --rm -it --restart=Never --image=curlimages/curl -- \
sh -c "curl -s http://dune-admin:8080/api/v1/market-bot/status"
# Local access from your laptop.
kubectl -n dune-admin port-forward svc/dune-admin 8080:8080
Scripted deploy (Linux/macOS + Windows)
From repo root:
./deploy.sh
./deploy.ps1
On Windows, if script execution is blocked, run once:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Both scripts run the full k8s flow:
- Pull kubeconfig from VM (
dune@192.168.0.72by default) unless skipped - Build a fresh timestamped image tag (
dune-admin:local-<timestamp>by default) - Import image into VM k3s runtime (
k3s ctr images import) - Render and apply
deploy/k8s/dune-admin.rendered.yaml - Auto-fix embedded bot deployment settings in the rendered manifest:
MARKET_BOT_ENABLED: "true"market_bot_enabled: truemarket_bot_item_data: /app/item-data.jsonmarket_bot_cache_db: /data/market-bot-cache.db
- Restart rollout, wait for old terminating pods to drain, then run in-cluster health checks for:
/api/v1/statusreachable/returns HTTP 200 (no UI 404)/api/v1/market-bot/statusreports"enabled":true
- Open
kubectl port-forwardon127.0.0.1:8080(unless disabled)
SSH auth behavior in both scripts:
- If
./sshKeyexists, it is used first (-i ./sshKey) - If key auth fails or no key is present, SSH falls back to password prompt
Script options
| Purpose | Bash | PowerShell |
|---|---|---|
| VM user | --vm-user dune |
-VmUser dune |
| VM host | --vm-host 192.168.0.72 |
-VmHost 192.168.0.72 |
| SSH key path | --ssh-key ./sshKey |
-SshKeyPath .\sshKey |
| Kubeconfig path | --kubeconfig ~/.kube/dune-external.yaml |
-KubeconfigPath "$HOME/.kube/dune-external.yaml" |
| Image tag | --image dune-admin:local |
-Image dune-admin:local |
| Namespace | --namespace dune-admin |
-Namespace dune-admin |
| Manifest path | --manifest deploy/k8s/dune-admin.rendered.yaml |
-Manifest deploy/k8s/dune-admin.rendered.yaml |
| Skip kubeconfig pull | --skip-kubeconfig |
-SkipKubeconfig |
| Skip image build | --skip-build |
-SkipBuild |
| Skip VM image import | --skip-image-import |
-SkipImageImport |
| Skip port-forward | --no-port-forward |
-NoPortForward |
First deploy vs quick redeploy
First deploy:
./deploy.sh
Quick redeploy (reuse kubeconfig, no auto port-forward):
./deploy.sh --skip-kubeconfig --no-port-forward
Quick redeploy with the exact same image tag (advanced):
./deploy.sh --image dune-admin:local --skip-kubeconfig --no-port-forward
Override defaults with flags (same names on both scripts), e.g.:
./deploy.sh --vm-user dune --vm-host 192.168.0.72 --image dune-admin:local --no-port-forward
./deploy.ps1 -VmUser dune -VmHost 192.168.0.72 -Image dune-admin:local -NoPortForward
Manual config (~/.dune-admin/config.yaml)
control: kubectl
ssh_host: 192.168.0.72:22 # VM host:port
ssh_user: dune # SSH user
ssh_key: /home/you/.ssh/key # absolute path; omit to use auto-detection
db_host: 127.0.0.1 # unused for kubectl — pod IP is discovered automatically
db_port: 15432
db_user: postgres
db_pass: yourpassword
db_name: dune
db_schema: dune
# Optional — discovered automatically if omitted:
control_namespace: funcom-seabass-mybattlegroup
# Optional broker command path:
broker_game_addr: 10.43.48.246:5672
broker_admin_addr: 10.43.189.193:5672
broker_tls: true
# Optional:
backup_dir: /funcom/artifacts/database-dumps/mybattlegroup
listen_addr: :8080
scrip_currency: 1
What works
| Feature | Supported |
|---|---|
| Battlegroup status (phase, servers) | Yes |
| Start / stop / restart | Yes — kubectl patch battlegroup |
| Update / backup | Yes — battlegroup.sh |
| Pod list | Yes |
| Log streaming | Yes — kubectl logs -f |
| DB access | Yes — tunnelled through SSH to pod IP |
| RabbitMQ broker commands | Yes — kubectl exec into broker pod |
| Backup download / upload / restore | Yes |
Backward compatibility
Existing .env files with just SSH_HOST, SSH_USER, DB_PASS, etc. continue to work unchanged. The control plane defaults to kubectl whenever SSH_HOST is set, and the namespace is auto-discovered at startup.
Troubleshooting
Battlegroup tab shows nothing — the namespace was not discovered. Check that the SSH user can run sudo kubectl get pods -A. You can also pin it explicitly with control_namespace in config.yaml.
DB connection fails — pod discovery succeeded but DB password is wrong. Delete ~/.dune-admin/config.yaml and re-run make setup.
"sudo: kubectl: command not found" — kubectl is not in the sudo-safe PATH on the VM. Add /usr/local/bin (or wherever kubectl lives) to /etc/sudoers secure_path.
Port-forward works but http://127.0.0.1:8080 returns 404 — you are running an old image that does not contain the built frontend (/app/dist). Rebuild and redeploy with the deploy script.
Market bot panel shows inactive after deploy — verify:
market_bot_enabled: truein~/.dune-admin/config.yamlmarket_bot_item_data: /app/item-data.jsonmarket_bot_cache_db: /data/market-bot-cache.db
Then redeploy and check:
kubectl -n dune-admin logs deploy/dune-admin --tail=120
kubectl -n dune-admin run curl --rm -it --restart=Never --image=curlimages/curl -- \
sh -c "curl -s http://dune-admin:8080/api/v1/market-bot/status"