kubectl get pods의 STATUS에 ImagePullBackOff나 ErrImagePull이 떠 있다면, 컨테이너를 시작하기도 전에 노드가 이미지를 레지스트리에서 받지 못하고 있다는 뜻입니다. ErrImagePull은 "방금 풀에 실패함", ImagePullBackOff는 "실패해서 점점 긴 간격으로 재시도 중"입니다. 둘 다 원인은 풀(pull) 단계에 있습니다.
1단계 — 실패 이유를 이벤트에서 본다
로그는 의미가 없습니다(컨테이너가 안 떴으니까). describe의 Events를 봅니다.
kubectl describe pod <pod>
출력 맨 아래 Events에서 Failed to pull image 뒤의 메시지가 핵심 단서입니다.
Failed to pull image "myreg/api:latst":
rpc error: code = NotFound desc = manifest unknown
2단계 — 에러 메시지로 원인 좁히기
| 메시지 키워드 | 원인 |
|---|---|
manifest unknown / not found | 이미지 이름 또는 태그 오타 |
pull access denied / 401 Unauthorized | 프라이빗 레지스트리 인증 누락 |
no such host / i/o timeout | 레지스트리 주소 오타 또는 네트워크 차단 |
toomanyrequests | Docker Hub 익명 풀 한도 초과 |
원인 5가지와 해결
① 이미지 이름·태그 오타 (manifest unknown) — latst처럼 태그 오타, 또는 존재하지 않는 태그. 매니페스트의 image: 값을 레지스트리에 실제로 있는 태그와 대조합니다. 풀 가능 여부는 docker pull <image>로 빠르게 확인됩니다.
② 프라이빗 레지스트리 인증 누락 (401) — imagePullSecrets가 없거나 잘못된 경우. 시크릿을 만들고 Pod에 연결합니다.
kubectl create secret docker-registry regcred \
--docker-server=<registry> \
--docker-username=<user> --docker-password=<pw>
매니페스트의 spec.imagePullSecrets: [{name: regcred}]에 추가합니다.
③ 레지스트리 주소 오류 (no such host) — 사설 레지스트리 도메인 오타나 DNS 미해석. 노드에서 nslookup <registry>로 해석되는지 확인합니다.
④ Docker Hub 풀 한도 (toomanyrequests) — 익명 풀은 IP당 한도가 있습니다. 인증된 Docker Hub 계정을 imagePullSecrets로 붙이거나 사내 미러 레지스트리를 씁니다.
⑤ imagePullPolicy 오해 — 로컬에만 있는 이미지인데 Always라 레지스트리에서 받으려다 실패. 로컬 빌드 이미지는 정책과 노드 상황을 함께 확인합니다.
체크리스트
kubectl describe pod <pod> # Events의 Failed to pull 메시지
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].image}' # 실제 image 값
kubectl get secret # imagePullSecrets 존재 여부
docker pull <image> # 같은 이미지가 진짜 풀 되는지
이 4개면 위 5원인이 거의 다 가려집니다.
프라이빗 레지스트리 인증과 imagePullSecrets를 직접 붙여보며 풀 실패를 재현·해결하는 실습은 쿠버네티스 트랙에서 회원가입 없이 무료로 해볼 수 있습니다.