d9c

command module
v1.23.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 11 Imported by: 0

README

d9c

d9c

English · Русский

A terminal (TUI) Docker manager for remote hosts — in the spirit of k9s and lazydocker, but focused on managing Docker over TCP or SSH. A single binary, no agents on the remote side: connect to the daemon, see containers, images, networks, volumes and Compose projects and manage them without leaving the terminal.

Built on Bubble Tea and the official Docker SDK.

license release ci Go Reference go platform donate

Want to take a look without setting up Docker? Run the demo on fake data: go run . -demo.


Table of contents


Features

  • Remote Docker over TCP and SSH — a single connection path for both transports, live :connect, saved hosts with CRUD, auto-reconnect on disconnect (backoff + banner).
  • All core resources — Containers / Images / Networks / Volumes / Compose / Hosts.
  • Management, not just viewing — start/stop/restart/kill/rm, bulk operations (multi-select with Space — bulk operations on containers and image removal), a run wizard, network/volume creation, build/tag/push (including to a private registry), docker system df and prune with confirmation.
  • Compose — discovery by labels, up/pull/down with streaming, config, edit, create, backup/restore, project logs, drill-down into containers (operations on project files and running docker compose — over SSH only; see Connecting to Docker).
  • Logs and metrics--tail/--since/--until, search, save to file; live CPU/MEM/Net/Disk via the Stats API.
  • Built-in terminal — interactive exec into a container (vt10x emulator), a single path for TCP and SSH.
  • Container filesystem browser — navigation and docker cp in both directions.
  • Live daemon event log (docker events) in a dedicated console.
  • Multi-host dashboard — status and aggregates (docker info) across all saved hosts.
  • CPU/MEM alerts, configurable themes and hotkeys, plugins (your own commands and keys from YAML — like in k9s).

Installation

No Go and no compiler required — nothing needs to be installed on the remote host either. Download the archive for your OS from the Releases page:

OS File
Linux (x86-64) d9c_vX.Y.Z_linux_amd64.tar.gz
Linux (ARM64) d9c_vX.Y.Z_linux_arm64.tar.gz
macOS (Intel) d9c_vX.Y.Z_darwin_amd64.tar.gz
macOS (Apple Silicon) d9c_vX.Y.Z_darwin_arm64.tar.gz
Windows (x86-64) d9c_vX.Y.Z_windows_amd64.zip

Inside the archive there is a single executable (d9c or d9c.exe) plus README.md and LICENSE.

Linux / macOS:

# unpack and put it on PATH (example for Linux amd64)
tar -xzf d9c_vX.Y.Z_linux_amd64.tar.gz
sudo install d9c_vX.Y.Z_linux_amd64/d9c /usr/local/bin/d9c

d9c -version          # check

macOS may block an unsigned binary on first launch ("cannot be opened because the developer cannot be verified"). Remove the quarantine: xattr -d com.apple.quarantine ./d9c.

Windows (PowerShell):

# unpack the zip and run d9c.exe from that folder,
# or put it in a directory that is on %PATH%
Expand-Archive d9c_vX.Y.Z_windows_amd64.zip
.\d9c_vX.Y.Z_windows_amd64\d9c.exe -version

Checksum verification (optional). Each release ships a checksums.txt (SHA-256):

sha256sum -c checksums.txt 2>/dev/null | grep d9c_vX.Y.Z_linux_amd64.tar.gz
# Windows
(Get-FileHash .\d9c_vX.Y.Z_windows_amd64.zip -Algorithm SHA256).Hash
go install

With Go 1.25+ installed:

go install github.com/kirg0/d9c@latest   # binary lands in $(go env GOPATH)/bin
Building from source

Requires Go 1.25+:

git clone https://github.com/kirg0/d9c.git
cd d9c
make build          # binary ./d9c (or d9c.exe on Windows)

or directly via go:

go build -o d9c .

The version can be baked into the binary at build time (release builds do this automatically):

go build -ldflags "-X github.com/kirg0/d9c/internal/version.Version=1.2.3" -o d9c .

The application follows SemVer; the current version is shown in the header (d9c vX.Y.Z) and printed by the -version flag.


Quick start

