쿠버네티스(Kubernetes)를 운영하다 보면 가장 자주 마주치는 에러 중 하나가 바로 ‘ErrImagePull’ 입니다. 컨테이너 이미지를 가져오지 못해 파드가 시작되지 않는 이 문제는 우리를 당황시키곤 합니다. 하지만 정확한 원인을 파악하고 체계적으로 접근하면 생각보다 어렵지 않게 해결할 수 있습니다. 이번 글에서는 ErrImagePull 에러가 발생하는 주요 원인들을 살펴보고, 실제 상황에서 바로 적용할 수 있는 구체적인 해결방법들을 단계별로 정리해보겠습니다.
1. ErrImagePull 에러란 무엇인가?
ErrImagePull은 쿠버네티스 클러스터에서 파드를 생성할 때 컨테이너 이미지를 레지스트리에서 가져오는 과정에서 실패했을 때 발생하는 에러입니다. 이 에러가 발생하면 쿠버네티스는 몇 번 재시도를 하다가 결국 ‘ImagePullBackOff’ 상태로 전환되어 더 이상 이미지를 가져오려고 시도하지 않습니다.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-7d4b8c9f8d-xyz12 0/1 ErrImagePull 0 30s
이런 상황에서는 파드가 정상적으로 시작되지 않아 애플리케이션이 동작하지 않게 됩니다. 문제를 해결하려면 먼저 정확한 원인을 파악하는 것이 중요합니다.
2. 에러 발생 원인 5가지와 진단 방법
ErrImagePull 에러가 발생하는 주요 원인들을 살펴보겠습니다.
2-1. 잘못된 이미지 이름 또는 태그
가장 흔한 원인 중 하나입니다. 이미지 이름에 오타가 있거나 존재하지 않는 태그를 지정했을 때 발생합니다.
# 잘못된 예시
containers:
- name: my-app
image: nginx:wrongtag # 존재하지 않는 태그
2-2. 프라이빗 레지스트리 인증 문제
Docker Hub나 AWS ECR, Google Container Registry 등 프라이빗 레지스트리에서 이미지를 가져올 때 인증 정보가 없거나 잘못되었을 경우 발생합니다.
2-3. 네트워크 연결 문제
쿠버네티스 노드에서 컨테이너 레지스트리에 접근할 수 없을 때 발생합니다. 방화벽 설정이나 네트워크 정책으로 인한 문제일 수 있습니다.
2-4. 레지스트리 서버 문제
레지스트리 서버가 다운되었거나 응답하지 않을 때 발생할 수 있습니다.
2-5. 노드의 디스크 공간 부족
이미지를 다운로드할 공간이 부족할 때도 이 에러가 발생할 수 있습니다.
3. 문제 진단을 위한 필수 명령어들
문제를 해결하기 전에 정확한 원인을 파악해야 합니다. 다음 명령어들을 사용하여 에러의 상세 정보를 확인할 수 있습니다.
3-1. 파드 상세 정보 확인
kubectl describe pod [pod-name]
이 명령어를 실행하면 파드의 상세 정보와 함께 Events 섹션에서 에러의 구체적인 원인을 확인할 수 있습니다.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Failed 2m (x4 over 3m) kubelet Error: ErrImagePull
Warning Failed 1m (x6 over 3m) kubelet Error: ImagePullBackOff
Normal BackOff 1m (x7 over 3m) kubelet Back-off pulling image "nginx:wrongtag"
3-2. 파드 로그 확인
kubectl logs [pod-name] --all-containers
3-3. 이벤트 로그 확인
kubectl get events --field-selector involvedObject.name=[pod-name]
4. 프라이빗 레지스트리 인증 문제 해결하기
프라이빗 레지스트리를 사용할 때 가장 중요한 것은 올바른 인증 정보를 제공하는 것입니다.
4-1. Docker Registry Secret 생성
가장 일반적인 방법은 kubectl 명령어를 사용하여 시크릿을 생성하는 것입니다.
kubectl create secret docker-registry my-registry-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=your-username \
--docker-password=your-password \
--docker-email=your-email@example.com \
--namespace=default
AWS ECR의 경우:
kubectl create secret docker-registry ecr-secret \
--docker-server=123456789012.dkr.ecr.us-west-2.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region us-west-2) \
--namespace=default
Azure Container Registry의 경우:
kubectl create secret docker-registry acr-secret \
--docker-server=myregistry.azurecr.io \
--docker-username=myregistry \
--docker-password=your-password \
--namespace=default
4-2. YAML 파일로 Secret 생성
더 세밀한 제어를 원한다면 YAML 파일로 시크릿을 생성할 수 있습니다.
apiVersion: v1
kind: Secret
metadata:
name: my-registry-secret
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJ5b3VyLXVzZXJuYW1lIiwicGFzc3dvcmQiOiJ5b3VyLXBhc3N3b3JkIiwiZW1haWwiOiJ5b3VyLWVtYWlsQGV4YW1wbGUuY29tIiwiYXV0aCI6ImVXOTFjaTExYzJWeWJtRnRaVHA1YjNWeUxYQmhjM04zYjNKayJ9fX0=
.dockerconfigjson
값은 Base64로 인코딩된 Docker 설정 파일입니다. 다음과 같이 생성할 수 있습니다:
echo -n '{"auths":{"https://index.docker.io/v1/":{"username":"your-username","password":"your-password","email":"your-email@example.com","auth":"base64-encoded-username:password"}}}' | base64 -w 0
4-3. Deployment에서 imagePullSecrets 사용
시크릿을 생성한 후에는 Deployment 또는 Pod 설정에서 이를 참조해야 합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: your-private-registry/your-image:tag
ports:
- containerPort: 80
imagePullSecrets:
- name: my-registry-secret
5. 네트워크 연결 문제 해결하기
네트워크 문제로 인한 ErrImagePull 에러를 해결하는 방법들을 살펴보겠습니다.
5-1. 노드에서 레지스트리 접근 확인
먼저 쿠버네티스 노드에서 직접 레지스트리에 접근할 수 있는지 확인해야 합니다.
# 노드에 SSH 접속 후
curl -I https://registry-1.docker.io/v2/
성공적인 응답이 오지 않는다면 네트워크 설정을 확인해야 합니다.
5-2. DNS 설정 확인
nslookup registry-1.docker.io
5-3. 프록시 설정 확인
기업 환경에서는 프록시 설정이 필요할 수 있습니다. containerd나 Docker 데몬의 프록시 설정을 확인하세요.
# containerd 프록시 설정 예시
sudo mkdir -p /etc/systemd/system/containerd.service.d
sudo tee /etc/systemd/system/containerd.service.d/proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
EOF
sudo systemctl daemon-reload
sudo systemctl restart containerd
6. 이미지 이름과 태그 문제 해결하기
6-1. 올바른 이미지 이름 형식 확인
이미지 이름은 다음과 같은 형식을 따라야 합니다:
[REGISTRY_HOST[:PORT]/]USERNAME/REPOSITORY[:TAG]
예시:
# Docker Hub 공식 이미지
image: nginx:1.21
# Docker Hub 사용자 이미지
image: username/my-app:v1.0
# 프라이빗 레지스트리
image: my-registry.com:5000/my-app:latest
6-2. 이미지 존재 여부 확인
# Docker Hub에서 확인
docker search nginx
# 특정 레지스트리에서 확인
docker pull your-registry/your-image:tag
6-3. 태그 확인 방법
Docker Hub의 경우 웹사이트에서 사용 가능한 태그를 확인할 수 있습니다. API를 사용하여 확인하는 방법도 있습니다:
# Docker Hub API로 태그 확인
curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags/" | jq '.results[].name'
7. ErrImagePull에러 예방 및 모니터링 방법
7-1. imagePullPolicy 활용
적절한 imagePullPolicy를 설정하여 문제를 예방할 수 있습니다:
containers:
- name: my-app
image: my-app:v1.0
imagePullPolicy: IfNotPresent # 로컬에 없을 때만 pull
imagePullPolicy 옵션:
Always
: 항상 이미지를 다시 가져옴IfNotPresent
: 로컬에 없을 때만 가져옴 (기본값)Never
: 로컬 이미지만 사용
7-2. Service Account 설정
Service Account에 imagePullSecrets를 설정하여 네임스페이스 전체에서 사용할 수 있습니다:
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
imagePullSecrets:
- name: my-registry-secret
7-3. 모니터링 설정
Prometheus와 Grafana를 사용하여 이미지 pull 실패를 모니터링할 수 있습니다:
# 모니터링 예시 쿼리
kube_pod_container_status_waiting_reason{reason="ErrImagePull"}
kube_pod_container_status_waiting_reason{reason="ImagePullBackOff"}
8. 자주 발생하는 실수와 주의사항
8-1. 대소문자 구분
Docker Hub에서는 이미지 이름이 대소문자를 구분합니다. 올바른 형식을 확인하세요.
8-2. 네임스페이스 주의
Secret은 네임스페이스별로 관리되므로, Pod와 같은 네임스페이스에 생성해야 합니다.
8-3. 토큰 만료 관리
클라우드 제공업체의 인증 토큰은 주기적으로 갱신해야 합니다.
9. ErrImagePull 에러, 단계별 체크리스트
ErrImagePull 에러 발생 시 다음 순서로 확인하세요:
1단계: 기본 정보 확인
- [ ]
kubectl describe pod [pod-name]
으로 상세 에러 확인 - [ ] 이미지 이름과 태그 철자 확인
- [ ] 이미지가 실제로 존재하는지 확인
2단계: 네트워크 확인
- [ ] 노드에서 레지스트리 접근 가능 여부 확인
- [ ] DNS 설정 확인
- [ ] 프록시 설정 확인
3단계: 인증 확인
- [ ] imagePullSecret 존재 여부 확인
- [ ] Secret 내용 정확성 확인
- [ ] 토큰 만료 여부 확인
4단계: 시스템 리소스 확인
- [ ] 노드 디스크 공간 확인
- [ ] 메모리 사용량 확인
이번 글에서 다룬 내용들을 차근차근 따라하시면 대부분의 ErrImagePull 에러를 해결하실 수 있을 것입니다. 무엇보다 중요한 것은 에러 메시지를 꼼꼼히 읽고 체계적으로 접근하는 것입니다. 처음에는 복잡해 보일 수 있지만, 몇 번 경험해보시면 금방 익숙해지실 거예요.