Chris Collins

Tools · containers

Container dashboard

A read-only dashboard for your own Docker and Kubernetes through a small local relay: containers, images, volumes and networks with live stats and logs; namespaces, workloads with rollout status, pods, services and endpoints, nodes, events, YAML, and a topology diagram — with every request copyable as curl, docker or kubectl.

Added

How to use it

A web page cannot open Docker’s unix socket, and the Kubernetes API needs credentials a page should never hold. So this dashboard reads through container-relay.py, one Python file that runs on your computer, listens on 127.0.0.1:8098, and forwards read-only requests to Docker and to one Kubernetes cluster you choose. Without a relay the page shows a recorded demo — a few containers and a one-node k3s cluster — so you can see what it does first.

With the gitwebsite app. If the gitwebsite app (or gw serve) is running on your computer, Connect reads Docker and Kubernetes through its companion instead — the same read-only rules (GET only, an allow-list of read endpoints, no exec/attach, Secrets refused), Docker’s socket found by itself, and every context of your kubeconfig to choose from (the kubeconfig is never written and its current context never changed). In the app’s own windows it connects by itself; from this site press ⚡ Use the gitwebsite app and approve the code in the app. The relay below is then not needed.

How to use it

  1. Not needed if the gitwebsite app is running — otherwise download container-relay.py (also the Download the relay button) and run it: python3 container-relay.py. It finds Docker’s socket by itself — /var/run/docker.sock, Rancher Desktop’s ~/.rd/docker.sock, Docker Desktop’s ~/.docker/run/docker.sock, Colima and OrbStack — or take --docker-host unix:///path (or tcp://host:2375).

  2. For Kubernetes, pick one of two ways. Either let kubectl do the authentication (this works with every auth plugin, OIDC and cloud login) and point the relay at it:

    kubectl proxy --port 8001 --context my-cluster &
    python3 container-relay.py --k8s-url http://127.0.0.1:8001

    or let the relay read a kubeconfig itself: python3 container-relay.py --kubeconfig ~/.kube/config --context my-cluster. It reads the file once, never writes it and never changes its current context; without --context it uses the file’s current context. Tokens, token files, client certificates, basic auth and exec credential plugins work; for the old auth-provider entries use kubectl proxy.

  3. Press Connect. The status line says what the relay reaches: the Docker API version, and the cluster with its context. Tick Connect when this page opens to skip this next time, and Refresh every to keep the tables current.

Docker

  • Containers — like docker ps -a: name, state with health, status and uptime, image, ports (127.0.0.1:8080→80/tcp), age and ID. Click one for its summary (command, restart count and policy, exit code and OOM kill, networks and addresses, mounts, labels, recent health-check results), Logs (the last 50–1,000 lines or all, follow, timestamps; stderr in red), Live stats (CPU and memory charts from the stats stream) and Inspect (the full JSON).

  • Stats — like docker stats: CPU %, memory used / limit and %, network and block I/O, PIDs and a CPU sparkline for every running container, every few seconds.

  • Images, Volumes, Networks — sizes, tags, how many containers use an image, subnets and the containers attached to a network; click for details.

Kubernetes — choose a namespace or all of them.

  • Workloads — Deployments, StatefulSets, DaemonSets, Jobs and CronJobs with ready / up-to-date / available counts and the rollout status in kubectl rollout status words ("1 old replicas are pending termination", "exceeded its progress deadline"). Click one for its pods, conditions, events and YAML.

  • Pods — the kubectl get pods columns: ready containers, the STATUS kubectl would print (CrashLoopBackOff, Init:0/1, Terminating, Completed), restarts with when the last one was, age, IP and node. Click one for its containers (state, last termination and exit code), conditions, QoS class, Logs (per container, follow, Previous for the instance that crashed), Events and YAML.

  • Services — type, cluster IP, external address, ports and ready / total endpoints, read from EndpointSlices; click one to see each endpoint, its pod and node.

  • Nodes — ready state, roles, kubelet version, allocatable CPU and memory, pods running out of those allowed; click for capacity versus allocatable (what the system reserves), conditions such as MemoryPressure, taints and the OS, kernel and runtime.