go run . -demo                 # demo data, no Docker
go run . -H tcp://host:2375    # remote daemon over TCP
go run . -H ssh://user@host    # remote daemon over an SSH tunnel
go run . -version              # print the version and exit

The examples above are for running from source. If you installed a prebuilt binary, use d9c instead of go run . (e.g. d9c -demo, d9c -H ssh://user@host).

If no host is specified, d9c opens on the Hosts section, where you can pick a saved host or add a new one — the connection happens via Enter / :connect.


Connecting to Docker

Transport Example Note
TCP -H tcp://host:2375 the daemon must listen on TCP (-H tcp://0.0.0.0:2375 on the server side)
SSH -H ssh://user@host an SSH tunnel to the local daemon socket; keys from the agent/~/.ssh
nerdctl (local) -H nerdctl:// containerd via a local nerdctl (see containerd)
nerdctl (SSH) -H nerdctl+ssh://user@host containerd via nerdctl on a remote host over SSH
CRI (local) -H crio:// CRI-O / any CRI runtime via a local crictl (see CRI-O)
CRI (SSH) -H crio+ssh://user@host a CRI runtime via crictl on a remote host over SSH

TCP vs SSH — what's available. Almost everything (containers, images, networks, volumes, exec, container FS browser, events, dashboard) works over both transports via the Docker Engine API. But Compose operations that need access to the host filesystem or run docker compose itself as a process go around the API — SSH only. So when connected over TCP the following Compose commands are unavailable (they don't appear in the hints or in ?): create, up, down, pull, config, edit, backup, restore (and the e key — edit the file). Over TCP you still get project discovery, view/inspect/logs, the local backups directory (view and delete archives only — restore requires SSH) and project container management: start / stop / restart / pause / unpause / remove. Need the full Compose set — connect via -H ssh://....

containerd

containerd has no Docker-compatible REST API, so d9c cannot talk to it the way it talks to Docker or Podman. Instead of a native gRPC client (heavy, and lacking logs/networks/volumes/ compose) d9c drives containerd through nerdctl — the Docker-compatible CLI frontend. nerdctl must be installed on the machine where containerd lives (installation guide — binaries from releases + CNI plugins; rootless mode — docs/rootless.md):

# containerd on this machine
d9c -H nerdctl://

# containerd on a remote host (nerdctl is executed there over SSH)
d9c -H nerdctl+ssh://user@host

When connected through nerdctl, the header shows a containerd chip together with the active namespace (containerd:default). All sections work: Containers (list/start/stop/restart/ kill/rm/inspect/logs/stats/run), exec (over the SSH transport), Images (pull/rmi/tag/push/build/ history), Networks, Volumes, Compose (discovery by the same labels + reconstructed up/down/pull), events, system df/prune.

Namespaces. containerd shards its objects by namespace (default, k8s.io for Kubernetes, etc.). The :namespace <name> command switches the namespace; :namespace with no argument opens a picker. Every command is automatically scoped to the active namespace. An unknown name is accepted without an error — containerd creates the namespace lazily on the first write.

