Published on

EKS Pod ImagePullBackOff 401 해결 가이드

Authors

서버리스가 아닌 이상, EKS에서 ImagePullBackOff는 대부분 노드(kubelet)가 이미지를 못 받아오는 문제입니다. 그중 401 Unauthorized는 특히 “네트워크가 아니라 인증”에 초점이 맞춰져야 합니다. 하지만 EKS에서는 인증 주체가 Pod가 아니라 노드의 kubelet/컨테이너 런타임(containerd) 인 경우가 많아, IRSA를 붙여도 해결되지 않는 일이 흔합니다.

이 글에서는 EKS에서 ImagePullBackOff + 401이 발생할 때 원인을 ECR vs 사설 레지스트리, 노드 IAM vs imagePullSecrets, 토큰 만료/스코프, 프라이빗 엔드포인트/리전 불일치 관점으로 빠르게 쪼개어 해결하는 체크리스트를 정리합니다.

관련해서 노드/클러스터 레벨 장애를 함께 점검해야 한다면 Terraform apply 후 EKS 노드 NotReady - CNI·IRSA·보안그룹 점검도 같이 보면 진단 속도가 빨라집니다.

1) 증상 확정: “정말 401인가?” 이벤트부터 본다

먼저 Pod 이벤트에서 정확히 어떤 레지스트리로, 어떤 이유로 실패했는지 확인합니다.

kubectl describe pod -n <ns> <pod>

아래처럼 이벤트에 401 또는 unauthorized: authentication required가 찍히는지 확인합니다.

  • Failed to pull image "...": rpc error: code = Unknown desc = ... 401 Unauthorized
  • pull access denied, repository does not exist or may require authorization

여기서 중요한 포인트:

  • ErrImagePull → 단발성 실패
  • ImagePullBackOff → 재시도 백오프로 굳어진 상태(원인 해결 전까지 계속)

원인 분리를 위해 이미지 URL을 먼저 분류합니다.

  • ECR 예: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:tag
  • Docker Hub 예: docker.io/library/nginx:latest
  • 사설(하버/깃랩) 예: registry.example.com/team/myapp:tag

2) 핵심 개념: EKS에서 이미지 풀 인증 주체는 보통 “노드”다

많이 헷갈리는 지점이 여기입니다.

  • IRSA(ServiceAccount IAM Role): Pod 안에서 AWS API를 호출할 때 사용(예: S3, DynamoDB)
  • 이미지 Pull: 기본적으로 노드의 kubelet/containerd가 수행

즉, “Pod에 IRSA를 붙였는데도 ECR Pull이 401”이라면, 대개 IRSA는 상관이 없고 노드 IAM Role 또는 imagePullSecrets 문제일 가능성이 큽니다.

3) 케이스 A: ECR에서 401이 나는 경우(가장 흔함)

3.1 노드 IAM Role에 ECR Pull 권한이 없다

EKS Managed Node Group/자체 노드의 IAM Role에 최소 아래 권한이 필요합니다.

  • ecr:GetAuthorizationToken
  • ecr:BatchGetImage
  • ecr:GetDownloadUrlForLayer
  • ecr:BatchCheckLayerAvailability

AWS 관리형 정책으로는 보통 다음을 붙입니다.

  • AmazonEC2ContainerRegistryReadOnly

확인은 노드가 사용하는 인스턴스 프로파일/역할을 확인해야 합니다.

kubectl get node -o wide
# 노드 이름으로 EC2 인스턴스 식별 후 IAM Role 확인

노드 Role이 잘못 붙었거나(다른 Role), 정책이 누락되면 kubelet이 ECR 토큰을 못 받아 401이 납니다.

3.2 ECR 리전 불일치 또는 레지스트리 도메인 오타

ECR은 리전별 엔드포인트가 다릅니다.

  • ap-northeast-2에 있는 레포를 us-east-1 도메인으로 당기면 인증/요청이 꼬입니다.
  • 계정 ID 오타도 401/404를 유발합니다.

체크:

aws ecr describe-repositories --region ap-northeast-2 --repository-names myapp

이미지 참조가 정확한지(계정/리전/레포명) 다시 확인합니다.

3.3 ECR Private Endpoint/프록시 환경에서 토큰 교환이 실패

프라이빗 서브넷 + VPC 엔드포인트 구성이면 다음이 필요합니다.

  • com.amazonaws.<region>.ecr.api
  • com.amazonaws.<region>.ecr.dkr
  • (이미지 레이어는 S3를 통해 내려받는 경우가 많아) com.amazonaws.<region>.s3 게이트웨이 엔드포인트 또는 NAT 경로

이게 없으면 보통은 타임아웃이 더 흔하지만, 환경에 따라 인증 단계가 실패로 보일 수도 있습니다. 네트워크/DNS 이슈가 의심되면 CoreDNS/노드 DNS도 함께 확인하세요. (DNS 계열 장애는 AWS EKS CoreDNS CrashLoopBackOff와 DNS 타임아웃 해결 같은 케이스로 이어질 수 있습니다.)

4) 케이스 B: 사설 레지스트리에서 401이 나는 경우

사설 레지스트리(하버/깃랩/자체 registry)에서 401은 거의 항상 Kubernetes pull secret 또는 자격증명 스코프 문제입니다.

4.1 imagePullSecrets가 없거나, 네임스페이스가 다르다

imagePullSecrets네임스페이스 단위 리소스입니다.

  • secret을 default에 만들고
  • Pod는 prod 네임스페이스에서 실행하면

Pod는 secret을 못 보고 401이 납니다.