Events lists the namespace’s (or cluster’s) events newest first, with repeat counts ("x12 over 5m"), filtered to warnings or by text. Topology draws one namespace: Services → their endpoint pods (dashed; red when not ready), and Deployments → ReplicaSets → Pods → Nodes (StatefulSets, DaemonSets and Jobs own their pods directly; CronJobs own Jobs). Old ReplicaSets with no pods are left out. Click a box for its details. ⛶ Full screen (or F) gives the dashboard the whole screen — the browser’s full screen where it is allowed, otherwise a full-window layer (iPhone) — with the tabs at the top; on Topology the diagram fills the space and is scaled up to fit as the window changes (a big namespace keeps its size and scrolls). ◫ Panels hides the connection panel. Escape leaves.

YAML views drop managedFields unless you tick Show managedFields. Copy command in a detail panel copies the matching kubectl describe, kubectl rollout status or docker inspect.

Requests lists every call the page makes, newest first. Each can be copied three ways: curl against the relay, direct — straight to Docker’s socket (curl --unix-socket /var/run/docker.sock http://localhost/v1.47/containers/json?all=1) or kubectl get --raw — and as the everyday docker or kubectl command that shows the same thing (docker logs -f --tail 200 web, kubectl get pods -n shop -o wide). Download as script saves them all.

What the relay allows

  • GET only. POST, PUT, PATCH, DELETE and HEAD are refused with 405, so nothing can be created, started, stopped, scaled or deleted through it. Streaming reads — docker logs --follow, docker stats, kubectl logs -f, watches — pass through as they arrive.

  • An allow-list of read endpoints. Docker: ping, version, info, disk usage, events, and listing and inspecting containers (with logs, stats, top and changes), images (with history), volumes and networks. Not exec, attach, archive or export (which copy files out of a container), or images/get. Kubernetes: discovery, version and health, OpenAPI, and resources — but not the exec, attach, portforward and proxy subresources, and not Secrets.

  • Not an open proxy. It talks only to the Docker socket and the one API server you named, and refuses paths with .., //, backslashes or encoded slashes.

  • Only this site. A request from a web page carries an Origin header; only https://geekychris.github.io and local previews (http://127.0.0.1:*, http://localhost:*) are answered. Add another with --allow-origin. Tools such as curl send no Origin and are allowed. The Host header must name this machine, which stops DNS-rebinding tricks.

  • Local. It binds to 127.0.0.1; keep it that way (--host exists for containers and VMs, not for networks).

  • The read-only rules are in the relay, not just the page: anything on your machine that can reach 127.0.0.1:8098 can read what the page reads. Stop it (Ctrl+C) when you are done.

The page itself never holds a token or a kubeconfig, and they are never put in links, the request log or copied commands. Chrome may ask whether this site may reach devices on your local network: allow it. Safari may refuse http://127.0.0.1 from an HTTPS page; use Chrome, Edge or Firefox, or a local preview.

Limits

  • Read-only by design: no exec, restarts, scaling, deletes or port forwarding. Use the docker or kubectl commands the request log gives you.

  • Secrets are never read, so their keys do not appear either.

  • Lists are fetched whole (no pagination): fine for a laptop or a small cluster, slow for thousands of pods. Choose a namespace to keep them small.

  • The Stats view samples up to 24 running containers; each sample takes Docker about a second.

  • Pod CPU and memory use need metrics-server and are not shown; node figures are capacity and allocatable, not use.

  • The STATUS column follows kubectl’s rules for what the API returns; a few cases kubectl derives from extra node data (such as NodeLost) are simplified.

  • Logs keep the newest 5,000 chunks in the page.

  • The demo is a recording made with the relay from a few throwaway containers and a one-node k3s cluster (Kubernetes 1.37); its logs replay in a loop and its stats wobble on purpose.

Linking to an example

Share link copies a link with the dashboard’s view: the relay address (without any user, password or query string), namespace, Docker and Kubernetes views, and filters. A link never connects by itself — it opens the demo until you press Connect. Put the tab after #: docker, k8s, events, topology or log.

Parameter Meaning Example

relay

the relay’s address (default http://127.0.0.1:8098)

relay=http%3A%2F%2F127.0.0.1%3A8099

ns

namespace (empty: all)

ns=shop

docker

containers, stats, images, volumes or networks

docker=stats

k8s

workloads, pods, services or nodes

k8s=pods

q

filter for the Docker and Kubernetes tables

q=web

ev

events of one type: Warning or Normal

ev=Warning

evq

events text filter

evq=BackOff

Examples (they open on the demo):

Runs entirely in your browser — network requests go only to the services named on this page.