My personal k3s cluster setup.
./dev/local development./charts/in-repo Helm charts./tools/cluster tools (non-Helm manifests)./apps/apps running in the cluster
kube:*: cluster-agnostic operations using plainkubectl/helmagainst the selected mise environment (KUBECONFIG)local:*: local-only lifecycle tasks (k3s-in-Docker)prod:*: prod wrappers aroundkube:*tasks with guardrails (e.g.confirm)
Within kube:*:
kube:operators:*: install/uninstall/diff cluster operators (Headlamp, OpenClaw operator, Infisical operator)kube:secrets:*: prod-only secret sync resources (InfisicalSecret)
kube:tools:* is a convenience wrapper:
kube:tools:applyrunskube:operators:applythenkube:secrets:applykube:tools:diffrunskube:operators:diffthenkube:secrets:diffkube:tools:deleterunskube:secrets:deletethenkube:operators:delete
- Have mise installed
mise trustto allow mise to use themise.tomlmise install- Create
.env.local(used bymise -E localtasks):
KUBECONFIG=dev/k3s/kubeconfig/kubeconfig.yaml
OPENCLAW_OWNER_PHONE=+15551234567
OPENCLAW_GATEWAY_TOKEN=REPLACE_METip: start from .env.local.example.
mise -E local run local:up
Prod uses mise.prod.toml (loads .env.prod). Set KUBECONFIG in .env.prod (recommended: point at a kubeconfig outside this repo, e.g. ~/kubeconfigs/barka.yaml).
Prod (tools install via Helm; Infisical via Universal Auth):
- Put
KUBECONFIG,INFISICAL_CLIENT_ID, andINFISICAL_CLIENT_SECRETin.env.prod(recommended) or export them in your shell.
mise -E prod run prod:tools:applyProd secrets are synced from Infisical by an InfisicalSecret resource rendered from charts/openclaw/templates/infisical.yaml.
- Requirements: Docker Desktop running
- Compose file:
dev/k3s/docker-compose.yml
Start the cluster:
mise -E local run local:upUse kubectl (plain kubectl, kubeconfig generated by k3s):
export KUBECONFIG=dev/k3s/kubeconfig/kubeconfig.yaml
kubectl get nodesOr via mise:
mise -E local run kube:kubectl -- get pods -ANote: local:up installs tools by running kube:tools:apply (Helm-based) using the selected KUBECONFIG.
Endpoints:
- Kubernetes API: https://localhost:6443
- Ingress (Traefik): http://localhost:8080 and https://localhost:8443
Stop the cluster:
mise -E local run local:downReset (delete cluster data volume, regenerates certs, etc.):
mise -E local run local:resetHeadlamp is installed by mise -E local run local:up from charts/headlamp/.
URL: http://headlamp.localhost:8080/
Prod: Headlamp has no Ingress; use port-forward:
mise -E prod run kube:headlamp:port-forwardLogin token (creates a short-lived token):
mise -E <env> run kube:headlamp:tokenTo uninstall tools:
mise -E <env> run kube:tools:deleteThe OpenClaw operator is installed by kube:tools:apply, and the instance is managed by the in-repo Helm chart at charts/openclaw/ via kube:apps:apply.
OpenClaw autoupdate (pod): enable the operator's OCI polling by setting instance.autoUpdate.enabled=true in charts/openclaw/values.yaml.
Local secrets: set OPENCLAW_GATEWAY_TOKEN in .env.local (required). OPENCLAW_OWNER_PHONE and OPENAI_API_KEY are optional. Then run:
Web search (optional): set PERPLEXITY_API_KEY (or OPENROUTER_API_KEY) in .env.local.
Web fetch fallback (optional): set FIRECRAWL_API_KEY.
mise -E local run local:openclaw:secrets:apply
mise -E local run kube:apps:applyProduction secrets: Infisical syncs into secret/openclaw-secrets in the openclaw namespace (must include OPENCLAW_GATEWAY_TOKEN).
Port-forward the instance service:
mise -E local run kube:openclaw:port-forwardLocal Ingress:
Browser automation:
- Local enables the Chromium sidecar (see
charts/openclaw/values-local.yaml).
The OpenClaw Helm chart installs the GitHub CLI (gh) into the instance's persistent volume via an init container (init-deps). The binary ends up at /home/openclaw/.openclaw/.local/bin/gh and is already on PATH.
SSH key material is expected to come from secret/openclaw-secrets (prod: synced from Infisical; local: created by local:openclaw:secrets:apply). The init container writes it into /home/openclaw/.openclaw/.ssh/.
Required secret keys (Infisical or local env):
SSH_PRIVATE_KEY: aned25519(or RSA) private key PEMSSH_KNOWN_HOSTS:known_hostsentries for the git hosts you will access
Tip: generate known_hosts content locally with (replace the hostname as needed):
ssh-keyscan -t ed25519 <git-host>Login guidance (inside the pod):
mise -E <env> run kube:kubectl -- -n openclaw exec -it openclaw-0 -- sh
gh --version
gh auth login
gh auth statusNote: SSH keys are for git@github.com:... operations; gh API access still needs a token. For a non-interactive setup, store a token as GH_TOKEN in Infisical (or export it in .env.local); gh will pick it up automatically without running gh auth login.
gh stores the auth token on disk in hosts.yml. In this cluster the config directory is set to GH_CONFIG_DIR=/home/openclaw/.openclaw/.config/gh, so the file is:
/home/openclaw/.openclaw/.config/gh/hosts.yml
If GITHUB_PAT_KEY is present in secret/openclaw-secrets, the init container will write hosts.yml automatically.
The file is written in the same shape as gh expects (including the users.<name>.oauth_token entry). The username defaults to AntonioClawbot and can be changed via instance.depsInit.gh.user.
If CLAW_EMAIL is present in secret/openclaw-secrets, the init container configures git identity:
user.nameis set toinstance.depsInit.gh.useruser.emailis set toCLAW_EMAIL
The OpenClaw Helm chart installs gogcli into the instance's persistent volume via the same init container (init-deps). The binary ends up at /home/openclaw/.openclaw/.local/bin/gog and is already on PATH.
Verify inside the pod:
mise -E <env> run kube:kubectl -- -n openclaw exec -it openclaw-0 -- sh
gog --version