확인:

kubectl get secret -n <ns>
kubectl describe pod -n <ns> <pod> | sed -n '/Image Pull Secrets/,$p'

4.2 docker-registry 타입 secret 생성/갱신

가장 안전한 방식은 kubernetes.io/dockerconfigjson 타입으로 만드는 것입니다.

kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username='<USER>' \
  --docker-password='<PASSWORD_OR_TOKEN>' \
  --docker-email='devnull@example.com' \
  -n <ns>

그리고 Deployment/Pod spec에 연결합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      imagePullSecrets:
        - name: regcred
      containers:
        - name: myapp
          image: registry.example.com/team/myapp:1.0.0

이미 존재하는 ServiceAccount에 기본 pull secret을 붙여서, 해당 SA를 쓰는 모든 Pod에 적용할 수도 있습니다.

kubectl patch serviceaccount default -n prod \
  -p '{"imagePullSecrets": [{"name": "regcred"}]}'

4.3 토큰/패스워드 만료 또는 2FA로 인한 실패

GitLab/Harbor/Docker Hub는 “비밀번호” 대신 Personal Access Token을 요구하거나, 2FA 활성화 시 비밀번호 로그인이 막힙니다.

증상은 동일하게 401로 떨어지므로, 아래를 확인하세요.

  • 토큰 만료 여부
  • 토큰 scope: read_registry(GitLab), pull 권한 등
  • 레포/프로젝트 접근 권한(비공개 프로젝트)

secret을 갱신했다면 Pod를 재시작해 재풀을 유도합니다.

kubectl rollout restart deploy/myapp -n prod

5) “ECR인데 imagePullSecrets로 해결되던데?”에 대한 설명

ECR도 표준 Docker Registry API를 쓰기 때문에 docker login으로 발급한 토큰을 .dockerconfigjson로 넣어 풀 수는 있습니다. 하지만 ECR 토큰은 기본적으로 12시간 만료라 운영 환경에서 권장되지 않습니다.

대신 권장 패턴은:

  • 노드 IAM Role에 AmazonEC2ContainerRegistryReadOnly 부여
  • (가능하면) Managed Node Group 사용 시 기본 권한 확인

특정 워크로드만 별도 자격증명을 쓰고 싶다면, ECR credential provider(노드 구성) 또는 외부 컨트롤러를 고려해야 하지만, 우선은 “노드 Role로 풀게 한다”가 가장 단순하고 안정적입니다.

6) 컨테이너 런타임 관점: 노드에서 직접 재현해 원인 좁히기

노드에 SSM으로 접속 가능하다면(또는 디버그용 ephemeral container), containerd가 실제로 어떤 에러를 내는지 확인하면 빨라집니다.

6.1 kubelet/containerd 로그 확인

Amazon Linux 2 기반 EKS 노드라면 보통:

sudo journalctl -u kubelet -n 200 --no-pager
sudo journalctl -u containerd -n 200 --no-pager

여기서 401이 반복되면 “Pod spec” 문제가 아니라 “노드 인증/설정” 문제일 확률이 큽니다.

6.2 이미지 풀을 노드에서 직접 시도

환경에 따라 crictl이 있을 수 있습니다.

sudo crictl pull 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:tag
  • 여기서도 401이면 노드 IAM/ECR endpoint 문제
  • 여기서는 성공하고 Pod만 실패하면 imagePullSecrets/SA/네임스페이스/이미지명 문제 가능성이 큼

7) 자주 하는 실수 Top 7 체크리스트

  1. IRSA로 이미지 풀을 해결하려고 함 → 대개 노드 IAM 문제
  2. secret을 다른 네임스페이스에 생성
  3. --docker-server 값 불일치 (예: https://registry... 붙이거나, 포트 포함 누락)
  4. ECR 리전/계정 ID 오타
  5. 토큰 만료(GitLab PAT/ECR 12h 토큰)
  6. 레포 권한 없음(private repo)
  7. VPC 엔드포인트/S3 경로 누락(프라이빗 클러스터)

8) 문제 해결 후 검증 절차

  1. 기존 실패 Pod를 지우거나 롤아웃 재시작
kubectl delete pod -n <ns> <pod>
# 또는
kubectl rollout restart deploy/<deploy> -n <ns>
  1. 새 Pod 이벤트에서 Pulled / Created / Started 확인
kubectl get pod -n <ns> -w
kubectl describe pod -n <ns> <new-pod>
  1. 동일 노드에서만 실패한다면 노드 단위 캐시/설정 문제일 수 있으니, 노드 교체/드레인으로 재현성 확인
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data

9) 결론: 401은 “인증 주체”를 먼저 고정하면 빨리 끝난다

EKS에서 ImagePullBackOff (401)는 원인이 다양해 보이지만, 실제로는 아래 두 갈래로 정리됩니다.

  • ECR: 노드 IAM Role + ECR 리전/엔드포인트(그리고 S3 경로)
  • 사설 레지스트리: imagePullSecrets(네임스페이스/서버값/토큰 스코프)

진단의 출발점은 항상 kubectl describe pod 이벤트이며, “누가(노드 vs Pod) 인증하는가”를 먼저 확정하면 불필요한 IRSA/권한 삽질을 크게 줄일 수 있습니다.

추가로 EKS에서 노드 레벨 이슈가 동반되는 경우(노드가 꼬여서 kubelet이 이상 동작, NotReady 등)에는 EKS에서 kubelet node not found 오류 해결도 함께 점검하면 전체 장애 범위를 더 빨리 좁힐 수 있습니다.