"AWS 에 그 이미지가 있는지" 를 확인하려면 먼저 무엇을 찾는지부터 갈라야 한다. EC2 를 띄우는 머신 이미지(AMI) 와 컨테이너 이미지를 담는 ECR 저장소는 전혀 다른 API 를 쓴다. 이어서 이미 클러스터에서 돌고 있는 파드의 이미지를 사내 레지스트리로 옮기는 방법을 정리한다.
aws ec2 describe-images --owners self --region ap-northeast-2
aws ec2 describe-images --owners self --filters "Name=name,Values=*my-custom-ami*"
aws ec2 describe-images --image-ids ami-0abcd1234efgh5678 --region ap-northeast-2
--owners 에 self · amazon · aws-marketplace 를 넣어 소유자를 좁힌다. AMI 는 리전마다 ID 가 다르므로 다른 리전에서 본 ID 를 그대로 쓸 수 없다. 공식 이미지는 SSM 파라미터 스토어로 찾는 쪽이 안정적이다.
aws ssm get-parameters-by-path \
--path /aws/service/ami-amazon-linux-latest --region ap-northeast-2 \
--query 'Parameters[].Name'
aws ecr describe-repositories --region ap-northeast-2
aws ecr describe-repositories --region ap-northeast-2 \
--query "repositories[?repositoryName=='busybox']"
aws ecr list-images --repository-name busybox --region ap-northeast-2
list-images 가 imageIds 배열을 돌려주면 그 저장소에 이미지가 있다는 뜻이다. 태그만 뽑거나 특정 태그 유무만 보려면 아래처럼 한다.
aws ecr list-images --repository-name busybox --region ap-northeast-2 \
--filter tagStatus=TAGGED --query 'imageIds[].imageTag' --output text
aws ecr describe-images --repository-name busybox --region ap-northeast-2 \
--query 'imageDetails[].{tags:imageTags,digest:imageDigest,pushedAt:imagePushedAt,size:imageSizeInBytes}'
aws ecr describe-images --repository-name busybox --region ap-northeast-2 \
--query 'reverse(sort_by(imageDetails,&imagePushedAt))[:1].[imageTags[0],imageDigest,imagePushedAt]' \
--output text
로그인과 pull.
URI=$(aws ecr describe-repositories --repository-names busybox --region ap-northeast-2 \
--query 'repositories[0].repositoryUri' --output text)
aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin "$URI"
docker pull "$URI:latest"
get-login-password 가 내보내는 토큰은 12시간짜리 임시 비밀번호다. 스크립트에 적어 두지 말고 매번 생성한다. 사설 ECR 이 아니라 공개 이미지를 찾는 것이라면 ECR Public Gallery(https://gallery.ecr.aws/) 를 본다.
먼저 파드가 실제로 쓰는 레퍼런스를 확인한다.
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.containers[*].image}{"\n"}'
kubectl get pod <POD> -n <NS> -o jsonpath='{.status.containerStatuses[*].imageID}{"\n"}'
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.nodeName}{"\n"}'
spec.containers[].image 는 매니페스트에 적힌 이름이고, status.containerStatuses[].imageID 는 실제로 내려받힌 다이제스트다. latest 태그를 쓰는 환경에서는 둘이 가리키는 대상이 다를 수 있으므로 다이제스트를 기준으로 삼는다.
원본 레지스트리에 닿을 수 있다면 노드에 들어갈 필요가 없다. 레이어를 그대로 옮기므로 다이제스트가 보존된다.
PASS=$(aws ecr get-login-password --region ap-northeast-2)
skopeo copy \
docker://busybox:1.36 \
docker://<ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/busybox:1.36 \
--dest-creds "AWS:${PASS}"
crane 도 같은 일을 한다. 도커 로그인 상태를 그대로 쓴다.
crane cp busybox:1.36 <ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/busybox:1.36
원본이 사설 레지스트리라면 파드가 쓰는 imagePullSecrets 에서 자격증명을 꺼내 쓴다.
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.imagePullSecrets[*].name}{"\n"}'
kubectl get secret <SECRET> -n <NS> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d > /tmp/auth.json
skopeo copy --src-authfile /tmp/auth.json docker://<SRC> docker://<DST>
/tmp/auth.json 에는 레지스트리 비밀번호가 평문으로 들어 있다. 작업이 끝나면 지운다.
원본 레지스트리에 닿을 수 없고 노드 캐시에만 있는 경우다. 런타임에 따라 명령이 다르다.
containerd — 쿠버네티스 이미지는 k8s.io 네임스페이스에 있다.
sudo ctr -n k8s.io images ls | grep busybox
sudo ctr -n k8s.io images export /tmp/busybox.tar docker.io/library/busybox:1.36
# nerdctl 이 있으면
sudo nerdctl -n k8s.io save -o /tmp/busybox.tar busybox:1.36
CRI-O.
sudo podman images | grep busybox
sudo podman save --format docker-archive -o /tmp/busybox.tar busybox:1.36
sudo skopeo copy containers-storage:busybox:1.36 docker-archive:/tmp/busybox.tar
도커.
docker save -o busybox.tar busybox:1.36
docker save -o base-images.tar alpine:3.20 busybox:1.36 ubuntu:22.04
docker save busybox:1.36 | gzip > busybox.tar.gz
docker load -i busybox.tar
gzip -dc busybox.tar.gz | docker load
꺼낸 tar 를 ECR 로 올린다.
docker load -i /tmp/busybox.tar
docker tag busybox:1.36 <ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/busybox:1.36
aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com
docker push <ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/busybox:1.36
aws ecr create-repository --repository-name busybox 로 먼저 만든다.docker save · ctr images export 는 노드에 캐시된 아키텍처 하나만 담는다. 멀티 아키텍처 매니페스트가 필요하면 skopeo copy --all 이나 crane cp 로 레지스트리 간 복사를 쓴다.ctr 로 export 할 때는 ctr -n k8s.io images ls 가 출력하는 정식 레퍼런스(docker.io/library/...) 를 그대로 써야 한다. 짧은 이름은 찾지 못한다.