nerdctl backend fine print
  • Local and SSH limitations mirror each other. Copying files into/out of a container (cp) works only with a local nerdctl (nerdctl://): over SSH the files would land on the remote host, not on the machine running d9c. Interactive exec / run -it is the opposite — SSH only (nerdctl+ssh://): bridging a local PTY into the built-in terminal is not implemented. Everything else works on both transports.
  • Compose without a compose file. nerdctl does not stamp the working_dir/config_files labels and has no compose ls, so the path of a discovered project's compose file cannot be recovered. The up/pull/down commands are reconstructed from the com.docker.compose.project labels (present on both containers and networks): up = start the project's containers (not a recreate from the file), pull = pull every service's image, down = remove the project's containers and networks (named volumes are kept — same as docker compose down by default). config / edit (the e key) / backup / restore are unavailable — they need the compose file itself.
  • system df is emulated. nerdctl 2.x has no system df subcommand; the report is assembled from the object lists: images with their summed size, containers (total/running), volumes. Volume sizes are not computed: volume ls --size walks every volume and can be very slow on real hosts.
  • Stats are one-shot. CPU%/MEM in Containers come from nerdctl stats --no-stream; nerdctl reports a ready-made CPU%, so no cross-tick delta bookkeeping (as with the Docker API) is needed.
  • The network: filter. The JSON output of nerdctl ps has no Networks field — the container's networks are extracted from nerdctl's own nerdctl/networks=["…"] label.
  • Events are rare. An idle containerd host emits almost no events (none of the healthchecks and background chatter of a typical docker daemon) — until the first event the viewer shows a "waiting for events…" hint, and if the stream ends (the nerdctl events process died, SSH dropped) the feed gets an [error] event stream ended — press r line.
  • PATH and iptables over SSH. A non-interactive SSH session has no /usr/sbin in PATH, while nerdctl invokes iptables when publishing ports (run -p …) — without it the run fails with failed to load networking flags. d9c prepends /usr/local/sbin:/usr/sbin:/sbin to PATH for every nerdctl command over SSH.
  • nerdctl+ssh:// is a first-class SSH host. The Hosts section offers it the same authentication options as ssh://: a key (custom path or ssh-agent/~/.ssh) or a password with the login/password modal on connect.
  • The Hosts dashboard is filled from nerdctl info --format json (host name, CPUs, memory) and nerdctl version (the containerd version from Server.Components); the container/image counters are computed from the lists.
  • Friendly errors. nerdctl's logrus wrapper (time="…" level=fatal msg="…") is stripped from every error — the UI shows just the substance ("no such image: …").
  • The container FS browser works by running ls -1Ap inside the container (containerd exposes no readdir API) — the image must contain ls.
  • Rootless is supported — the backend was live-tested on Debian 13 with containerd v2.3.2 and rootless nerdctl 2.3.4.
CRI-O / generic CRI

For runtimes speaking CRI (the Kubernetes Container Runtime Interface) — CRI-O, containerd's CRI plugin, cri-dockerd — d9c works through crictl, the official CRI client. crictl must be installed on the machine where the runtime lives:

# CRI runtime on this machine (crictl finds the socket itself or reads /etc/crictl.yaml)
d9c -H crio://

# explicit socket path
d9c -H crio:///var/run/crio/crio.sock
d9c -H cri:///run/containerd/containerd.sock

# runtime on a remote host (crictl is executed there over SSH)
d9c -H crio+ssh://user@host
d9c -H cri+ssh://user@host/run/crio/crio.sock

crio:// and cri:// are synonyms (one shared backend); crio+ssh:// is a first-class SSH host with the same key/password authentication as ssh://. The header shows a cri-o chip (or cri for another runtime — from the RuntimeName of crictl version).

What works. Containers — listings (names render as pod/container: the pod is CRI's grouping unit), inspect, start/stop/rm, kill (maps to CRI stop with a zero timeout — CRI has no other signals), logs (-f/--tail/--since), CPU/MEM metrics (CPU% is derived as the delta of the cumulative counter between refresh ticks), interactive exec (over the SSH transport, like nerdctl), the container FS browser (ls inside the container); Images — list/inspect/rmi/ pull/prune; events (requires cri-tools ≥ 1.26); system df is emulated from the lists; the Hosts dashboard gets the counters and the runtime version.

What CRI has no notion of — soft degradation: Networks/Volumes/Compose show empty lists (networking belongs to CNI, volumes and compose to the orchestrator), while build/tag/push/ run/cp answer with a clear "CRI manages only pods, containers and images" error. Creating containers is the kubelet/orchestrator's job, not a TUI's. Also note that some runtimes refuse to start an exited container (restart may return the runtime's error) — in Kubernetes the kubelet recreates containers instead.

Setting up a CRI-O host

Verified with a live run against Debian 13 + CRI-O 1.33. For d9c to work fully:

  • crictl — the cri-tools package is missing from some repositories (e.g. openSUSE OBS isv:/cri-o) — grab the binary from cri-tools releases instead. Set the endpoint in /etc/crictl.yaml, otherwise crictl probes sockets with warnings:

    runtime-endpoint: unix:///var/run/crio/crio.sock
    image-endpoint: unix:///var/run/crio/crio.sock
    
  • Socket access. /var/run/crio/crio.sock is owned by root — connect as crio+ssh://root@host (or grant your user access to the socket).

  • Events (:events). CRI-O only serves the event stream with enable_pod_events = true (a drop-in under /etc/crio/crio.conf.d/); without it the stream closes right after opening and the viewer reports a finished stream.

  • Idempotent stop. crictl stop of a nonexistent container succeeds (a CRI-O trait) — stopping a stale list row won't surface an error.

  • Standalone rigs without Kubernetes. CRI-O's packaged CNI config ships disabled (/etc/cni/net.d/10-crio-bridge.conflist.disabled — rename it, dropping .disabled), and old CNI plugins (e.g. 1.1.1 from Debian) fail the bridge CHECK ("Interface veth… Mac doesn't match") — install plugins ≥ 1.5 from containernetworking/plugins into /opt/cni/bin. This matters for creating pods (crictl runp); d9c itself never creates pods, but without CNI a test rig has nothing to fill the lists with.

The Hosts section is both the list of saved hosts and a multi-host dashboard: each host gets a row with status (● up/down) and an aggregate from docker info (containers/running/images/daemon version). Data is collected over a single connection per host, refreshed roughly every 10 seconds. Enter — connect to the selected host. Management right from the section: a — add, e — edit, d — delete (with confirmation); the same actions are available via the :add / :edit / :rm commands. The :dashboard / :dash commands are aliases for :hosts. The host list is stored in the shared d9c-config.yaml (the hosts: section, see Config, themes and keys).

For ssh:// hosts the add/edit form lets you choose the authentication method (←/→/space toggle):

  • Key — the "Key path" field takes a custom private-key path; empty falls back to ssh-agent and the default ~/.ssh keys.
  • Password — only the login is saved to the config; the password is never written to disk. On connect (Enter / :connect) a modal prompts for the login and password: the saved login is pre-filled but editable before connecting. The password lives in memory only for the session.

Sections and navigation

Sections: Containers / Images / Networks / Volumes / Compose / Hosts.

  • Navigation — arrow keys / j / k, PgUp/PgDn, g/G.
  • Filter — /, command line — :, quit — q.
  • Key hints are in the bottom line; full help for the current section is on the ? key.

Filter /

Plain text is a case-insensitive substring (multiple words are logical AND). Structured terms are also available (for Containers they are the richest):

Term What it does
nginx substring in name/image/status
re:^web-\d+ regular expression (case-insensitive)
status:running by status/state (running, exited, healthy…)
label:env / label:env=prod by container label (key or key=value)
network:frontend (net:) by attached network

Terms combine with a space (AND): status:running label:env=prod net:bridge. A regex error is highlighted right in the filter line.


Config, themes and keys

All application settings — theme, color overrides, hotkeys, alert thresholds and the list of saved hosts — live in a single YAML file. By default d9c looks for d9c-config.yaml next to the executable; a different path can be set with a flag:

d9c -config /path/to/d9c-config.yaml

Plugins are the only exception: they live in a separate d9c-plugins.yaml. A missing config is not an error — the built-in tokyonight theme and an empty host list are used. The file is read at startup, and changes made from the interface (editing hosts, picking a theme in the picker) are written back immediately — the other sections are preserved. An old standalone d9c-hosts.json is automatically migrated into the new config's hosts: on first run (the file is renamed to d9c-hosts.json.migrated).

lang: en                  # UI language: en (default) or ru
theme: dracula            # built-in palette (tokyonight by default)
colors:                   # optional pointwise color overrides
  primary: "#ff79c6"
  danger: "#ff5555"
hosts:                    # saved hosts (Hosts section; usually edited from the UI)
  - name: prod
    host: ssh://user@prod.example.com
    ssh_auth: key          # key | password (empty = key via ssh-agent/~/.ssh)
    ssh_key_path: ~/.ssh/prod_ed25519   # optional; for ssh_auth: key
  - name: staging
    host: ssh://deploy@staging.example.com
    ssh_auth: password     # prompts for the password on connect; never stored
  - name: local
    host: tcp://localhost:2375

Built-in themes: tokyonight, dracula, nord, gruvbox, solarized, catppuccin, k9s (bright, in the spirit of the k9s skin). The theme can also be switched on the fly, without a config — via the :theme <name> command (e.g. :theme nord); :theme without an argument opens a picker modal with a list of themes and live preview (arrows — preview, Enter — apply, q/Esc — cancel). Picking a theme through the picker (Enter) is saved to the config (theme:) — it survives a restart; :theme <name> changes the theme for the current session only. In colors you can override any of the base colors on top of the selected theme:

The UI language is switched the same way: the :lang command with no argument opens a picker modal (Русский / English, arrows — preview, Enter — apply, q/Esc — cancel), while :lang en / :lang ru change the language directly. The choice is saved to the config (lang:) and survives a restart. The interface is English by default.

Key Purpose
primary accents, active keys, indicators
secondary table headers, labels
success running / healthy / "● up"
warning transitional states (paused, reconnect)
danger errors, stopped, unhealthy
muted dimmed text, separators
bg / bgalt background and raised surfaces (selection, bars, modals)
fg primary text
border frames and lines

A color value is hex (#rgb or #rrggbb) or an ANSI palette index 0255. An unknown theme, an unknown color key or an invalid value is an error at startup (loading config: …).

Keys

Normal-mode actions can be remapped in the keys: section of the same d9c-config.yaml. Only the actions you want to change need to be listed — the rest stay at their defaults:

keys:
  filter: f        # filter instead of "/"
  logs: g          # logs instead of "l"
  select: space    # mark for a bulk operation (the alias "space" = the spacebar)
Action Default What it does
inspect i details of the selected resource
logs l container / compose-project logs
edit e edit the compose file
exec x shell in a container (built-in terminal)
filter / filter by rows
command : command line
toggle-all a all / running only
stats s CPU/MEM metrics
select space mark for a bulk operation
copy y copy menu
refresh r refresh manually
pause p pause/resume auto-refresh
help ? help

A value is a key name in Bubble Tea notation (f, ctrl+d, f5, space, etc.). Navigation (↑/↓, j/k, PgUp/PgDn), Enter and the quit keys (q, esc, Ctrl+C) are fixed and cannot be remapped. An unknown action, an empty key, a reserved key or one key bound to two actions is an error at startup (loading keybindings: …). The ? help shows the actual (remapped) keys.


Container filesystem (f / :files)

In the Containers section the f key (or the :files [path] command) opens a browser of the selected running container's filesystem. The listing is built via ls inside the container, so in minimal images without ls (scratch/distroless) the browser is unavailable (this is reported with a clear error).

Key Action
enter / l enter a directory
/ h / - go up one level
d download the selected file/directory into d9c's working directory (docker cp out of the container)
↑/↓ j/k, g/G, PgUp/PgDn navigate the list
q / esc close the browser

Uploading INTO a container is done with the :cp <local-path> <container-dir> command (the target path must be an existing directory inside the container). Calling :cp without arguments opens a modal wizard: a built-in picker for the local filesystem (navigating the machine where d9c runs) plus a destination directory field in the container — Tab switches focus, enter/l enters a directory, /h goes up, enter in the destination field starts the upload. Downloading unpacks the daemon's tar stream to disk with protection against escaping the destination directory; symlinks and special files are skipped.


Auto-refresh

Lists are refreshed on a timer. The initial interval is set by the -interval flag (e.g. -interval 5s, 3s by default); the :interval <dur> command changes it on the fly (:interval 10s, range 1s1h), and :interval without an argument shows the current value. The p key (or :interval pause / :interval resume) pauses and resumes auto-refresh — the server status indicator keeps working meanwhile, and manual refresh via r is always available. The state is shown in the header: ↻3s — the active interval, ⏸ paused — paused.


Resource threshold alerts

Containers whose load exceeds a given threshold are highlighted with a marker next to the name (in both Containers table modes), and a ⚠ N counter appears in the header — the number of "hot" containers. The thresholds rely on the live Stats API metrics (the same CPU%/MEM% as in s mode); stopped and not-yet-polled containers are not counted.

The initial thresholds are set by the alerts: section in d9c-config.yaml (optional; 0 or absence = the metric is off):

alerts:
  cpu: 80     # highlight a container at CPU% ≥ 80 (may exceed 100 on multi-core)
  mem: 90     # highlight at MEM% ≥ 90

The thresholds are changed on the fly with the :alert command:

Command Action
:alert cpu <%> CPU% threshold (e.g. :alert cpu 80)
:alert mem <%> MEM% threshold
:alert cpu off / :alert mem off turn off an individual metric
:alert off turn alerts off entirely
:alert show the current thresholds

Plugins

Plugins are custom commands and hotkeys described in a YAML file (like in k9s). Each plugin runs a local command (on the machine where d9c runs) with substitution of the selected row's data. This lets you wire in dive, lazydocker, ctop, your own scripts, docker commands and so on — without changing the application code.

Where the file lives

By default d9c looks for the file d9c-plugins.yaml next to the executable. A different path can be set with a flag:

d9c -plugins-file /path/to/plugins.yaml

A missing file is not an error, there will just be no plugins. The file is read once at startup: after editing it, restart d9c.

File format

The root is the plugins key with a list of objects:

plugins:
  - name: dive                 # required — the command name (invoked as :dive)
    key: ctrl+d                # optional — a hotkey
    scope: images              # in which section it's available (default "*")
    description: Image layers  # optional — for documentation
    command: dive              # required — the executable (without arguments)
    args: ["${ID}"]            # optional — arguments (each on its own line)
    background: false          # optional — launch mode (default false)
Fields
Field Req. Description
name yes The command name. Invoked as :name.
command yes The executable name/path. Run directly, without a shell.
args no The argument list. Each one is a separate list item (not a single string).
scope no The section where the plugin is active. Default * (everywhere).
key no A hotkey (Bubble Tea format: ctrl+d, f5, alt+x…).
description no A short description (documentation).
background no false — interactive (takes over the terminal); true — in the background with output to a console.
Allowed scope values

containers, images, networks, volumes, compose, hosts, or * (any section). Case-insensitive. A plugin with scope: containers is only available in the containers section; scope: "*" — in all of them.

${VARIABLE} substitution

Before launch, the values from the selected row are substituted into command and into each args item. Unknown placeholders are left as is (so a typo is visible).

Always available:

Variable Value
${HOST} The address of the current Docker host (tcp://… or ssh://…).
${ID} The identifier of the selected row. For containers/images/networks — the ID; for volumes/projects/hosts — the name (which is also the row key).

Depending on the section, the following are added:

Section (scope) Additionally
containers ${NAME} ${IMAGE} ${STATUS} ${STATE} ${PORTS}
images ${NAME} ${IMAGE} ${TAGS} (all three = the image tags)
networks ${NAME} ${DRIVER}
volumes ${NAME} ${DRIVER}
compose ${NAME} ${PATH} (the working directory) ${STATUS}
hosts ${NAME} ${HOST} (the URL of the selected host)

The remote daemon is ${HOST}. Since the command runs locally, for actions against the remote daemon call the local client with this address, e.g. docker -H ${HOST} … or docker -H ${HOST} exec -it ${ID} sh.

How to invoke a plugin
  • By command: : → type name → Enter. The plugin names for the current section appear in autocompletion.
  • By key: if key is set — press it in the appropriate section. The binding is shown in the hints at the bottom of the screen.

Built-in commands and keys always take priority. If you name a plugin like a built-in command (stop, rm, logs…) or bind it to a taken key (i, l, x, s, a, /, :…), the built-in action fires. So for keys prefer ctrl+<letter> or function keys (f2f12), and pick names different from the built-in ones.

Launch modes

Interactive (background: false, default). d9c hands over the terminal to the launched program (like exec/shell), and returns the interface after it exits. Suitable for interactive programs: a shell in a container, dive, lazydocker, vim, htop. A non-zero exit code is shown as an error in the bottom line.

Background (background: true). The command runs without taking over the terminal, and its stdout/stderr are streamed line by line into the operation console (like compose up progress). Suitable for one-off commands that print text (docker system df, reports, scripts). Close the console with q/esc.

Important limitations
  • No shell. command runs directly, so pipelines (|), redirections (>), substitutions ($(…)), wildcards (*) and environment variables are not expanded. To use them, call a shell explicitly:
    • Linux/macOS: command: sh, args: ["-c", "docker -H ${HOST} logs ${ID} | tail -n 100"]
    • Windows: command: cmd, args: ["/c", "…"]
  • The command runs locally, on the machine with d9c. The needed binaries (docker, dive, lazydocker…) must be installed and available on PATH.
  • Cross-platform. The paths to the shell and utilities differ on Windows and Linux — keep in mind where d9c runs.
  • The file is read at startup; after changes a restart is needed.
Full d9c-plugins.yaml example
plugins:
  # An interactive shell in the selected container (via the remote daemon).
  - name: sh
    key: ctrl+s
    scope: containers
    description: Shell inside the container
    command: docker
    args: ["-H", "${HOST}", "exec", "-it", "${ID}", "sh"]

  # Explore image layers with dive.
  - name: dive
    key: ctrl+d
    scope: images
    description: Image layer analysis
    command: dive
    args: ["${TAGS}"]

  # Full lazydocker, connected to the same host.
  - name: lazy
    scope: "*"
    command: lazydocker

  # The daemon's disk usage — output to the operation console.
  - name: df
    scope: "*"
    background: true
    description: docker system df
    command: docker
    args: ["-H", "${HOST}", "system", "df"]

  # The last 200 log lines through a shell pipeline (in the background).
  - name: tail
    scope: containers
    background: true
    command: sh
    args: ["-c", "docker -H ${HOST} logs --tail 200 ${ID}"]
Troubleshooting
  • The plugin isn't invoked by :name — check the scope (does it match the current section or *) and that the name doesn't collide with a built-in command.
  • The key doesn't fire — it's probably taken by a built-in action; change it to ctrl+<…>/fN.
  • executable file not found — the needed binary isn't on PATH on the machine with d9c.
  • A pipeline/>/* "doesn't work" — that's expected: wrap the command in sh -c "…" / cmd /c "…".
  • A loading plugins: … error at startup — invalid YAML, or a plugin without name/ command, or with an unknown scope. Fix the file and restart.

Development

The full set of checks before a commit (quality gate):

make check      # = fmtcheck + vet + golangci-lint + test

or manually:

gofmt -l .               # should be empty
go vet ./...
golangci-lint run ./...  # config in .golangci.yml; install: make tools
go test ./...
go test -race ./...      # for concurrent code

Useful Makefile targets: make build, make run ARGS="-H tcp://host:2375", make demo, make test, make race, make lint, make tools (installs golangci-lint/staticcheck).

Architecturally all Docker operations are hidden behind the docker.Backend interface, so the demo mode (-demo) and headless tests use FakeBackend and don't require a real daemon. The UI is built on the Elm model (Bubble Tea): Update doesn't block the event loop, long operations go through tea.Cmd.


Support the project

d9c is developed in spare time. If the tool turned out useful, you can support its development with a donation — it helps to find time for new features:

➡️ dalink.to/kirg08

A repository star ⭐ is motivating too. Thank you!


License

MIT © kirg0

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
cmd
addgroup command
One-shot tool: adds a user to the docker group via root SSH.
One-shot tool: adds a user to the docker group via root SSH.
crilivetest command
crilivetest exercises every docker.Backend operation against a live CRI-O / generic CRI host and prints PASS/FAIL/XFAIL per operation.
crilivetest exercises every docker.Backend operation against a live CRI-O / generic CRI host and prints PASS/FAIL/XFAIL per operation.
livetest command
livetest exercises every docker.Backend operation against a live host and prints PASS/FAIL/XFAIL per operation.
livetest exercises every docker.Backend operation against a live host and prints PASS/FAIL/XFAIL per operation.
ping command
Diagnostic tool: checks Docker access via SSH and lists containers.
Diagnostic tool: checks Docker access via SSH and lists containers.
setup command
setup installs the local public key on the remote host via password auth.
setup installs the local public key on the remote host via password auth.
internal
alerts
Package alerts flags containers whose live resource usage crosses user-configured thresholds (CPU% / memory%).
Package alerts flags containers whose live resource usage crosses user-configured thresholds (CPU% / memory%).
hosts
Package hosts manages the list of Docker hosts the user has connected to.
Package hosts manages the list of Docker hosts the user has connected to.
i18n
Package i18n provides the application's UI language selection.
Package i18n provides the application's UI language selection.
keymap
Package keymap maps the normal-mode action keys (inspect, logs, filter, …) to the keys that trigger them, loaded from the same d9c-config.yaml file the theme uses.
Package keymap maps the normal-mode action keys (inspect, logs, filter, …) to the keys that trigger them, loaded from the same d9c-config.yaml file the theme uses.
plugins
Package plugins loads user-defined commands from a small YAML file, letting d9c be extended with custom actions (like k9s plugins).
Package plugins loads user-defined commands from a small YAML file, letting d9c be extended with custom actions (like k9s plugins).
settings
Package settings owns the unified d9c configuration file (d9c-config.yaml): the single place every persistent setting lives — UI theme and color overrides, normal-mode keybindings, resource-alert thresholds, and the list of saved hosts.
Package settings owns the unified d9c configuration file (d9c-config.yaml): the single place every persistent setting lives — UI theme and color overrides, normal-mode keybindings, resource-alert thresholds, and the list of saved hosts.
theme
Package theme loads the UI color scheme from a small YAML config file, the same way plugins and saved hosts are persisted next to the d9c binary.
Package theme loads the UI color scheme from a small YAML config file, the same way plugins and saved hosts are persisted next to the d9c binary.
ui
ui/buildform
Package buildform renders the modal "build image" form shown in the images view when the build command is invoked without a context directory.
Package buildform renders the modal "build image" form shown in the images view when the build command is invoked without a context directory.
ui/composeedit
Package composeedit provides the embedded editor for compose files, with YAML syntax validation before saving.
Package composeedit provides the embedded editor for compose files, with YAML syntax validation before saving.
ui/connform
Package connform renders the modal credential prompt shown when connecting to an SSH host configured for password authentication.
Package connform renders the modal credential prompt shown when connecting to an SSH host configured for password authentication.
ui/connwait
Package connwait renders the modal status window shown while d9c dials a saved host that needs no credential prompt (SSH by key, TCP, unix).
Package connwait renders the modal status window shown while d9c dials a saved host that needs no credential prompt (SSH by key, TCP, unix).
ui/cpform
Package cpform renders the modal "upload to container" wizard shown in the containers view when `:cp` is invoked without arguments.
Package cpform renders the modal "upload to container" wizard shown in the containers view when `:cp` is invoked without arguments.
ui/driverfield
Package driverfield renders a horizontal driver selector used by the create-network and create-volume modal forms.
Package driverfield renders a horizontal driver selector used by the create-network and create-volume modal forms.
ui/events
Package events provides a live-events viewer component for the d9c TUI.
Package events provides a live-events viewer component for the d9c TUI.
ui/execform
Package execform renders the modal one-off-run wizard: start a disposable interactive container from an image (`docker run --rm -it` analogue) with optional volume mounts and a command (empty = shell).
Package execform renders the modal one-off-run wizard: start a disposable interactive container from an image (`docker run --rm -it` analogue) with optional volume mounts and a command (empty = shell).
ui/fsbrowser
Package fsbrowser provides a navigable view of a container's filesystem for the d9c TUI.
Package fsbrowser provides a navigable view of a container's filesystem for the d9c TUI.
ui/help
Package help renders the scrollable keyboard/command reference overlay.
Package help renders the scrollable keyboard/command reference overlay.
ui/hostform
Package hostform renders the modal add/edit form for the hosts view.
Package hostform renders the modal add/edit form for the hosts view.
ui/netform
Package netform renders the modal "create network" form shown in the networks view.
Package netform renders the modal "create network" form shown in the networks view.
ui/pullform
Package pullform renders the modal "pull image" form shown in the images view when the pull command is invoked without a selected image.
Package pullform renders the modal "pull image" form shown in the images view when the pull command is invoked without a selected image.
ui/pushform
Package pushform renders the modal registry-credentials form shown before pushing an image to a private registry.
Package pushform renders the modal registry-credentials form shown before pushing an image to a private registry.
ui/runform
Package runform renders the modal "run container" wizard shown in the containers view: image plus optional name, ports, env and volumes.
Package runform renders the modal "run container" wizard shown in the containers view: image plus optional name, ports, env and volumes.
ui/shell
Package shell renders an interactive container exec session as a panel inside the TUI.
Package shell renders an interactive container exec session as a panel inside the TUI.
ui/volform
Package volform renders the modal "create volume" form shown in the volumes view.
Package volform renders the modal "create volume" form shown in the volumes view.
version
Package version exposes the application version, following Semantic Versioning (https://semver.org): MAJOR.MINOR.PATCH.
Package version exposes the application version, following Semantic Versioning (https://semver.org): MAJOR.MINOR.PATCH.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL