Learning Platform
Глоссарий Troubleshooting
Урок 15.03 · 22 мин
Средний
dockerdebuginspect

docker inspect и events

Третий debug-инструмент после logs и exec — это inspect. Это команда, которая выдаёт всё, что Docker знает о контейнере: статус, exit code, networks, volume mappings, environment, restart history. Возвращает JSON, и через --format можно вытащить конкретное поле.

Параллельно — docker events, stream событий в реальном времени. Полезно, когда контейнер постоянно рестартится, и хочешь понять, в какой момент он умирает.


jq, yq, JSON и YAML из командной строки

docker inspect basic

docker inspect pg

Выведет JSON-массив с одним объектом — структурой контейнера. Это огромный документ (200+ строк), внутри:

[
  {
    "Id": "5fa3d8e9b1c0...",
    "Created": "2026-05-15T09:42:11.234Z",
    "Path": "docker-entrypoint.sh",
    "Args": ["postgres"],
    "State": {
      "Status": "running",
      "Running": true,
      "Paused": false,
      "Restarting": false,
      "OOMKilled": false,
      "Dead": false,
      "Pid": 12345,
      "ExitCode": 0,
      "Error": "",
      "StartedAt": "2026-05-15T09:42:11.567Z",
      "FinishedAt": "0001-01-01T00:00:00Z"
    },
    "Image": "sha256:...",
    "RestartCount": 0,
    "Config": {
      "Env": ["POSTGRES_USER=de", "POSTGRES_PASSWORD=secret", ...]
    },
    "HostConfig": {
      "Binds": [],
      "RestartPolicy": {"Name": "no", "MaximumRetryCount": 0}
    },
    "NetworkSettings": {
      "IPAddress": "172.17.0.2",
      "Ports": {"5432/tcp": [{"HostIp": "0.0.0.0", "HostPort": "5432"}]}
    },
    "Mounts": [...]
  }
]

Чтобы вытащить конкретное поле — --format с Go template:

docker inspect pg --format '{{.State.Status}}'
# running

docker inspect pg --format '{{.NetworkSettings.IPAddress}}'
# 172.17.0.2

docker inspect pg --format '{{.RestartCount}}'
# 0

docker inspect pg --format '{{.State.ExitCode}}'
# 0

--format — это Go-шаблон. Точка . — корневой объект, .State.Status — путь к полю. Если поле — массив, можно итерировать через range:

docker inspect pg --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
# /var/lib/docker/volumes/pg-data/_data -> /var/lib/postgresql/data

Или вывести JSON только нужной части через json:

docker inspect pg --format '{{json .State}}'
# {"Status":"running","Running":true,...}
TIP

Вспомнить точное название поля можно так: docker inspect pg | grep -i ip — поищет «ip» в JSON-выводе, покажет окружающие строки с правильным path. Дальше делаешь --format '{{.NetworkSettings.IPAddress}}'.


Самые полезные поля для debug

ПолеЧто говорит
.State.Statusrunning, exited, paused, dead, restarting
.State.ExitCodeКод выхода последнего процесса. 0 = ОК, не 0 = ошибка
.State.OOMKilledtrue если killed по OOM (out of memory)
.State.ErrorТекст ошибки запуска, если контейнер не стартанул
.RestartCountСколько раз перезапускался по restart policy
.State.StartedAt / .FinishedAtКогда стартовал / упал
.NetworkSettings.IPAddressIP в default bridge
.NetworkSettings.NetworksIP в каждой сети (для compose — там IP в user-defined network)
.HostConfig.RestartPolicyПолитика рестарта: no/on-failure/always/unless-stopped
.MountsСписок volumes/bind mounts
.Config.EnvВсе env-переменные
.Config.Cmd / .Config.EntrypointТочка входа

Самый частый чек при «контейнер не работает»:

docker inspect <c> --format '{{.State.Status}} (exit {{.State.ExitCode}})'
# exited (exit 1)

docker inspect <c> --format '{{.State.Error}}'
# (empty if started OK, or "OCI runtime create failed: ...")

Inspect для образа

docker inspect работает и для образов:

docker inspect postgres:16 --format '{{.Config.Env}}'
# [PATH=... GOSU_VERSION=1.17 LANG=en_US.utf8 PG_MAJOR=16 PG_VERSION=16.3 PGDATA=/var/lib/postgresql/data]

docker inspect postgres:16 --format '{{.Config.ExposedPorts}}'
# map[5432/tcp:{}]

docker inspect postgres:16 --format '{{.Config.Entrypoint}}'
# [docker-entrypoint.sh]

Удобно, когда читаешь чужой образ и хочешь понять, что именно он запускает и какие переменные ожидает.

Что покрывает inspect
StateТекущий статус: running/exited/paused, ExitCode, OOMKilled, RestartCount, StartedAt/FinishedAt
ConfigКонфигурация контейнера: Env, Cmd, Entrypoint, ExposedPorts, Hostname, User
NetworkSettingsIP-адреса во всех сетях, проброс портов, Gateway, MAC-адрес, DNS
MountsСписок volume и bind mount: Source, Destination, Mode (ro/rw), Driver, Propagation
HostConfigПараметры запуска: RestartPolicy, Resources (CPU/Memory limits), LogConfig, SecurityOpt, ReadonlyRootfs

docker events: real-time stream

docker events стримит события Docker daemon: запуск контейнера, остановка, OOM, healthcheck failed, network connect/disconnect. Полезно, когда что-то происходит и хочешь увидеть, что именно.

docker events

В другом терминале:

docker run --rm hello-world

В терминале с events:

2026-05-15T10:15:23.456Z container create 7f3e... (image=hello-world, name=quirky_pasteur)
2026-05-15T10:15:23.567Z network connect ad34... (container=7f3e..., name=bridge)
2026-05-15T10:15:23.678Z container start 7f3e... (image=hello-world, name=quirky_pasteur)
2026-05-15T10:15:23.890Z container die 7f3e... (exitCode=0, image=hello-world, name=quirky_pasteur)
2026-05-15T10:15:23.912Z network disconnect ad34... (container=7f3e..., name=bridge)
2026-05-15T10:15:23.945Z container destroy 7f3e... (image=hello-world, name=quirky_pasteur)

Видим весь жизненный цикл: create -> network connect -> start -> die -> destroy. --rm означает уничтожение после die — это видно в events.

Фильтры

--filter сужает события:

# Только события контейнера pg
docker events --filter container=pg

# Только OOM
docker events --filter event=oom

# Только конкретные типы (контейнеры, не сети/volume)
docker events --filter type=container

# С определённого момента
docker events --since 10m

Идеальный сценарий для «контейнер рестартится каждые 30 секунд»:

docker events --filter container=app

И смотришь, в каком порядке идут события. Часто видишь: start -> die exitCode=137 (OOM!) -> start -> die exitCode=137. Это OOM Killer убивает по нехватке памяти. Фикс: добавить --memory лимит и оптимизировать приложение.


OOM-детект

OOM (out of memory) — частая причина «контейнер падает без объяснений». Проверяется так:

1. docker inspect -> .State.OOMKilled:

docker inspect app --format '{{.State.OOMKilled}}'
# true

2. Exit code 137:

docker inspect app --format '{{.State.ExitCode}}'
# 137

137 = 128 + 9, где 9 — SIGKILL. OOM Killer ядра шлёт SIGKILL, процесс не может его обработать, контейнер умирает.

3. В dmesg на хосте:

dmesg | grep -i kill
# Out of memory: Killed process 12345 (python) total-vm:1024MB, ...

4. docker events --filter event=oom:

docker events --filter event=oom
# 2026-05-15T11:23:45.678Z container oom 5fa3... (image=my-etl, name=app)

Имея 4 источника подтверждения OOM, фикс понятен:

  • Поставить --memory 512m на контейнер, чтобы он умирал управляемо (с понятной ошибкой), а не хост стучался в OOM Killer.
  • Оптимизировать приложение (профайлинг, разбиение работы).

Health status

Если у контейнера задан HEALTHCHECK (из Dockerfile или compose), inspect покажет:

docker inspect pg --format '{{.State.Health.Status}}'
# healthy

docker inspect pg --format '{{json .State.Health}}'
# {"Status":"healthy","FailingStreak":0,"Log":[{"Start":"...","End":"...","ExitCode":0,"Output":"..."}]}

Поле Log хранит последние ~5 healthcheck-вызовов с выводом. Удобно, когда healthcheck время от времени фейлится — видишь стектрейс.


Реальный сценарий: «контейнер рестартится в цикле»

Симптомы: docker ps показывает контейнер со статусом Restarting (1) X seconds ago. Что делать.

1. Узнать exit code:

docker inspect app --format '{{.State.ExitCode}} (started {{.RestartCount}} times)'
# 1 (started 23 times)

Exit 1 = «общая ошибка приложения». RestartCount растёт — restart policy на always или on-failure.

2. Посмотреть логи последнего запуска:

docker logs app --tail 50
# Traceback (most recent call last):
#   File "/app/main.py", line 12, in <module>
#     from psycopg import connect
# ModuleNotFoundError: No module named 'psycopg'

Ага, не установили psycopg. Чиним Dockerfile.

3. Если логи пустые, смотрим events с момента запуска:

docker events --since $(docker inspect app --format '{{.Created}}') --filter container=app

Увидим последовательность create -> start -> die -> start -> die. Если между start и die проходит миллисекунда — приложение падает сразу.

Debug «контейнер не работает» через inspect + events
docker ps -aСмотрим статус: Up / Exited / Restarting. Если Exited — упал, если Restarting — крутится в цикле
inspect --format ExitCode + OOMKilledExitCode 0 = OK. 137 = OOM. 1 = generic error. 125 = docker daemon error. 126 = команда не исполняемая. 127 = команда не найдена
docker logs --tail 50Последние строки stdout/stderr перед смертью — обычно там traceback или ошибка startup'а
docker events для timelineСобытия в порядке: create, start, die. Помогает увидеть pattern (рестартится после healthcheck fail, или сразу при старте)

Попробуй сам

  1. Запусти redis:7-alpine. Сделай docker inspect redis --format '{{.NetworkSettings.IPAddress}}'.
  2. Получи статус и exit code в одну строку: docker inspect redis --format '{{.State.Status}} ({{.State.ExitCode}})'.
  3. В отдельном терминале запусти docker events --filter container=redis. В первом — docker stop redis && docker start redis. Посмотри сообщения в events-окне.
  4. Создай контейнер с лимитом памяти и сожги её: docker run -d --name eater --memory 64m python:3.13-slim python -c "x = ' ' * 200_000_000". Сразу docker inspect eater --format '{{.State.OOMKilled}} (exit {{.State.ExitCode}})'. Должно быть true (exit 137).
  5. Запусти docker events в одном терминале, в другом сделай пару docker run --rm hello-world. Прочитай последовательность событий.
  6. Для compose-стенда: docker compose events — то же, но фильтрует на сервисы compose-проекта.

Проверка знанийKnowledge check
Как с помощью docker inspect и docker events понять, что контейнер падал именно по OOM (out of memory), и что значит exit code 137?
ОтветAnswer
Признаков OOM четыре: 1) docker inspect <c> --format '{{.State.OOMKilled}}' -> true. Это самый надёжный индикатор — Docker daemon явно отметил, что контейнер был убит по OOM. 2) docker inspect <c> --format '{{.State.ExitCode}}' -> 137. Это 128 + 9, где 9 = SIGKILL. OOM Killer ядра Linux шлёт SIGKILL процессу, и поскольку SIGKILL невозможно перехватить, процесс умирает с кодом 9. По UNIX-конвенции exit code = 128 + signal, отсюда 137. 3) docker events --filter event=oom (в реальном времени) или --since 10m — покажет события OOM от daemon. 4) На Linux-хосте dmesg | grep -i kill покажет сообщение от OOM Killer: "Out of memory: Killed process <pid> (name) total-vm:XMB". Что делать: поставить --memory 512m на контейнер (тогда он умрёт управляемо при достижении лимита, не уронив хост), и оптимизировать приложение (профайлинг, batch размер, streaming вместо load-all-in-memory).

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Какая команда покажет ТОЛЬКО IP-адрес контейнера pg в default-bridge сети, без всего JSON?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5