3.7 KiB
3.7 KiB
name, description
| name | description |
|---|---|
| container-port-image-identity-binding | Diagnose or write fleet gates that silently verify the WRONG process/image: /health answered by a dying container, podman inspect naming a merely-created container, cgroup lacking the service name, RepoDigests[0] vs the pin, detached launchers losing cwd. Bind every fact to its object by host pid. |
Container / port / image identity binding
For fleet gates, restart checks, "is it really up?" triage, and any bench/window harness that stops a production service and starts a rig on the same port. Use when a check passes but the thing still misbehaves, or when the same class of silent failure keeps recurring.
The failure signature (all of these mean "you checked a proxy")
| Check that lied | What it actually measured |
|---|---|
curl /health = 200 |
whichever process owned the socket, often the one being stopped |
podman inspect -f '{{.State.Running}}' |
a container that was created, not one that bound a port |
podman ps / container name |
existence, not service |
pgrep -f "<pattern>" |
your own polling shell, or a sibling arm |
| log mtime advancing | some request completed, not necessarily yours |
df <dir> |
a filesystem that merely looks related to the one the bytes go to |
podman image inspect -f '{{index .RepoDigests 0}}' |
ONE of several digests — a by-digest pull makes an image carry the tag digest first |
| rootless cgroup path | the container ID, never the service/container name |
The bindings that work
- Listener → process:
ss -H -ltnp 'sport = :<port>'→pid=; needs privilege for foreign processes (sudo sswhen the listener is root's). - Host pid → container:
podman top <ctr> hpid(header line first).podman top <ctr> pidprints container-internal pids (1,7) and compares against nothing — this is the single most expensive mistake in this class. - Image pin:
podman image inspect -f '{{range .RepoDigests}}{{println .}}{{end}}' <ref>and test membership of the pin, never position. Message the difference: "present but does not carry X". - Device holder:
fuser /dev/kfd→ pids → resolve each throughpodman top <ctr> hpid; anything outside the allowed set is foreign (an orphaned engine wedges the next boot asdevice error). - Detached launcher: assert cwd (
cd "$(dirname "$0")/.."; verify a known executable exists) and write aPASS/FAILline per fact.setsid nohup … &turns a lost cwd into silence, not an error.
Procedure
- Write ONE preflight that prints
PASS <fact> …/FAIL <fact> — reason, exit 2 on any FAIL. Facts: cwd, image digest membership, free space on the real target filesystem, stale artifacts, GPU holders, listener, inputs, reference data. - Call it as step 0 of the orchestrator, before any GPU/port is touched. Delete the duplicated inline checks so the fact has one owner.
- Pin each lie with a bats test using PATH stubs (
podman,ss,fuser): wrong digest, foreign listener pid, foreign GPU pid, dirty dir, wrong cwd. Fixture files must be NON-EMPTY — a-sfact on a: > filefixture fails for the wrong reason. - Keep one driver. Ad-hoc copies beside the orchestrator drop guards, and two drivers racing on one port produce phantom "strays" that look like a hijack.
Traps
podman top … pidvshpid— see above.- Stub collision: a test stub that answers
topfor both the rig and production must branch on the container name, or the test proves nothing. - A gate that reports a stale-but-present image must distinguish "absent" from "retagged/older" — the operator's fix differs.
- Verify a kill by re-reading the port;
podman rm -ffrees the cgroup, a pattern-kill may not.