
Docker run, exec, logs и inspect: практика без магии
Запускаем тестовый контейнер, разбираем порты и переменные, читаем журналы, выполняем команды через exec и проверяем реальное состояние через inspect.
Содержание
Чтобы не удалять контейнер при первой непонятной ошибке, нужно различать команды его жизненного цикла. run создаёт контейнер, start запускает его повторно, exec выполняет дополнительную команду внутри работающего экземпляра, logs читает вывод приложения, а inspect показывает сохранённые настройки и состояние.
Что будем проверять после запуска
Давайте контейнерам понятные имена, не публикуйте порт шире необходимого и после запуска проверяйте три слоя: список и состояние, журнал основного процесса, фактический HTTP-ответ. При сбое сначала сохраните inspect и logs, а уже затем удаляйте объект.
Проверьте Docker и свободный порт
Нужен установленный Docker Engine и свободный локальный порт. Убедитесь, что daemon отвечает:
Эти команды выполняются на VPS. Первая подтверждает связь клиента со службой Docker, вторая выводит версию серверной части, а третья проверяет, не занят ли порт 8080:
sudo docker version
sudo docker info --format '{{.ServerVersion}}'
sudo ss -lnt '( sport = :8080 )'
Пустой результат ss означает, что TCP-порт 8080 сейчас никто не слушает. На общем сервере выберите согласованный порт и не останавливайте чужой процесс ради примера.
Создайте контейнер осознанно
sudo docker run -d \
--name web-demo \
-p 127.0.0.1:8080:80 \
nginx:1.29-alpine
Здесь:
-dотсоединяет терминал;--nameзадаёт устойчивое имя;127.0.0.1:8080:80связывает локальный порт хоста с портом контейнера;- последним аргументом указан образ.
Явная привязка к loopback важна: запись -p 8080:80 обычно публикует порт на всех адресах хоста. Для первого опыта внешний доступ не нужен.
Проверьте контейнер и ответ:
sudo docker ps
sudo docker port web-demo
curl --fail --silent --show-error --head http://127.0.0.1:8080/
Успех — статус Up, отображение привязки и HTTP-ответ без ошибки curl.
Прочитайте журнал основного процесса
Сначала запросите полный журнал, затем ограничьте выдачу последними пятью минутами. Третья команда оставляет терминал ждать новые строки; она удобна, когда вы одновременно отправляете запрос из другого окна:
sudo docker logs web-demo
sudo docker logs --since 5m --tail 50 web-demo
sudo docker logs -f --since 1m web-demo
logs показывает stdout и stderr в пределах возможностей настроенного logging driver. Режим -f следует за новыми строками; выйдите из него через Ctrl+C — контейнер продолжит работать.
Если приложение пишет только во внутренний файл, docker logs останется пустым. Для контейнерной эксплуатации предпочтительнее направить прикладные события в стандартные потоки и отдельно настроить ротацию на хосте.
Выполните диагностическую команду через exec
sudo docker exec web-demo nginx -t
sudo docker exec web-demo ps
sudo docker exec -it web-demo sh
exec не изменяет команду основного процесса и не создаёт новый контейнер. Интерактивная оболочка полезна для краткой диагностики, но ручная правка конфигурации внутри неё исчезнет при пересоздании и не попадёт в Dockerfile.
Команда должна быть исполняемым файлом. Для shell-конструкций нужен явный интерпретатор:
sudo docker exec web-demo sh -c 'id && nginx -T 2>/dev/null | head'
Не передавайте секрет через аргументы без необходимости: команда может попасть в историю, журнал автоматизации или список процессов.
Используйте inspect для точных ответов
Полный документ inspect велик, поэтому ниже формат вывода ограничен четырьмя вопросами: работает ли контейнер, какие порты он публикует, из какого образа создан и какие каталоги подключены:
sudo docker inspect --format 'status={{.State.Status}} pid={{.State.Pid}}' web-demo
sudo docker inspect --format '{{json .NetworkSettings.Ports}}' web-demo
sudo docker inspect --format '{{.Config.Image}}' web-demo
sudo docker inspect --format '{{json .Mounts}}' web-demo
Inspect отвечает на вопросы, которые нельзя надёжно восстановить по памяти: какой образ использован, какие порты опубликованы, какие mounts подключены и почему контейнер остановился.
Для переменных окружения выводите только имена, если среди значений могут быть пароли:
sudo docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' web-demo \
| sed 's/=.*$/=<hidden>/'
Остановка, запуск и пересоздание
Остановите контейнер обычной командой и сравните два списка. Затем запустите тот же экземпляр снова; его имя, порт и остальные параметры останутся прежними:
sudo docker stop web-demo
sudo docker ps
sudo docker ps -a
sudo docker start web-demo
После stop контейнер исчезает из обычного docker ps, но остаётся в docker ps -a. start сохраняет прежние порты, mounts и переменные. Если нужно изменить эти параметры, создайте новый контейнер; у start нет задачи переписывать конфигурацию.
Проверьте завершение:
sudo docker inspect --format \
'status={{.State.Status}} exit={{.State.ExitCode}} error={{.State.Error}}' web-demo
Смоделируйте короткую задачу
Для одноразовой команды удобно автоматическое удаление. Следующий пример создаёт контейнер Alpine, печатает одну строку и удаляет контейнер сразу после завершения процесса:
sudo docker run --rm alpine:3.22 printf 'container completed\n'
--rm подходит, когда состояние после завершения не нужно исследовать. Для неизвестного приложения на первом запуске лучше оставить контейнер, проверить код выхода и удалить вручную.
Нельзя сочетать --rm с restart policy. И не используйте docker rm -f как обычную остановку: принудительное удаление затрудняет корректное завершение и диагностику.
Удалите только созданный пример
sudo docker stop web-demo
sudo docker rm web-demo
sudo docker image ls nginx:1.29-alpine
Удаление контейнера не удаляет образ. Не запускайте широкую очистку system prune на сервере, пока не понимаете, какие остановленные контейнеры, сети и build cache понадобятся для отката.
Диагностический порядок
Если сервис недоступен:
docker ps -a— существует ли объект и каков статус;docker inspect— код выхода, ошибка, порт и mounts;docker logs --since ...— события рядом со временем сбоя;docker exec— только если основной процесс работает;curlс хоста — отвечает ли опубликованный порт;- внешний запрос — доступен ли путь через firewall и reverse proxy.
Этот порядок отделяет ошибку приложения от неверной публикации порта. Системные события daemon смотрите через journalctl, а сетевой путь проверяйте по слоям. Далее разберите теги, digest и registry.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Чем docker run отличается от docker start?
docker run создаёт новый контейнер из образа и запускает его, а docker start повторно запускает уже существующий остановленный контейнер с прежней конфигурацией.
Почему docker exec не работает после остановки контейнера?
exec запускает дополнительный процесс внутри работающего контейнера. Когда основной процесс завершён, окружения для новой команды уже нет; сначала выясните причину через inspect и logs.
Где смотреть код завершения контейнера?
Используйте docker inspect с полями State.ExitCode, State.Error и State.FinishedAt. Журнал приложения объясняет контекст, но сам код надёжнее брать из состояния контейнера.


