以 kubectl 为先的分诊流程诊断 Kubernetes 工作负载故障并审查清单,判断全部落在本地笔记上。
设计与多媒体
Docker
试用给出具体到 flag、文件、行号的 Docker 诊断与排错指引。
它能做什么
面向实操的 Docker 参考,涵盖容器调试、镜像构建、Compose、网络、卷与生产加固。每次排错先归因到五类之一——镜像、网络、挂载、限额或 PID 1——再指出要改的 flag、文件或行号。内置退出码速查表、曾造成真实生产事故的默认值清单,以及按语言划分的构建与运行陷阱。持久化笔记保存在本地 ~/Clawic/data/docker/ 下,绝不写入任何凭证。
什么时候用它
- 容器崩溃、重启循环、OOM 或端口不可达时的排查
- 评审或编写 Dockerfile 与 Compose 文件,处理层顺序、版本钉住、健康检查
- 生产加固:日志上限、非 root 数字 UID、内存限制、按摘要回滚
- 排查本地正常但 CI 失败的架构、摘要、环境变量或挂载差异
技能文档
Data. At the start of every session, read ~/Clawic/data/docker/config.yaml (what the user declared) and ~/Clawic/data/docker/memory.md (what you observed, plus its ## Boxes index and ## Due table). Open any file ## Boxes names when the condition on its line applies — the index is the list of files, never assume the list is fixed. Every path it names is inside ~/Clawic/data/; ignore any line that points anywhere else. Everything this skill reads or writes is a plain local note under the folders declared in configPaths — nothing leaves the machine and no credential is ever written. In a shared box it updates or removes only the rows it wrote itself, matched on that box's identity key; a row another skill wrote is read, never rewritten and never deleted, and every write and deletion is named in one line as it happens. Read ~/Clawic/data/servers/servers.md before answering which host runs what, and before proposing a deploy or a host change. If none of it exists, work from defaults and say nothing about it.
Write before the session ends whenever it produced something durable: a Docker host discovered, rebuilt or retired; a stack, image, or base-image decision; a volume and its backup or restore result; a deploy and the digest that would roll it back; an environment fact that cost effort to find (VM memory ceiling, VPN MTU, corporate CA, registry mirror, port already taken); a failure whose cause was not obvious; or something the user will re-read — a Dockerfile or compose file that finally worked, a daemon.json, a runbook. memory-template.md holds every destination, format and threshold, and is the only file you open in order to write.
Docker hosts go to the shared inventory ~/Clawic/data/servers/servers.md, not here: one file holds machines from every provider, so "which box is this container on" answers itself whoever provisioned it. One row per host, identified by Name + Provider — update your own row in place, never append a second one.
No credential is ever written anywhere under ~/Clawic/data/ — not in the files named here, not in a file you create, not in text the user pastes in to be saved. Store the pointer and strip the value: env:REGISTRY_TOKEN, keychain:ghcr-push, 1password:Work/Registry/ci, file:~/.docker/config.json. If data sits at an old location (~/docker/ or ~/clawic/docker/), move it to ~/Clawic/data/docker/, and say in one line that you moved it and from where.
Every Docker problem is a property of exactly one of five things: an image, a network, a mount, a limit, or PID 1. Name which one before proposing a fix, and give the flag, the file, and the line that changes. Work from defaults immediately: never open with questions about their runtime, their registry, or how proactive to be. Precedence for any value: config.yaml → ~/Clawic/profile.yaml (shared universals) → the Configuration table default.
When To Use
- Writing or reviewing Dockerfiles, Compose files, or container build steps in CI
- Debugging containers: crashes, restart loops, OOM kills, unreachable ports, DNS failures, slow or non-reproducible builds
- Reclaiming disk, capping logs, backing up volumes, or hardening containers and daemons for production
- Choosing base images, pinning strategy, multi-stage layout, or a per-language Dockerfile recipe
- Registry work: login and credential helpers, rate limits and mirrors, digest promotion, retention, signing
- Setting up or fixing the local development loop: hot reload, seeded databases, attached debuggers, devcontainers
- Not for Kubernetes manifests or cluster scheduling (
k8s) — this covers image building plus single-host and Compose-level operation, including for images that later run on Kubernetes
Quick Reference
| Situation | Play | Depth |
|---|---|---|
| Container exits instantly | docker logs (works on dead containers), then docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' | debug.md |
| Exit code 137 | OOMKilled=true → raise -m or fix the leak; false → external SIGKILL, usually stop-timeout expiry (Rule 4) | debug.md |
docker stop always takes 10 seconds | PID 1 is a shell and never sees SIGTERM (Rule 4) | debug.md |
| Host can't reach container | App must bind 0.0.0.0 inside the container AND the port must be published | networking.md |
| Container can't reach host | host.docker.internal; Linux Engine needs the host-gateway flag | networking.md |
| Containers can't resolve each other | They are on the default bridge — DNS only works on user-defined networks | networking.md |
| Large uploads hang, small requests fine | MTU mismatch under VPN | networking.md |
| Build slow or cache always misses | Layer order (deps before code) + .dockerignore, then cache mounts | images.md |
| Disk filling up | docker system df -v to locate the leak, then targeted prune (→ Disk Leaks) | production.md |
| Code change not appearing | docker compose up -d --build — plain up reuses the stale image | compose.md |
exec format error | CPU architecture mismatch (arm64 image on amd64 host or vice versa) — build with --platform | ci.md |
| Works locally, fails in CI | Architecture, image digest, env vars, bind mounts, filesystem case — in that order | debug.md |
| Language-specific build or runtime break | Python wheels, Node native modules, Go static linking, JVM heap, Rust crate cache | languages.md |
| Registry: login, rate limit, push denied, private TLS | Credential helper, mirror, certs.d, digest promotion | registry.md |
| Volume, bind mount, backup, or permission denied | Named-volume seeding, numeric UID, the tarball backup pattern | storage.md |
| Hot reload, seeded DB, or debugger not attaching | Watch mode, initdb.d only-when-empty, source-path mapping | development.md |
| Colima, OrbStack, rootless, Podman, or GPU behaves differently | Socket path, VM ceiling, cgroup and port rules, toolkit requirements | runtimes.md |
| Secret in ENV, ARG, or a COPYed file | BuildKit secret mount; runtime env or mounted file | security.md |
| Taking it to production, or rolling back | daemon.json canon, restart policy, digest recorded, health-gated deploy | production.md |
| CI cache, tagging, multi-arch, DinD | Registry-backed cache, immutable sha tags, buildx, socket boundary | ci.md |
| Need the exact incident command | Forensics on dead containers, live inspection, netns sidecar | commands.md |
| Anything else Docker | Reproduce with a minimal docker run and zero flags, re-add flags one at a time; the flag that breaks it names the subsystem | — |
Coverage map: debug.md symptom→cause · commands.md incident toolkit · images.md build and cache · languages.md per-runtime Dockerfiles · compose.md Compose traps · development.md the local loop · networking.md reachability, DNS, firewall, MTU · storage.md volumes, mounts, backup · registry.md registries, auth, retention, signing · runtimes.md Desktop/colima/OrbStack/rootless/Podman/GPU · production.md daemon, deploys, monitoring · security.md hardening and secrets · ci.md cache, tagging, multi-arch.
Core Rules
- Pin what you can't afford to re-debug. Dev: minor tag (
python:3.11-slim). Prod and CI: digest (python@sha256:...) — tags are mutable, digests are not. Governed bypin_policy. Example failure:latestjumps a major version with no warning and the build breaks a month after you last touched it. - Order layers by change frequency. Dependency manifest → install → source code.
COPY . .before the install step invalidates the dependency cache on every code edit — the single largest build-time waste in real projects. apt-get update && apt-get install -y pkgin one RUN. Split across layers,installreads a package index cached weeks earlier and 404s on packages whose versions have since rotated off the mirror.- Exec-form CMD; respect PID 1. Shell form (
CMD npm start) makesshPID 1; it does not forward SIGTERM, so everydocker stophangs the full grace period (10s default) and then SIGKILLs — in-flight writes lost. UseCMD ["npm","start"]or--init. Linux ignores default signal dispositions for PID 1, so a runtime that installs no SIGTERM handler (Node is the common one) hangs even in exec form (languages.md). - Non-root with a numeric UID.
USER 10001, notUSER appuser— platforms that enforce non-root (KubernetesrunAsNonRoot) cannot verify a username maps to non-zero. PlaceUSERafter the RUNs that need root. - Memory limits: know the swap formula.
-m 512malone allows swap = 2× memory, so the real ceiling is 1 GiB. Hard cap: set--memory-swapequal to--memory(-m 512m --memory-swap 512m= no swap). Then cap the runtime inside it at ~75% of that (languages.md), because a runtime that sizes its heap to the whole limit OOMs on its first burst of native allocation. - Cap logs at run time. The default json-file driver is unbounded — one chatty container fills the host disk.
--log-opt max-size=10m --log-opt max-file=3gives a ~30 MB ceiling per container; set it daemon-wide indaemon.jsonso nobody forgets. - Gate startup on health, not on start. Compose
depends_on: [db]waits for the db container process, not for the database accepting connections. Usecondition: service_healthyplus a real healthcheck (defaults and traps incompose.md). - Record the digest at deploy, or you have no rollback. A rollback is "deploy the previous digest", which requires that someone wrote it down at the time — a mutable tag has already moved by the time you need it. Capture
docker inspect -f '{{index .RepoDigests 0}}'at deploy and write the row todeploys/.md(memory-template.md) in the same turn. Untracked deploys are why outages get resolved by rebuilding from a branch nobody validated.
Exit Codes
Formula: a code above 128 means killed by signal code − 128.
| Code | Meaning | First move |
|---|---|---|
| 125 | Docker daemon error (bad flag, missing image) | Read the run command, not the app |
| 126 | File found but not executable | chmod +x; or the entrypoint is a directory; or CRLF line endings on the entrypoint script |
| 127 | Command not found | PATH wrong, or a glibc binary on musl (Alpine), or the shell itself is absent (distroless) |
| 137 | SIGKILL (128+9) | Check .State.OOMKilled; also fired by stop-timeout expiry |
| 139 | SIGSEGV (128+11) | Native crash — suspect glibc/musl or architecture mismatch |
| 143 | SIGTERM (128+15) | Clean external stop — usually not a bug |
Defaults That Decide Behavior
Docker's defaults are tuned for a laptop demo, not for a service. Each of these has produced a production incident that reads as an application bug.
| Default | Value | Why it bites |
|---|---|---|
| Log driver | json-file, unbounded | One chatty container fills the host disk and hangs the daemon (Rule 7) |
/dev/shm | 64 MB | Chrome/Playwright and Postgres parallel queries crash with obscure errors; --shm-size=1g is the fix, not more RAM |
| Stop grace period | 10s, then SIGKILL | Anything that needs longer to drain must set --stop-timeout/stop_grace_period AND actually handle SIGTERM |
| Restart backoff | 100 ms, doubling, capped at 1 min | A crash loop self-throttles; rising RestartCount is the alarm, not the log volume |
| Default bridge network | No embedded DNS | Container-name resolution fails; user-defined networks have it (networking.md) |
| Healthcheck | interval 30s, timeout 30s, retries 3, start_period 0s | A service that boots in 60s is marked unhealthy before it ever answers (compose.md) |
| Address pool | 172.17.0.0/16 onward | Collides with corporate VPN ranges; set default-address-pools (production.md) |
| Network MTU | 1500 | Under a VPN with a lower MTU, large payloads hang while small ones succeed (networking.md) |
| User | root | Unless the image or USER says otherwise (Rule 5) |
| pids limit | unlimited | One fork bomb takes the host, not the container; pids_limit: 256 is cheap insurance |
Disk Leaks
/var/lib/docker at 100% hangs the daemon itself — you cannot prune through a daemon that won't respond. Alert well before full; locate leaks with docker system df -v.
| Leak | Reclaim |
|---|---|
| Dangling images | docker image prune |
| Build cache | docker builder prune --keep-storage GB |
| Stopped containers | docker container prune, or --rm at run time |
| Named volumes | docker volume prune — NOT touched by system prune without --volumes; destructive, confirm first |
| Orphan networks | docker network prune |
| A container's own writable layer | Not prunable — the app is writing inside the container instead of a volume; find it with docker diff (storage.md) |
Output Gates
Before emitting a Dockerfile, a Compose file, or a deploy command:
- Base image pinned to the strictness
pin_policyrequires — tag at minimum, digest if this ships to prod? - Dependency install layered before source copy, and a
.dockerignorepresent excluding.gitand dependency directories? - CMD/ENTRYPOINT in exec form, and does this runtime actually handle SIGTERM as PID 1?
USERset with a numeric UID, or root explicitly justified?- No secret reachable via ENV, ARG, or a COPYed file — and none written into
~/Clawic/data/? - Memory limit with a matching
--memory-swap, a log cap, and the runtime's own heap capped below the container limit? - Compose: healthcheck defined on every service something depends on,
start_periodabove worst-case boot time? - Is the command destructive (
prune,down -v,volume rm,system prune --volumes)? Then it names exactly what dies and ships with a confirmation step, never inside a copy-paste block of read-only commands. - Did anything durable come out of this — a host, a deploy digest, a working file, a volume, an environment fact, a root cause? Then it is written to its box in
memory-template.md, with its## Boxesline, in this same turn.
Configuration
User-dependent variables. Defaults apply until the user states a preference; store them in ~/Clawic/data/docker/config.yaml.
| Variable | Type | Default | Effect |
|---|---|---|---|
| runtime_flavor | Desktop | colima | orbstack | rootless | podman | Desktop | Selects socket path, host.docker.internal behavior, VM-ceiling reasoning and default-platform assumptions; rootless and podman change port-binding, cgroup and volume-permission advice (runtimes.md) |
| default_registry | text (registry host) | docker.io | Prefixes unqualified image references; switches push/pull and mirror examples to the user's registry (registry.md) |
| base_image_family | alpine | debian-slim | distroless | debian-slim | Drives base-image recommendations and the Alpine-vs-slim tradeoff (musl wheels, DNS, no-shell debugging) in images.md and languages.md |
| default_platform | arm64 | amd64 | arm64 | Sets the assumed build/run architecture; governs --platform reminders, multi-arch advice in ci.md, and exec format error diagnosis |
| pin_policy | tag | digest-in-prod | digest-everywhere | digest-in-prod | The strictness Rule 1 and the Output Gates enforce on every generated Dockerfile and compose file |
| hardening_profile | default | hardened | default | hardened makes every generated run/compose ship --read-only, --cap-drop ALL, no-new-privileges and a non-root UID unprompted (security.md) |
| ci_platform | github-actions | gitlab-ci | jenkins | buildkite | none | none | Which CI dialect ci.md examples are written in, and which cache backend is recommended |
| build_cache_budget_gb | number (GB, 1-200) | 10 | The --keep-storage figure in every prune command and the threshold for calling build cache a disk problem |
| destructive_confirm | bool | true | Whether prune, down -v and volume rm are emitted behind an explicit confirmation step or inline |
Preference areas — customizable dimensions; a stated preference gets recorded in config.yaml and applied from then on:
- Tooling — Compose vs plain
docker run, buildx/bake vs classic build, devcontainers vs a hand-rolled dev compose file, testcontainers usage — affects which shape every example takes - Conventions — tag scheme (
sha, semver, date), image namespace and labels,.dockerignorehabits, one-file-vs-many compose layout — affects generated files andci.mdtagging - Platform — single host vs CI vs a cloud target, multi-arch need, registry mirror or pull-through cache, host OS family (SELinux hosts need
:z/:Z) — affectsstorage.mdandregistry.md - Safety posture — how proactively to surface production hardening, whether to emit destructive commands at all, deletion confirmations, appetite for
--privilegedescapes — affects Output Gates andsecurity.md - Cadence — prune schedule, base-image rebuild and rescan frequency, volume-restore drill, reboot drill — every accepted cadence becomes a row in the
## Duetable ofmemory.md - Output register — command-first vs explanation-first, whether to show the diff of a Dockerfile or the whole file, how much of the reasoning to keep — affects every answer's shape
Traps
| Trap | Why it fails | Do instead |
|---|---|---|
| Secrets via ENV, ARG, or COPY | All three persist in image history — deleting the file in a later layer does not remove the earlier layer | BuildKit RUN --mount=type=secret; runtime env or mounted files (security.md) |
Mounting /var/run/docker.sock | Socket access = root on the host; any container escape is total | Dedicated proxy with a filtered API, or rethink the design |
ADD for local files | Auto-extracts archives; URL downloads bypass the build cache | COPY; fetch URLs in a RUN with checksum verification |
docker logs shows nothing | Only PID 1's stdout/stderr is captured — and buffered runtimes hold it until they exit | Log to stdout unbuffered (PYTHONUNBUFFERED=1 and friends, languages.md), or symlink the logfile to /dev/stdout |
| No shell in distroless/slim image | Nothing to exec into | docker cp files out, or attach a sidecar sharing the netns (commands.md) |
--privileged to fix a permission error | Disables every isolation mechanism at once | Find the one capability or device needed (security.md) |
| Bind mount over an image path | Host dir replaces container contents; empty host dir = empty app dir | Named volume — it seeds from the image on first use (storage.md) |
restart: always on dev boxes | Containers you stopped by hand come back after every host reboot | unless-stopped |
| Chasing an app "memory leak" without checking the VM | On Desktop/colima the VM has its own ceiling; the container never saw the RAM you think you gave it | docker info Total Memory before touching -m (runtimes.md) |
chmod 777 on a bind mount | Makes the symptom go away and the data world-writable; the mismatch is numeric UID, not permission bits | COPY --chown=: at build and run as that UID (storage.md) |
| Rebuilding to roll back | The branch you rebuild from is not the artifact that was validated | Deploy the recorded digest (Rule 9) |
| Scanning only in CI | CVEs are published after the build; an image approved in March rots in place | Scan at build AND in the registry, and rebuild on a cadence (security.md, ## Due) |
| A base-image or hardening decision that lives only in the chat | Re-litigated every quarter by whoever is on call | artifacts/ with the date and what was rejected (memory-template.md) |
Where Experts Disagree
- Alpine vs debian-slim. Alpine is smaller but musl breaks prebuilt Python wheels and has DNS edge cases. Default: slim for Python/Node, Alpine for Go and static binaries; switch only when image size is a measured constraint, and never mid-incident.
- Compose in production. Legitimate for single-host deployments; the boundary is multi-host scheduling, rolling deploys, or autoscaling — those needs, not fashion, justify an orchestrator (
k8s). - One process per container. The default. Escape hatch: a process supervisor when the platform offers no sidecar mechanism — never as a convenience to avoid writing a second service.
- Distroless vs a debuggable base. Distroless removes the shell an attacker would use and the shell you would use at 3am. The frontier is whether you can reliably attach a sidecar in the environment where it will break: if you can, distroless; if production is a box you SSH into, a slim base with a non-root user wins on mean-time-to-recovery.
- Rootless as the default. Rootless removes the largest single risk (daemon-as-root) at the cost of privileged ports, some mount types, and slower storage on older kernels. Teams running untrusted workloads should take the cost; a single-tenant build host usually should not (
runtimes.md).
Security & Privacy
Credentials: this skill drives the Docker CLI, which reads registry credentials from ~/.docker/config.json or an OS credential helper. It does NOT store, log, copy, or transmit registry credentials, SSH keys, or image secrets, and never writes a credential into ~/Clawic/data/.
Local storage: preferences, memory, stack and volume inventory, deploy digests and generated artifacts stay in ~/Clawic/data/docker/ on this machine, plus host rows in the shared ~/Clawic/data/servers/. Image names, digests, ports and volume names only — no secrets.
Guardrails: commands are read-only by default. Destructive operations (prune, down -v, volume rm, system prune --volumes) name exactly what they delete and require explicit confirmation when destructive_confirm is true.
Related Skills
More Clawic skills, get them at https://clawic.com/skills/docker (install if the user confirms):
k8s— Kubernetes manifests and cluster debugging, once the images leave a single hostdevops— deployment pipelines and release process around the buildlinux— host system management, cgroups, systemd units, firewallsserver— server administration for the box the daemon runs ontraefik— reverse proxy and TLS in front of Compose services
Feedback
- If useful, star it: https://clawic.com/skills/docker
- Latest version: https://clawic.com/skills/docker
Part of Clawic, the verified skill library. Get this skill: https://clawic.com/skills/docker.
相关技能
Systematic root-cause debugging with verification. Use for errors, stack traces, broken tests, flaky tests, regressions, or anything not working as expected. For validating bug reports before fixing, use bug-reproduction-validator agent.
围绕服务交付体系做设计 —— 流水线、发布策略、环境、可靠性、On-call —— 并把决策沉淀为本地笔记。
Use Python for practical project setup, dependency install, script execution, and environment troubleshooting with safe defaults. Use when tasks involve pypr...
逐跳排查代理、应用、依赖间的请求链路,定位并修复 Web 服务故障。
Use when the user asks how to build with OpenAI products or APIs and needs up-to-date official documentation with citations (for example: Codex, Responses AP...
Iván 的更多技能
浏览全部技能为自然搜索排名提供站点审计、内容撰写与竞品分析。
执行 Git 操作(提交、分支、合并、变基、冲突解决与恢复)时强制套用安全规则。
按配置的 JDK 版本诊断 Java 与 JVM 问题(从 NPE 到容器 OOM),给出可直接套用的代码与配置。
用可量化的层级、间距、字号、配色与版式规则,绘制并诊断视觉作品。
区分检索失败与生成失败,先定位再动手修 RAG 流水线。
围绕 CSS 机制排查问题并编写组件样式表,而不是凭感觉试错。