Контейнер работает, но что-то идёт не так. Логи не дают полной картины, конфиг надо проверить изнутри, процесс завис и непонятно почему. Чтобы разобраться, нужно попасть внутрь — и у Docker для этого есть несколько принципиально разных инструментов. Выбор зависит от того, работает ли контейнер прямо сейчас, есть ли в нём оболочка и что именно нужно сделать.
Способ 1: docker exec — правильный способ
docker exec запускает новый процесс внутри уже работающего контейнера. Это основной инструмент для интерактивного доступа и разовых команд.
Открыть интерактивную оболочку bash:
docker exec -it container_name bash
Если bash нет — попробовать sh:
docker exec -it container_name sh
Alpine-образы и многие минималистичные контейнеры не включают bash — только sh. Попытка открыть bash в таком контейнере даст OCI runtime exec failed: executable file not found.
Флаги:
-i— интерактивный режим (stdin остаётся открытым)-t— выделить псевдотерминал (TTY)- вместе
-itдают нормальный интерактивный сеанс с цветами, автодополнением и управляющими символами
Выполнить одну команду без входа в оболочку:
docker exec container_name cat /etc/nginx/nginx.conf
docker exec container_name ps aux
docker exec container_name env
Запустить команду от имени другого пользователя:
docker exec -it -u root container_name bash
docker exec -it -u www-data container_name sh
Полезно когда контейнер запускается от непривилегированного пользователя, но для отладки нужны права root.
Задать переменную окружения для команды:
docker exec -e DEBUG=true container_name python manage.py check
Способ 2: docker attach — подключиться к основному процессу
docker attach подключает ваш терминал к основному процессу контейнера (PID 1), а не запускает новый. Это важное отличие от exec.
docker attach container_name
Используется когда нужно видеть вывод основного процесса в реальном времени или отправить ему ввод. Но есть серьёзное ограничение: нажатие Ctrl+C отправляет SIGINT основному процессу и может остановить контейнер.
Чтобы выйти не останавливая контейнер — использовать escape-последовательность Ctrl+P, затем Ctrl+Q. Этот приём работает только если контейнер запущен с -it.
Способ 3: docker run -it — войти при запуске
Если контейнер ещё не запущен и нужно войти в него сразу при старте:
docker run -it ubuntu:22.04 bash
Для отладки образа — запустить с переопределением точки входа:
docker run -it --entrypoint bash nginx:latest
Это игнорирует ENTRYPOINT из Dockerfile и запускает bash вместо обычного процесса. Удобно когда нужно изучить содержимое образа до запуска приложения или когда сервис сразу падает и exec не успевает.
Способ 4: docker cp — скопировать файл из контейнера
Иногда не нужен интерактивный сеанс — нужно просто достать файл. docker cp работает без оболочки и даже с остановленными контейнерами:
Скопировать из контейнера на хост:
docker cp container_name:/etc/nginx/nginx.conf ./nginx.conf
Скопировать с хоста в контейнер:
docker cp ./new_config.conf container_name:/etc/nginx/nginx.conf
После замены файла конфигурации — перезагрузить процесс внутри контейнера:
docker exec container_name nginx -s reload
Способ 5: docker logs — читать вывод без входа
Прежде чем заходить в контейнер, стоит проверить логи — часто ответ уже там:
docker logs container_name
Следить за логами в реальном времени:
docker logs -f container_name
Показать последние N строк:
docker logs --tail 100 container_name
Добавить временны́е метки:
docker logs -t container_name
Логи за последние 30 минут:
docker logs --since 30m container_name
Найти контейнер: имя, ID и статус
Перед подключением нужно знать идентификатор контейнера.
Список запущенных контейнеров:
docker ps
Все контейнеры включая остановленные:
docker ps -a
Только ID (удобно для скриптов):
docker ps -q
Подключаться можно как по полному имени, так и по первым символам ID:
docker exec -it a3f bash # достаточно первых символов
Подключение к контейнеру без оболочки: distroless и scratch
Минималистичные образы на основе distroless (Google) или scratch не содержат ни bash, ни sh, ни даже базовых утилит. docker exec ... bash выдаст ошибку. Это намеренно — меньше поверхность атаки.
Способ 1 — nsenter через хост:
Получить PID основного процесса контейнера:
docker inspect --format '{{.State.Pid}}' container_name
Войти в пространства имён контейнера:
sudo nsenter -t <PID> -m -u -i -n -p -- sh
nsenter входит непосредственно в пространства имён (namespaces) контейнера на уровне ядра — без Docker API. Работает даже если в контейнере нет вообще никакого исполняемого файла.
Способ 2 — ephemeral debug container (Docker 20.10+):
docker debug container_name
Команда docker debug (доступна в Docker Desktop и новых версиях CLI) подключает временный debug-контейнер с полным набором инструментов к целевому контейнеру, разделяя его пространства имён.
Способ 3 — добавить утилиты в работающий контейнер через exec:
Если контейнер основан на дистрибутиве с пакетным менеджером но без нужных утилит:
docker exec -it container_name apt-get install -y procps curl
docker exec -it container_name sh
Изменения не переживут пересоздание контейнера, но для отладки этого достаточно.
Подключение к контейнеру по SSH
SSH в Docker — антипаттерн для большинства случаев: контейнер должен делать одно дело, а не быть мини-сервером. Но для специфичных задач (легаси-приложения, требующие SSH, VPN-соединения, обучающие среды) это применяется.
Если в контейнере уже запущен sshd — подключиться как к обычному серверу:
# Узнать порт проброса
docker ps | grep container_name
# PORTS: 0.0.0.0:2222->22/tcp
ssh user@localhost -p 2222
Полезные команды для диагностики изнутри контейнера
После входа в контейнер — быстрая диагностика.
Процессы:
ps aux
Сетевые соединения:
ss -tlnp
Переменные окружения:
env | sort
Дисковое пространство:
df -h
Файловая система корня:
ls -la /
Какой дистрибутив:
cat /etc/os-release
Шпаргалка
| Задача | Команда |
|---|---|
| Войти в запущенный контейнер | docker exec -it name bash |
| Войти через sh (Alpine и др.) | docker exec -it name sh |
| Выполнить команду без входа | docker exec name команда |
| Выполнить от имени root | docker exec -it -u root name bash |
| Подключиться к основному процессу | docker attach name |
| Выйти из attach не останавливая | Ctrl+P, затем Ctrl+Q |
| Войти при запуске контейнера | docker run -it image bash |
| Войти переопределив entrypoint | docker run -it --entrypoint bash image |
| Скопировать файл из контейнера | docker cp name:/path/file ./file |
| Смотреть логи в реальном времени | docker logs -f name |
| Войти в distroless контейнер | sudo nsenter -t $(docker inspect --format '{{.State.Pid}}' name) -m -u -i -n -p -- sh |
| Список запущенных контейнеров | docker ps |