Skip to main content
CodeOath
← All posts

Docker105 min total · 19 parts

Docker Fundamentals: Images, Containers, and Writing a Good Dockerfile

Part 17 of 19 · ~2 min

Debugging a Running Container

Two in the morning, three weeks after Berrywell went live: your phone buzzes with an alert that the job queue is backed up and climbing. worker is up, technically, but nothing's getting processed.

docker ps                          # worker is there, but "Up 38 seconds" — that number is wrong
docker logs -f worker              # follow stdout/stderr
docker exec -it worker sh          # drop into a shell inside the running container
docker inspect worker              # everything Docker knows about it, as one JSON blob
docker stats                       # a live-updating read on CPU, memory, and network use
docker top worker                  # what's actually running inside it, seen from the host

docker ps is the first clue: worker isn't just running, it's restarting, over and over, roughly every forty seconds. docker exec needs something to attach to that's alive right now, and by the time you type the command the container it would have attached to is usually already gone, replaced by whatever came after it — so this particular tool is off the table before you've even reached for it. docker logs, on the other hand, doesn't care whether the container is still running; it's reading history, not a live process. The tail of the log right before each restart shows nothing informative, though — just an abrupt cutoff mid-job, no exception, no stack trace.

docker inspect worker's .State section is where the actual answer is sitting:

"State": {
    "Status": "restarting",
    "ExitCode": 137,
    "Error": "",
    "OOMKilled": true,
    "StartedAt": "2026-10-02T02:11:47Z",
    "FinishedAt": "2026-10-02T02:12:24Z"
}

docker stats, watched live through the next restart cycle, confirms the shape of it — MEM USAGE / LIMIT climbs from under 100MiB toward 512MiB / 512MiB over roughly thirty seconds, and then the container disappears from the list and a new one takes its place a moment later. An exit code of 137 specifically means the process was terminated by SIGKILL — and here, "OOMKilled": true says plainly that the kill came from the kernel's own out-of-memory killer, not from anything Docker itself decided on its own.