chore(skills): promote runbook skills to managed-skills; drop superseded SKILL.md
- 31 new managed skills (anubis/arr/authentik/hermes/freetoken/podman/llm-swap runbooks etc.) now tracked. - Removed superseded skills: omp_harness_config, peon_ping_integration (replaced by user-authored peon-ping-* managed skills), rocmfp4-strix-benchmark-orchestration. - New memory-root skills: niri_compositor_ops, omp_git_workflow, omp_model_config, quadlet-media-migration, homelab-service-triage, hermes-dankclaw-ops, frank-default-large-ops, caddy-auth-dns-playbook.
This commit is contained in:
1 parent
7be39d60dd
commit
9bfa0be85d
48 files changed
+1361
-42
No files matched your search
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: podman-netns-addressability-probe
|
||||
description: "Runbook to answer \"can container X actually reach service Y\" on a rootless-podman/netavark host, instead of assuming localhost works everywhere; includes the probe commands and the false-positive traps."
|
||||
---
|
||||
|
||||
# Podman netns addressability probe
|
||||
|
||||
Answer **"can this container actually dial that service?"** per *network namespace*,
|
||||
not per host. On rootless podman + netavark, a bridge-net container cannot reach
|
||||
host-netns loopback listeners at all, so `localhost:PORT` reasoning is wrong for it.
|
||||
|
||||
## Decision rule
|
||||
- `NetworkMode=host` → the container **is** the host netns: dials everything on
|
||||
`127.0.0.1`, binds any free port.
|
||||
- bridge/named network → own netns. Only **published** ports are reachable, via the
|
||||
network's **gateway IP**. Unpublished host listeners are **refused instantly (RST)**,
|
||||
not routed — even when the listener is bound `0.0.0.0`.
|
||||
|
||||
## Probe sequence (all read-only, run on the host)
|
||||
1. Namespace: `podman inspect <name> --format '{{.HostConfig.NetworkMode}}'`
|
||||
2. Owner of a listener: `sudo ss -ltnp 'sport = :<port>'` (host netns only — this is
|
||||
why a `0.0.0.0` listener can still be unreachable from a bridge net).
|
||||
3. From inside the suspect container:
|
||||
`podman exec <name> cat /proc/net/route` → default route = gateway IP to dial.
|
||||
4. Probe the candidate address **inside that netns**:
|
||||
`podman exec <name> sh -c 'timeout 2 bash -c "exec 3<>/dev/tcp/<gw-ip>/<port>"; echo rc=$?'`
|
||||
|
||||
## Interpretation (do not blur these)
|
||||
- **instant refusal** = nothing listening in a reachable namespace (or rootlessport
|
||||
rejected an unpublished port map).
|
||||
- **timeout** = no route to that address at all. `host.containers.internal`
|
||||
(`169.254.1.2`) is an alias on the **default `podman` net only**; containers on a
|
||||
named network time out against it rather than being refused.
|
||||
|
||||
## Probe-tool gotchas verified on this host (podman 5.x, netavark)
|
||||
- `podman network inspect <net> --format '{{json .containers}}'` **errors**
|
||||
(`can't evaluate field containers in type interface {}`) — membership is not exposed
|
||||
there. List from the container side instead:
|
||||
`podman ps -a --format '{{.Names}} {{.Networks}}'`
|
||||
- An **empty** `Networks` field in that output = host network or a shared namespace
|
||||
(`--network=container:<other>`), not "no network".
|
||||
- Quadlet `Network=<name>.network` yields runtime network name **`systemd-<name>`**;
|
||||
probe with `podman network ls`, never by the `.network` filename.
|
||||
|
||||
## Fix options when a bridge-net container must reach a host-netns listener
|
||||
(a) move it to `Network=host`, or (b) publish the port — (b) makes that port reachable
|
||||
from every namespace **and the LAN**, so it is an exposure change needing explicit
|
||||
operator approval, never a silent fix.
|
||||
|
||||
Repo source of truth for this fleet: `serverAppConfigs-docs/Architecture/Container
|
||||
Network Namespaces.md` (commit `2e179b0`).
|
||||
Reference in new issue
Block a user