노드 그룹을 늘렸는데 새로 붙은 노드에서만 파드가 ImagePullBackOff 로 남는다. 노드를 여러 서브넷에 걸쳐 두었다면 특정 서브넷에 뜬 노드만 실패하는 형태로 나타난다. 이 경우 원인은 이미지나 권한이 아니라 그 서브넷의 경로다.
ECR 에서 이미지를 받는 과정은 한 번의 통신이 아니다. 인증 토큰과 매니페스트는 ECR API 로 받고, 실제 레이어는 S3 에서 내려받는다. private 서브넷에서 인터넷 경로가 없다면 둘 다 따로 열어 주어야 한다.
| 필요한 것 | 엔드포인트 | 형태 |
|---|---|---|
| ECR 인증·API | com.amazonaws.<region>.ecr.api |
Interface |
| 이미지 매니페스트·레이어 요청 | com.amazonaws.<region>.ecr.dkr |
Interface |
| 레이어 본체 | com.amazonaws.<region>.s3 |
Gateway (또는 Interface) |
Interface 엔드포인트는 프라이빗 DNS 사용을 켜야 한다. 켜지 않으면 노드가 <account>.dkr.ecr.<region>.amazonaws.com 을 공인 IP 로 해석하고 다시 인터넷으로 나가려 한다. 엔드포인트의 보안 그룹은 노드 보안 그룹에서 오는 443 을 받아야 한다.
S3 를 Gateway 엔드포인트로 두었다면 엔드포인트가 아니라 라우팅 테이블에 경로가 들어간다. 서브넷이 연결된 라우팅 테이블에 해당 프리픽스 목록 경로가 있는지 확인한다.
두 서브넷의 차이를 위에서 아래로 훑는다. 대부분 첫 항목에서 끝난다.
# 1. Interface 엔드포인트가 그 서브넷에 ENI 를 두고 있는가
aws ec2 describe-vpc-endpoints \
--filters "Name=service-name,Values=com.amazonaws.ap-northeast-2.ecr.dkr" \
--query 'VpcEndpoints[].{Id:VpcEndpointId,Subnets:SubnetIds,PrivateDns:PrivateDnsEnabled}'
# 2. 서브넷이 어떤 라우팅 테이블에 붙어 있는가
aws ec2 describe-route-tables \
--filters "Name=association.subnet-id,Values=<SUBNET_ID>" \
--query 'RouteTables[].Routes'
# 3. 네트워크 ACL 이 다른가
aws ec2 describe-network-acls \
--filters "Name=association.subnet-id,Values=<SUBNET_ID>"
Interface 엔드포인트는 선택한 서브넷마다 ENI 를 하나씩 만든다. 나중에 추가한 서브넷을 엔드포인트에 넣지 않으면 그 서브넷의 노드만 이름 해석은 되는데 연결이 안 되는 상태가 된다.
# 엔드포인트의 사설 IP 로 해석되는가
nslookup <ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com
# 443 이 열리는가
curl -sv -o /dev/null https://<ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/v2/ 2>&1 | tail -5
# 토큰을 받아 직접 받아 본다
aws ecr get-login-password --region ap-northeast-2 \
| sudo ctr -n k8s.io image pull --user AWS:$(cat -) \
<ACCOUNT_ID>.dkr.ecr.ap-northeast-2.amazonaws.com/<REPO>:<TAG>
nslookup 결과가 공인 IP 면 프라이빗 DNS 가 꺼져 있는 것이고, 사설 IP 인데 curl 이 걸리면 보안 그룹이다. 토큰 발급 단계에서 막히면 권한 문제다.
노드 그룹의 인스턴스 역할에 ECR 읽기 권한이 있어야 한다. 관리형 정책 AmazonEC2ContainerRegistryReadOnly 를 붙이는 것이 표준이다. 직접 정책을 쓸 때 필요한 동작은 다음과 같다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "*"
}
]
}
권한 문제라면 서브넷과 무관하게 모든 노드가 똑같이 실패한다. 일부 노드만 실패한다면 권한은 원인이 아니다.
인터넷 경로를 열어 두었다면 VPC 엔드포인트 없이도 동작한다. 다만 이미지 레이어가 NAT 를 통과하므로 데이터 처리 요금이 붙는다. 이미지가 큰 환경에서는 엔드포인트 쪽이 싸다. NAT 를 쓰기로 했다면 서브넷의 라우팅 테이블에 0.0.0.0/0 → NAT Gateway 가 있는지, 그리고 그 NAT 가 해당 가용 영역에 있는지를 본다.