로컬에서 빌드한 애플리케이션 이미지를 Minikube 쿠버네티스에 올려 보는 중이었다. Deployment와 Service를 적은 yaml을 kubectl apply 하자 Pod 상태가 ErrImagePull로 떨어졌다. docker images로 보면 이미지는 분명 로컬에 있었다.

같은 에러를 두 번 만났고, 원인은 두 번 다 달랐다. 이 글은 그 두 가지 기록이다.

환경

  • Mac Apple Silicon

  • Minikube로 구성한 K8S

  • 로컬에서 빌드한 애플리케이션과 Docker 이미지를 K8S로 배포 테스트

첫 번째: Minikube는 내 Docker 데몬을 보지 않는다

에러 메시지는 이랬다.

pull access denied for cms, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

원인은 간단했다. Minikube 안의 쿠버네티스는 내 로컬 Docker에 있는 이미지를 보지 못한다. Minikube 노드는 자기 Docker 데몬을 따로 갖고 있다. 로컬 데몬에 있는 cms 이미지는 그쪽에서 보면 없는 이미지이고, 없으니 레지스트리에서 받으려다 실패한 것이다.

그래서 Minikube와 내 Docker 호스트를 연결했다.

eval $(minikube -p minikube docker-env)

minikube docker-env는 DOCKER_HOST 같은 환경 변수를 출력하고, eval이 그걸 현재 쉘에 적용한다. 이후 이 쉘의 docker 명령은 Minikube 안의 데몬을 향하므로, 이 상태에서 이미지를 빌드해야 Minikube 쪽에 이미지가 생긴다. 환경 변수라서 터미널을 새로 열면 다시 실행해야 한다.

두 번째: 이름이 cms 하나뿐인 이미지

이어서 Vue 프론트엔드 애플리케이션도 배포해야 했다. 앞에서 한 번 당해서 조심하고 있었는데도 또 이미지 pull 에러가 났다.

docker: error response from daemon: pull access denied for...

이번에는 docker login이 되어 있는데도 로그인을 요구했다. 여기서 두 번째 문제를 알게 됐다. 이미지 이름이 {사용자명}/{이미지명} 형식이 아니라 그냥 {이미지명}이었다.

Docker Hub에서 받을 이미지도 아니었고 로컬 이미지만 쓰면 됐기 때문에 이름 형식이 문제가 될 줄은 몰랐다. 이미지 이름이 {사용자명}/{이미지명}이 되도록 관련 부분을 모두 고쳐 적용하자 해결됐다.

돌아보면 에러 메시지에 힌트가 있었다. 레지스트리와 네임스페이스 없이 cms만 쓰면 Docker는 이를 docker.io/library/cms, 즉 Docker Hub 공식 이미지 자리로 해석한다. 그런 저장소는 없으니 “repository does not exist or may require ‘docker login’“이 나온다. 로그인 여부와는 상관없는 메시지였다.

🤔
태그가 없거나 :latest면 imagePullPolicy 기본값이 Always라서, 로컬에 이미지가 있어도 매번 레지스트리에서 받으려한다는 내용이 있다. 이름 변경만으로 풀린 이유는 이쪽일 수도 있다.