← Назад к вопросам
Отладка неработающего Docker контейнера
1.8 Middle🔥 181 комментариев
#Docker и контейнеризация
Условие
Вам дали скомпилированный бинарник приложения без исходников. При запуске в Docker контейнере приложение не работает.
Задача
Опишите пошаговый процесс отладки:
- Как проверить, что контейнер запустился?
- Как посмотреть логи контейнера?
- Как войти внутрь контейнера для отладки?
- Какие инструменты использовать для диагностики?
- Как проверить сетевые соединения изнутри контейнера?
Сценарии проблем
- Приложение падает сразу после старта
- Приложение работает, но недоступно по сети
- Приложение медленно отвечает
- Приложение потребляет много памяти
Команды для каждого сценария
Приведите конкретные команды docker и linux для диагностики каждой проблемы.
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
1. Проверка статуса контейнера
Основные команды
# Список всех контейнеров
docker ps -a
# Формат с дополнительной информацией
docker ps -a --format 'table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
# Только ID
docker ps -aq
# С временем создания
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.CreatedAt}}\t{{.Status}}"
Интерпретация статусов
# GOOD: Контейнер работает
Up 2 hours # ✅ Нормально работает
Up 2 hours (healthy) # ✅ Healthcheck OK
Up 2 hours (unhealthy) # ⚠️ Healthcheck FAILED
# BAD: Контейнер не работает
Exited (0) # ✅ Завершился корректно (код 0)
Exited (1) # ❌ Ошибка (код 1)
Exited (137) # ❌ Убит сигналом (OOMKilled)
Exited (139) # ❌ Segmentation fault
Created # ❌ Создан но не запущен
Restarting # ❌ Постоянно перезапускается
Dead # ❌ Процесс зависший
Детальная информация о контейнере
# Полная информация
docker inspect <container_id>
# Только состояние
docker inspect <container_id> --format='{{.State}}'
# Exit code
docker inspect <container_id> --format='{{.State.ExitCode}}'
# Started time и finished time
docker inspect <container_id> --format='Started: {{.State.StartedAt}} Finished: {{.State.FinishedAt}}'
# IP адрес контейнера
docker inspect <container_id> --format='{{.NetworkSettings.IPAddress}}'
2. Просмотр логов контейнера
Основные команды
# Все логи
docker logs <container_id>
# Последние 100 строк
docker logs --tail 100 <container_id>
# В реальном времени (follow)
docker logs -f <container_id>
# С временными метками
docker logs -t <container_id>
# Последние 10 минут
docker logs --since 10m <container_id>
# С форматированием времени
docker logs --timestamps <container_id> 2>&1 | head -50
Анализ логов
# Поиск ошибок
docker logs <container_id> 2>&1 | grep -i error
# Последняя ошибка
docker logs <container_id> 2>&1 | tail -20
# Количество логов
docker logs <container_id> 2>&1 | wc -l
# Сохранение в файл для анализа
docker logs <container_id> > container.log 2>&1
# Поиск pattern
docker logs <container_id> 2>&1 | grep "Connection refused"
# Уникальные ошибки
docker logs <container_id> 2>&1 | grep -i error | sort | uniq
Логирование из Dockerfile
# Если приложение не логирует в stdout
# Перенаправьте логи
# В Dockerfile:
# CMD ["./app", "--log-file=-"] # - = stdout
# Или
# CMD ["/bin/sh", "-c", "./app 2>&1"] # Перенаправляем stderr в stdout
3. Вход внутрь контейнера для отладки
Запущенный контейнер
# Interactive shell
docker exec -it <container_id> /bin/bash
# или
docker exec -it <container_id> /bin/sh
# Выполнить одну команду
docker exec <container_id> ps aux
# С переменной окружения
docker exec -e DEBUG=1 <container_id> /bin/bash
# От другого пользователя
docker exec -u root <container_id> /bin/bash
Остановленный контейнер
# Запустить новый контейнер с тем же image
docker run -it <image_name> /bin/bash
# Или создать контейнер на основе остановленного
docker commit <container_id> debug-image
docker run -it debug-image /bin/bash
# Запустить контейнер на основе образа и замаунтить volume
docker run -it -v /path/on/host:/data <image_name> /bin/bash
Отладка с помощью Dockerfile
# Добавьте debug tools в образ
FROM ubuntu:22.04
# Установка debug tools
RUN apt-get update && apt-get install -y \
curl \
wget \
netcat \
telnet \
strace \
ltrace \
tcpdump \
procps \
vim \
htop
COPY ./app /app
WORKDIR /app
CMD ["./app"]
4. Диагностические инструменты внутри контейнера
Минимальный набор
# Внутри контейнера проверяем
ls -la # Файловая система
pwd # Рабочая директория
env # Переменные окружения
ps aux # Процессы
df -h # Место на диске
free -h # Память
netstat -tlnp # Открытые порты
ifconfig # Сеть
Встроенные инструменты для мониторинга
# Основные команды в контейнере
# Вывести переменные окружения, которые может использовать приложение
env | sort
# Проверить рабочую директорию
pwd && ls -la
# Проверить бинарник
file /app/myapp
ldd /app/myapp # Зависимости (если бинарник скомпилирован для Linux)
# Запустить с debug информацией
strace -e trace=file ./myapp # Отследить файловые операции
strace -e trace=network ./myapp # Отследить сетевые операции
# Посмотреть какие системные вызовы делает приложение
ltrace ./myapp # Library calls
# Проверить правильность ELF образа
readelf -l /app/myapp
Работа с сетью
# Проверить на что слушает приложение
netstat -tlnp
netstat -tlnp | grep LISTEN
# Или
ss -tlnp
# Проверить открытые соединения
netstat -anp
netstat -anp | grep ESTABLISHED
# DNS
nslookup google.com
cat /etc/resolv.conf # DNS серверы
# Проверка порта в локальной сети
netcat -v <host> <port>
netcat -zv <host> <port> # -z = только проверка, без отправки
# TCP/UDP
nc -u <host> <port> # UDP
# Curl для HTTP
curl -v http://localhost:8080
curl -v http://localhost:8080/health
5. Проверка сетевых соединений
Из host машины
# Проверить что контейнер слушает
docker port <container_id>
# Прямое подключение к контейнеру
IP=$(docker inspect <container_id> --format='{{.NetworkSettings.IPAddress}}')
netcat -v $IP 8080
# curl с verbose
curl -v http://$IP:8080
# tcpdump - перехват пакетов
sudo tcpdump -i docker0 'port 8080'
Внутри контейнера
# Проверить что слушает
netstat -tlnp
ss -tlnp
# Если порт занят другим процессом
fuser 8080/tcp # Какой процесс слушает
lsof -i :8080 # Список файлов для порта
# Проверить localhost
netcat -v localhost 8080
curl -v http://localhost:8080
# Проверить 0.0.0.0 (все интерфейсы)
netcat -v 0.0.0.0 8080
# Проверить сетевой интерфейс
ifconfig
ip addr
# DNS resolution
nslookup <external_service>
host <external_service>
6. Сценарий 1: Приложение падает сразу
Диагностика
# Шаг 1: Проверить статус
docker ps -a
# Status: Exited (1) или Exited (127)
# Шаг 2: Посмотреть логи
docker logs <container_id>
# Обычно видна ошибка в логах
# Шаг 3: Проверить exit code
docker inspect <container_id> --format='{{.State.ExitCode}}'
# 0 = успех
# 1 = ошибка приложения
# 127 = бинарник не найден
# 128+signal = убит сигналом
# 137 = OOMKilled
# Шаг 4: Если логов мало - запустить вручную
docker run --rm <image_name> ./app
# Или с bash для отладки
docker run --rm -it <image_name> /bin/bash
# Внутри: ./app
Возможные причины
# 1. Бинарник не совместим с ОС в образе
docker run --rm <image_name> file /app/myapp
# Проверить что это Linux executable
# 2. Отсутствуют зависимости
docker run --rm <image_name> ldd /app/myapp
# Если libc не найдена - нужна glibc base image
# 3. Отсутствуют переменные окружения
docker run --rm -e CONFIG_PATH=/etc/config <image_name> ./app
# 4. Отсутствуют файлы конфигурации
docker run --rm -v /local/config:/app/config <image_name> ./app
# 5. Неправильные права доступа
docker run --rm <image_name> ls -la /app/myapp
# Должно быть executable (-x)
7. Сценарий 2: Приложение работает, но недоступно по сети
Диагностика
# Шаг 1: Проверить что контейнер работает
docker ps | grep <container_id>
# Status: Up
# Шаг 2: Проверить логи нет ли ошибок
docker logs <container_id>
# Шаг 3: Войти в контейнер
docker exec -it <container_id> /bin/bash
# Шаг 4: Проверить что приложение слушает внутри контейнера
netstat -tlnp
ss -tlnp
# Шаг 5: Проверить адрес и порт
# ВАЖНО: Должно быть 0.0.0.0:8080 или :::8080 (IPv6)
# НЕ должно быть 127.0.0.1:8080 (только localhost)
# Шаг 6: Проверить с curl внутри контейнера
curl -v http://localhost:8080
Возможные причины
# 1. Приложение слушает на localhost только
# Решение: Измените конфигурацию на 0.0.0.0
# ./app --bind 0.0.0.0:8080
# 2. Неправильное port mapping
docker port <container_id> # Проверить mapping
# Если пусто, перезапустите с портом
docker stop <container_id>
docker rm <container_id>
docker run -p 8080:8080 <image_name>
# 3. Firewall блокирует порт
sudo iptables -L -n | grep 8080
sudo ufw status | grep 8080
# 4. Неправильный порт в EXPOSE
docker inspect <image_name> | grep -i expose
8. Сценарий 3: Приложение медленно отвечает
Диагностика
# Шаг 1: Проверить CPU и память
docker stats <container_id>
# Шаг 2: Если CPU 100% - горячий цикл
# Войти в контейнер
docker exec -it <container_id> /bin/bash
# Посмотреть процессы
top
ps aux
# Отследить системные вызовы
strace -p <pid> -e trace=open,read,write
# Шаг 3: Если память растет - утечка
# Мониторить память
watch 'docker stats <container_id>'
# Шаг 4: Проверить I/O
docker exec <container_id> iostat
docker exec <container_id> vmstat
# Шаг 5: Если медленнее всего конкретный endpoint
# Проверить логи с временами
docker logs -t <container_id> | tail -100
Оптимизация
# Увеличить ресурсы контейнера
docker run --cpus="2" --memory="4g" <image_name>
# Профилирование с помощью perf (если есть)
docker exec --privileged <container_id> perf record -F 99 -p <pid>
9. Сценарий 4: Приложение потребляет много памяти
Диагностика
# Шаг 1: Текущее использование
docker stats --no-stream <container_id>
# Шаг 2: История
docker stats <container_id> --no-stream
# Запустить несколько раз
# Шаг 3: Войти в контейнер
docker exec -it <container_id> /bin/bash
# Шаг 4: Посмотреть как распределена память
cat /proc/meminfo
free -h
# Шаг 5: По процессам
ps aux --sort=-%mem | head
# Шаг 6: Отследить утечку памяти
# Если память постоянно растет
watch -n 1 'free -h'
watch -n 1 'ps aux --sort=-%mem | head -10'
# Шаг 7: Профилирование памяти
# Если приложение на Python
python -m memory_profiler ./app
# На Go
pprof http://localhost:6060/debug/pprof/heap
Решение
# Увеличить лимит памяти
docker run --memory="8g" <image_name>
# Проверить что есть swap
free -h
# Если утечка памяти в приложении - отладить код
# Если нет - может быть проблема с зависимостями (library leak)
# Перезагружать контейнер периодически
# В docker-compose
restart_policy:
condition: on-failure
max_retries: 5
10. Комплексная проверка контейнера
#!/bin/bash
# Скрипт для полной диагностики контейнера
CONTAINER=$1
echo "=== Статус контейнера ==="
docker ps -a | grep $CONTAINER
echo ""
echo "=== Логи (последние 50 строк) ==="
docker logs --tail 50 $CONTAINER
echo ""
echo "=== Exit code ==="
docker inspect $CONTAINER --format='{{.State.ExitCode}}'
echo ""
echo "=== IP адрес ==="
docker inspect $CONTAINER --format='{{.NetworkSettings.IPAddress}}'
echo ""
echo "=== Port mapping ==="
docker port $CONTAINER
echo ""
echo "=== Ресурсы ==="
docker stats --no-stream $CONTAINER
echo ""
echo "=== Открытые порты внутри ==="
docker exec $CONTAINER netstat -tlnp 2>/dev/null || docker exec $CONTAINER ss -tlnp
echo ""
echo "=== Переменные окружения ==="
docker exec $CONTAINER env
echo ""
echo "=== Файловая система ==="
docker exec $CONTAINER ls -la /
11. Best practices для отладки
# 1. Используйте healthcheck в Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 2. Логируйте в stdout/stderr
CMD ["./app", "--log-file=/dev/stdout"]
# 3. Используйте minimal images (alpine)
FROM alpine:latest
# 4. Добавьте debug tools в dev image
FROM python:3.11 as debug
RUN apt-get update && apt-get install -y curl netcat
# 5. Используйте docker-compose для локального тестирования
docker-compose up
# 6. Сохраняйте логи для анализа
docker logs <container> > /tmp/container.log
# 7. Используйте docker events для мониторинга
docker events --filter "container=<container_id>"
# 8. Commitьте debug образы для сохранения состояния
docker commit <container_id> debug-image:latest
docker run -it debug-image:latest /bin/bash