ArgoCD로 로컬 Minikube 클러스터에 앱이 배포되도록 구성해 두었고, 여기까지는 Docker Hub의 public 이미지를 받아 쓰고 있었다. 이미지를 AWS ECR로 옮기자 Pod가 뜨지 않았다.

⚠️
Error message Failed to pull image “{AWS Account ID}.dkr.ecr.ap-northeast-2.amazonaws.com/saas:tag-09ce85b761470bd32785e3285b1bee91eaed1fc5”: Error response from daemon: Head “https://{AWS Account ID}.dkr.ecr.ap-northeast-2.amazonaws.com/v2/saas/manifests/tag-09ce85b761470bd32785e3285b1bee91eaed1fc5”: no basic auth credentials

no basic auth credentials, 인증 정보가 없다는 말이다. public 이미지는 인증 없이 받을 수 있지만 ECR은 private 레지스트리라서 받는 쪽이 자격증명을 들고 가야 한다. 이 글에서는 그 자격증명을 누가 들고 있어야 했는지, 처음 시도는 왜 소용없었는지 정리한다.

공식 문서의 docker login으로는 바뀌지 않았다

AWS 공식 문서가 안내하는 ECR 로그인 명령은 이렇다.

aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin {AWS Account ID}.dkr.ecr.ap-northeast-2.amazonaws.com

이 명령을 써도 에러 내용은 그대로였다. 처음 찾은 방법은 이 명령으로 ~/.docker/config.json에 자격증명이 기록되니, 그 파일로 Kubernetes Secret을 만들라는 것이었다. 파일에는 새로 기록된 내용 자체가 없었다.

돌아보면 두 가지를 섞어 보고 있었다. docker login은 내 터미널의 Docker에 로그인하는 것이지 Minikube에 로그인하는 것이 아니다. 이미지를 받는 주체는 Minikube 노드 안의 컨테이너 런타임이고, 그쪽은 로컬 터미널의 로그인 상태를 모른다. Kubernetes에서 private 레지스트리 자격증명은 docker-registry 타입 Secret으로 클러스터 안에 넣고 Pod가 그 Secret을 참조하게 해야 한다.

graph LR
  A[로컬 터미널 docker login] -.->|전달되지 않음| C[Minikube 노드]
  S[Secret ecr-registry] -->|imagePullSecrets| C
  B[ArgoCD] -->|Deployment 적용| C
  C -->|이미지 pull| E[AWS ECR]

파일에 내용이 비어 있던 이유는 확인하지 못했다. Docker Desktop처럼 자격증명을 config.json 대신 OS 키체인에 넣는 credential store를 쓰면 파일에는 인증 정보가 남지 않는데, 그 경우였을 수 있다.

docker-registry Secret을 직접 만들었다

두 번째로 찾은 방법도 Secret을 만드는 것은 같지만, 파일을 거치지 않고 바로 만든다.

kubectl create secret docker-registry ecr-registry \
    --docker-server=https://{AWS Account ID}.dkr.ecr.ap-northeast-2.amazonaws.com \
    --docker-username=AWS \
    --docker-password=$(aws ecr get-login-password) \
    --docker-email={Email정보}

# 시크릿 생성 확인
kubectl get secret

# Deployment 재시작
  • kubectl create secret docker-registry: 레지스트리 자격증명을 Kubernetes Secret으로 만든다.

  • --docker-server: ECR 레지스트리의 베이스 URL만 넣는다. 개별 이미지 이름이나 레포지토리 경로(/saas 같은)는 붙이지 않는다.

  • --docker-username=AWS: ECR 토큰 인증의 사용자 이름은 항상 AWS다.

  • --docker-password=$(aws ecr get-login-password): 서브쉘로 ECR 로그인 패스워드를 받아 바로 넘긴다. 파일에 기록될 필요가 없어서 앞의 문제를 피해 간다.

  • --docker-email: 사용자 이메일 주소. Secret 생성에 꼭 필요하지는 않지만 오류를 피하려고 넣을 수 있다.

Secret을 만든 뒤 Deployment를 재시작하자 이미지를 받아 왔다.

이 Secret은 12시간 뒤에 만료된다

aws ecr get-login-password가 돌려주는 토큰은 12시간 동안만 유효하다. Secret 안의 비밀번호도 그 토큰이라서, 시간이 지나 Pod가 다시 이미지를 받아야 할 때 같은 에러가 다시 날 수 있다. 로컬 실습이라면 그때 Secret을 다시 만들면 되지만, 오래 두는 클러스터라면 토큰 갱신을 자동화할 방법을 따로 찾아야 한다. 이건 다음에 다시 봐야겠다.