Что означает ошибка ErrImagePull
Ошибка ErrImagePull (и её производная ImagePullBackOff) появляется, когда kubelet на узле кластера не может скачать указанный контейнерный образ из реестра. В логах вы увидите сообщение вида: Failed to pull image "registry.example.com/app:v1": rpc error: code = Unknown desc = failed to pull and unpack image.
Проблема блокирует запуск пода на этапе инициализации (Pending → ImagePullBackOff). Сервис остаётся недоступным, а оркестратор продолжает бесконечно ретраить операцию, постепенно увеличивая интервалы между попытками.
Причины возникновения
- Опечатка в имени образа или указание несуществующего тега (реестр возвращает
404 Not Found). - Отсутствие авторизации для приватного реестра (
403 Forbiddenили401 Unauthorized). - Блокировка исходящих соединений файрволом, отсутствие маршрутизации или некорректная настройка HTTP/HTTPS-прокси на нодах.
- Сбой локального DNS-резолвера, из-за которого домен реестра не преобразуется в IP-адрес.
- Нехватка свободного места на разделе
/var/lib/containerdили/var/lib/docker. Кэширование обрывается, и загрузка отменяется.
Способы решения
Способ 1: Валидация имени и тега образа
Частая причина — человеческий фактор при редактировании манифеста. Убедитесь, что путь к репозиторию, имя образа и тег совпадают с реально опубликованной версией.
- Найдите проблемный под:
kubectl get pods -n <namespace> | grep ErrImagePull - Посмотрите текущую конфигурацию:
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].image}' - Исправьте деплоймент:
kubectl set image deployment/<name> <container-name>=registry.example.com/app:v1.2.3
💡 Совет: Всегда используйте конкретные теги или SHA-дайджесты. Тег
latestусложняет отладку и может привести к загрузке нестабильной сборки.
Способ 2: Диагностика сетевых ограничений
Если образ публичный, но не грузится, проблема почти наверняка в сети узла. Kubelet использует системный стек ноды, а не сеть пода.
- Подключитесь к ноде по SSH:
ssh user@k8s-node-01 - Проверьте резолв:
nslookup registry.example.com - Попробуйте скачать образ напрямую:
crictl pull registry.example.com/app:v1.2.3 - Если команда падает, проверьте прокси:
systemctl show docker | grep -i proxyилиenv | grep -i proxy
Для корпоративных сред добавьте домены реестра в noProxy конфигурации systemd для containerd.service или docker.service.
Способ 3: Настройка imagePullSecrets для приватных реестров
Без корректного секрета kubelet не сможет аутентифицироваться в Docker Hub, GitLab Registry или AWS ECR. Секрет должен создаваться в том же неймспейсе, где разворачивается приложение.
kubectl create secret docker-registry regcred \
--docker-server=https://registry.example.com \
--docker-username=deploy-bot \
--docker-password=$CI_TOKEN \
--namespace=production
Привяжите секрет к деплойменту:
spec:
template:
spec:
containers:
- name: app
image: registry.example.com/app:v1.2.3
imagePullSecrets:
- name: regcred
Проверьте статус: kubectl get secret regcred -o yaml и убедитесь, что токен не истёк.
Способ 4: Очистка повреждённого кэша рантайма
Иногда частичная загрузка оставляет «битые» слои, которые блокируют повторные попытки. Рантайм не может распознать их и постоянно возвращает ошибку.
# Останавливаем проблемный под, чтобы kubelet перестал его трогать
kubectl scale deployment <name> --replicas=0
# Очищаем локальный кэш на ноде
sudo crictl rmi registry.example.com/app:v1.2.3
# Перезапускаем runtime
sudo systemctl restart containerd
После запуска снова масштабируйте деплоймент до нужного количества реплик. Загрузка начнётся с чистого листа.
Профилактика
- Синхронизация времени: Настройте
chronyилиsystemd-timesyncdна всех нодах. Расхождение системных часов более чем на 5 минут ломает TLS-рукопожатия с реестрами. - Мониторинг места на дисках: Поднимите
node-exporterи алерты наNodeDiskPressure. Забитый диск — самая тихая причина отказа загрузки. - Ротация токенов: Для CI/CD используйте short-lived credentials и автоматизируйте обновление
imagePullSecretsчерез External Secrets Operator или HashiCorp Vault. - Локальные зеркала: Для крупных кластеров настройте
registry-mirrorв конфигурацииcontainerd. Это снизит нагрузку на публичные реестры и уберет сетевые таймауты.