Deploy Karmada Dashboard (kind dev env)
Brings up karmada-dashboard-api + karmada-dashboard-web (+ kubernetes-dashboard-api)
on the karmada-host cluster and exposes the web UI on the host's 8000 port.
This skill encodes the working procedure and the non-obvious gotchas that the README QuickStart misses. Follow it top to bottom; skip steps only after verifying their state.
Assumptions / prerequisites
- A Karmada control plane is already running (here: a kind dev env with clusters
karmada-host,member1/2/3). Verify before doing anything:export KUBECONFIG="$HOME/.kube/karmada.config" kubectl config use-context karmada-host kubectl get deployments.apps -n karmada-system # karmada-apiserver et al should be READY - Certs exist in
$HOME/.karmada(ca.crt,ca.key,ca-config.json). - Tools available:
kubectl,docker. Run all commands from the repo root. - The node can reach Docker Hub — the dashboard images (
karmada/karmada-dashboard-*,karmada/kubernetes-dashboard-api, allimagePullPolicy: IfNotPresent) are pulled automatically on deploy. No manual image build/load is needed. - Two contexts exist in
~/.kube/karmada.config:karmada-host(where the dashboard runs) andkarmada-apiserver(where the login ServiceAccount/token lives). Do not mix them up — this is a common source of errors.
Step 1 — Create the kubeconfig secret
The deployment manifests mount a secret named karmada-dashboard-config
(see secretName: karmada-dashboard-config in artifacts/dashboard/karmada-dashboard-{web,api}.yaml).
Create it with the helper script (it generates the dashboard client cert on demand from
the CA in $HOME/.karmada):
export KUBECONFIG="$HOME/.kube/karmada.config"
bash hack/generate-karmada-dashboard-kubeconfig.sh "$HOME/.kube/karmada.config" karmada-host
# -> creates secret/karmada-dashboard-config in namespace karmada-system
GOTCHA: the secret name must be exactly karmada-dashboard-config. Creating a plain
kubeconfig secret instead (an older README instruction, now fixed) leaves the pods stuck
in ContainerCreating with
MountVolume.SetUp failed ... secret "karmada-dashboard-config" not found.
Step 2 — Deploy the dashboard (NodePort overlay)
Images are pulled automatically by the node.
export KUBECONFIG="$HOME/.kube/karmada.config"
kubectl config use-context karmada-host
kubectl apply -k artifacts/overlays/nodeport-mode
Wait for rollout (first run also pulls images, so allow time):
for d in karmada-dashboard-web karmada-dashboard-api kubernetes-dashboard-api; do
kubectl rollout status deployment/$d -n karmada-system --timeout=180s
done
kubectl get pods -n karmada-system | grep -i dashboard # all should be 1/1 Running
Step 3 — Create the login ServiceAccount and get the JWT token
Switch context to karmada-apiserver for these (the SA/token live on the Karmada API
server, not the host cluster):
export KUBECONFIG="$HOME/.kube/karmada.config"
kubectl config use-context karmada-apiserver
kubectl apply -f artifacts/dashboard/karmada-dashboard-sa.yaml
# optional: member-cluster proxy access for cluster management
kubectl apply -f artifacts/dashboard/karmada-dashboard-clusterrolebinding.yaml
# fetch the token (paste into the dashboard "Enter token" field)
kubectl -n karmada-system get secret/karmada-dashboard-secret \
-o go-template="{{.data.token | base64decode}}"
Step 4 — Expose the web UI on the host's 8000 port
GOTCHA: On kind, the NodePort (32000) only lives on the node container's internal
IP, so it is not reachable from the host network. Use kubectl port-forward to publish
the web service on the host's 8000 port (the README's documented alternative). Bind
--address 0.0.0.0 so it listens on all interfaces (needed for remote access; use the
default 127.0.0.1 if local-only is enough):
export KUBECONFIG="$HOME/.kube/karmada.config"
kubectl config use-context karmada-host
kubectl port-forward -n karmada-system services/karmada-dashboard-web \
--address 0.0.0.0 8000:8000
# run in background (nohup ... &) if it must outlive the shell
This process is session-bound: it dies if the shell exits, the host reboots, or the web pod restarts. For a durable setup, run it as a systemd service instead.
Verify locally: curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/ → 200.
Step 5 — Accessing from another host (cloud VMs)
Step 4 already confirms local access works. To reach the dashboard from another machine when it runs on a public-cloud VM, remind the user to open the corresponding security group / firewall rule (e.g. an ingress rule for TCP port 8000) so inbound traffic can reach the host.
Quick teardown
export KUBECONFIG="$HOME/.kube/karmada.config"
kubectl config use-context karmada-host
kubectl delete -k artifacts/overlays/nodeport-mode
kubectl -n karmada-system delete secret karmada-dashboard-config
# kill any running port-forward: pkill -f "port-forward.*karmada-dashboard-web"