Azure Container Registry의 내부 저장 구조를 이해하고, Soft Delete 함정을 피해 효율적으로 비용을 관리하는 방법
들어가며
CI/CD 파이프라인을 운영하다 보면 Container Registry에 이미지가 계속 쌓입니다. "일단 빌드 잘 되니까"라고 방치하면, 어느 날 스토리지 비용이 예상보다 높거나, 이미지를 삭제하려는데 CLI가 "성공"이라 하면서 실제로는 삭제되지 않는 황당한 상황을 마주할 수 있습니다.
이 글에서는 Azure Container Registry(ACR)를 운영하면서 겪은 실제 경험을 바탕으로:
- ACR이 이미지를 어떤 구조로 저장하는지
- *레이어 공유(Layer Deduplication)**가 어떻게 작동하는지
- Soft Delete 기능이 삭제 작업에 미치는 영향
- SKU별 비용 구조와 최적화 방법
- AWS ECR과 비교한 이미지 Lifecycle 관리의 차이
을 실제 데이터와 함께 정리합니다.
1. ACR의 저장 구조 — 이미지가 아닌 "레이어"로 저장된다
1.1 3계층 아키텍처
ACR은 컨테이너 이미지를 통째로 저장하지 않습니다. OCI(Open Container Initiative) 표준에 따라 3계층 구조로 저장합니다:
Registry (myregistry.azurecr.io)
│
├── Repository (myapp-worker-common)
│ ├── Manifest (sha256:f880...) ← 태그 5061, latest가 가리킴
│ ├── Manifest (sha256:771f...) ← 태그 5056이 가리킴
│ └── ...
│
├── Repository (myapp-worker-batch)
│ ├── Manifest (sha256:ab12...) ← 태그 5061이 가리킴
│ └── ...
│
└── Blob Store (레이어 저장소) ← 레지스트리 전체에서 공유
├── sha256:7128a8... (31MB) — Base OS layer
├── sha256:8715c0... (15MB) — Runtime dependencies
├── sha256:952b1b... (31MB) — Framework libraries
├── sha256:fab378... (10MB) — App code (worker-common:5061)
├── sha256:6c6d03... (10MB) — App code (worker-batch:5061)
└── ...
- Registry: 최상위 컨테이너. SKU, 리전, 접근 정책을 관리
- Repository: 이미지의 논리적 그룹. docker push myregistry.azurecr.io/myapp:v1에서 myapp이 리포지토리
- Manifest: 이미지의 "레시피". 어떤 레이어 blob들로 구성되는지 digest 목록을 포함
- Blob Store: 실제 레이어 데이터가 저장되는 곳. 리포지토리 경계를 넘어 레지스트리 전체에서 공유
1.2 Manifest란?
Manifest는 이미지를 구성하는 레이어들의 참조 목록입니다. 태그(5061, latest)는 특정 manifest를 가리키는 포인터에 불과합니다.
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": { "digest": "sha256:..." },
"layers": [
{ "digest": "sha256:7128a8...", "size": 31443735 },
{ "digest": "sha256:8715c0...", "size": 14966550 },
{ "digest": "sha256:952b1b...", "size": 31651232 },
{ "digest": "sha256:78f394...", "size": 154 },
{ "digest": "sha256:c91769...", "size": 93 },
{ "digest": "sha256:4f4fb7...", "size": 32 },
{ "digest": "sha256:fab378...", "size": 9997779 }
]
}
- 두 태그가 같은 manifest digest를 가리키면 → 완전히 동일한 이미지 (예: 5061과 latest)
- 두 태그가 다른 manifest를 가리켜도 → 내부 레이어는 공유될 수 있음
2. 레이어 공유 — 실제 데이터로 증명
2.1 같은 리포지토리 내 태그 간 공유
worker-common 리포지토리에서 태그 5061과 5056의 레이어를 비교한 실제 데이터입니다:
=== worker-common:5061 ===
sha256:7128a879... 31,443,735 (31MB) ← Base OS
sha256:8715c03a... 14,966,550 (15MB) ← Runtime
sha256:952b1bd0... 31,651,232 (31MB) ← Framework
sha256:78f394ff... 154 ← Config
sha256:c91769d3... 93 ← Env
sha256:af490c76... 3,921 ← Metadata
sha256:4f4fb700... 32 ← Entrypoint
sha256:fab378aa... 9,997,779 (10MB) ← App code
=== worker-common:5056 ===
sha256:7128a879... 31,443,735 (31MB) ← 동일 ✅
sha256:8715c03a... 14,966,550 (15MB) ← 동일 ✅
sha256:952b1bd0... 31,651,232 (31MB) ← 동일 ✅
sha256:78f394ff... 154 ← 동일 ✅
sha256:7e55d592... 93 ← 다름 ❌
sha256:63330f00... 3,923 ← 다름 ❌
sha256:4f4fb700... 32 ← 동일 ✅
sha256:3202da71... 9,997,503 (10MB) ← 다름 ❌
8개 레이어 중 5개가 완전히 동일한 digest → Blob Store에 1번만 저장됨
이미지 크기는 각각 ~88MB이지만, 실제 추가 스토리지는 다른 3개 레이어(~10MB)만큼만 필요합니다.
2.2 리포지토리 간 공유 (핵심!)
3개 리포지토리에서 같은 태그(5061)의 레이어를 비교한 데이터입니다:
| Layer (digest 앞 8자리) | Size | worker-common | worker-batch | worker-scheduler | 공유? |
| 7128a879 | 31MB | O | O | O | 3개 모두 공유 |
| 8715c03a | 15MB | O | O | O | 3개 모두 공유 |
| 952b1bd0 | 31MB | O | O | O | 3개 모두 공유 |
| 78f394ff | 154B | O | O | O | 3개 모두 공유 |
| c91769d3 | 93B | O | O | O | 3개 모두 공유 |
| 4f4fb700 | 32B | O | O | O | 3개 모두 공유 |
| App code | ~10MB | fab378 | 6c6d03 | 909297 | 각각 다름 |
7개 레이어 중 6개가 3개 리포지토리 모두에서 동일 → ACR Blob Store에 1번만 저장
3개 리포지토리 × 88MB = 264MB가 아닌, 약 78MB(공유 레이어) + 30MB(3개 고유 App 레이어) = ~108MB만 실제 저장됩니다.
2.3 이것이 가능한 이유: Content-Addressable Storage
각 레이어는 내용의 SHA256 해시가 곧 식별자입니다. 동일한 base image(mcr.microsoft.com/dotnet/runtime:8.0 등)를 사용하는 이미지는 동일한 레이어 digest를 가지므로, ACR은 리포지토리 경계를 넘어서 중복을 자동으로 제거합니다.
단순 합산: 314개 이미지 × 88MB = ~27 GiB
실제 ACR 사용량: 2.18 GiB
절감율: ~92%
Blob Store는 Docker Distribution (OCI Distribution Spec) 구현이며, Azure Portal에서는 직접 볼 수 없습니다. 레이어 정보는 CLI(az acr manifest show)로만 확인 가능합니다.
2.4 레이어 공유가 깨지는 경우
# Case 1: Base image 버전 변경
FROM mcr.microsoft.com/dotnet/runtime:8.0 # → 8.1로 변경하면
# 모든 하위 레이어가 새로 생성됨 (digest 전부 변경)
# Case 2: 중간 레이어 변경
COPY packages.json . # 이 레이어가 바뀌면
RUN npm install # 이후 모든 레이어도 재생성
COPY src/ . # (Docker layer cache 무효화)
Dockerfile 최적화 팁: 변경 빈도가 낮은 레이어를 위에, 자주 바뀌는 앱 코드를 아래에 배치
# 권장 구조
FROM base-image # 거의 안 바뀜 → 공유 극대화
COPY dependencies . # 가끔 바뀜
RUN install-deps
COPY app-code . # 매 빌드마다 바뀜 → 이 레이어만 추가 저장
2.5 삭제 시 레이어 공유의 영향
이미지를 삭제하면 해당 manifest와 다른 이미지가 참조하지 않는 고유 레이어만 삭제됩니다:
태그 5061: [Layer A] [Layer B] [App v5061] ← 삭제 요청
태그 5056: [Layer A] [Layer B] [App v5056]
결과:
- Layer A: 5056이 아직 참조 중 → 삭제 안 됨
- Layer B: 5056이 아직 참조 중 → 삭제 안 됨
- App v5061: 5061만 참조하던 레이어 → 삭제됨 (~10MB만 회수)
314개 이미지 중 ~250개를 삭제해도 스토리지가 27 GiB 줄어드는 게 아니라, 고유 앱 레이어만큼만 줄어드는 이유입니다.
3. ACR SKU별 비용 구조
3.1 기본 요금
| 항목 | Basic | Standard | Premium |
| 월별 요금 (USD) | ~$5/month | ~$20/month | ~$50/month |
| 포함 스토리지 | 10 GiB | 100 GiB | 500 GiB |
| 스토리지 한도 | 40 TiB | 40 TiB | 100 TiB |
| Webhooks | 2 | 10 | 500 |
| Geo-Replication | - | - | O |
| Private Link | - | - | O |
| Retention Policy | - | - | O (Preview) |
요금은 리전에 따라 다를 수 있으며, Azure Pricing Calculator에서 리전 선택 후 확인 필요
3.2 포함 스토리지 초과 시
포함 스토리지를 초과하면 일별(per day) 단위로 추가 과금됩니다:
| SKU | 포함 | 스토리지 초과 비용 |
| Basic | 10 GiB | ~$0.003/GiB/day |
| Standard | 100 GiB | ~$0.003/GiB/day |
| Premium | 500 GiB | ~$0.003/GiB/day |
비용 시뮬레이션:
시나리오: Standard SKU에서 250 GiB 사용
기본 요금: ~$20/month
초과 스토리지: 250 - 100 = 150 GiB 초과
추가 비용: 150 GiB × $0.003/GiB/day × 30일 = ~$13.50/month
─────────────────────────────────────────
월 총 비용: ~$33.50/month
이미지 정리로 80 GiB로 줄인 경우:
기본 요금: ~$20/month
추가 비용: $0 (100 GiB 이내)
─────────────────────────────────────────
월 총 비용: ~$20/month
연간 절감: ~$162/year
3.3 네트워크/대역폭 비용
| 구간 | 비용 |
| 인바운드 (Push) | 무료 |
| 같은 리전 내 Pull | 무료 |
| 다른 리전 Pull | ~$0.02/GB |
| 인터넷 Egress | 첫 100 GB/month 무료, 이후 ~$0.087/GB |
같은 리전의 App Service나 AKS에서 Pull하는 경우 대역폭 비용은 발생하지 않습니다.
3.4 실제 사례
실제 운영 중인 ACR 레지스트리의 상태입니다:
| 항목 | 값 |
| SKU | Basic |
| 리전 | Korea Central |
| 현재 사용량 | 2.18 GiB / 10 GiB 포함 |
| 월 비용 | ~$5 (포함 스토리지 이내) |
| Soft Delete | enabled (retentionDays=7) |
Basic SKU에 포함된 10 GiB 이내이므로 추가 스토리지 비용은 없습니다. 하지만 이미지를 정리하지 않고 방치하면 스토리지가 누적되어 초과 비용이 발생할 수 있습니다.
4. 이미지 정리를 방치하면 생기는 일
4.1 스토리지 누적 패턴
CI/CD에서 매 빌드마다 새 이미지를 Push하면:
예시: 3개 리포지토리, 주 5회 빌드, 고유 App 레이어 평균 10MB
월간 추가량: 3 repos × 20 builds × 10 MB = 600 MB/month (레이어 공유 고려)
1년 누적: 600 MB × 12 = ~7 GB
Basic SKU (10 GiB 포함) 기준:
- 16개월 후: 포함 스토리지 초과 → 추가 비용 시작
레이어 공유 덕분에 실제 증가량은 이미지 크기 × 빌드 수보다 훨씬 적지만, 누적되면 문제가 됩니다.
4.2 비용 외 영향
| 영향 | 설명 |
| API 응답 지연 | 대량의 태그/매니페스트로 인한 목록 조회 속도 저하 |
| 관리 복잡성 | 어떤 이미지가 현재 운영 중인지 파악 어려움 |
| 보안 리스크 | 오래된 이미지에 알려진 취약점(CVE) 포함 가능 |
| 복구 시간 증가 | 필요한 이미지를 찾는 시간 증가 |
5. Soft Delete — 이미지 삭제의 숨겨진 함정
5.1 문제 상황
CLI로 이미지를 삭제했는데, Azure Portal에서 확인하면 이미지가 그대로 남아있었습니다:
$ az acr repository delete --name myregistry \\\\
--image "myapp-worker-common:497" --yes
# exit code 0 (성공!)
# 하지만 Portal에서 확인하면... 이미지가 그대로 있음
- exit code 0을 반환하므로 성공한 것처럼 보임
- show-tags API도 삭제한 태그를 계속 반환
- 90개 이미지를 루프로 삭제해도, 실제로는 1개만 삭제됨
5.2 원인: Soft Delete (Preview)
ACR에 Soft Delete가 enabled 상태이면, az acr repository delete는 이미지를 영구 삭제하지 않고 "soft-deleted" 상태로 전환만 합니다.
# Soft delete 상태 확인
$ az acr config soft-delete show --registry myregistry
# 결과: status=enabled, retentionDays=7
| 동작 | 설명 |
| CLI delete 실행 | API 요청 성공(200/202) → exit code 0 반환 |
| 실제 상태 | soft-deleted로 전환만 됨 |
| Portal 표시 | 이미지가 계속 보임 |
| show-tags API | soft-deleted 태그를 포함하여 반환 (stale 데이터) |
| 영구 삭제 시점 | 보존 기간(기본 7일) 만료 후 autopurge(24시간 주기) |
5.3 Soft Delete의 비용 영향
Soft-deleted artifacts are billed as per active SKU pricing for storage. — Microsoft 공식 문서
Soft-deleted 아티팩트도 보존 기간 동안 스토리지에 포함되어 과금됩니다. 이미지를 삭제해도 스토리지 사용량이 즉시 줄어들지 않습니다.
상황: 50 GiB의 이미지를 삭제했지만 soft delete enabled (retentionDays=7)
Day 0: 삭제 실행 → 스토리지 변화 없음 (soft-deleted로 전환만)
Day 1-6: soft-deleted 아티팩트가 계속 스토리지 과금
Day 7: autopurge에 의해 영구 삭제 시작
Day 8: 스토리지 사용량 반영 (최대 24시간 지연)
7일간 추가 비용: 50 GiB × $0.003/day × 7일 = $1.05
5.4 해결 방법: Soft Delete 비활성화 후 삭제
# 1. Soft delete 비활성화
az acr config soft-delete update --registry myregistry --status disabled
# 2. 이미지 삭제 (이제 영구 삭제됨)
az acr repository delete --name myregistry --image "repo:tag" --yes
# 3. 완료 후 Soft delete 재활성화
az acr config soft-delete update --registry myregistry --status enabled --days 7
5.5 추가 주의사항
- show-tags API는 stale 데이터 반환: soft-deleted 태그를 포함하여 반환하므로, 삭제 대상 목록을 만들 때 이 API를 반복 호출하면 이미 삭제된 태그가 계속 나옴
- az acr manifest delete(preview)는 비정상 동작: exit code 0을 반환하지만 실제 삭제하지 않음
- 삭제 대상 태그는 사전에 파일로 저장: manifest list-metadata에서 한 번 추출한 목록을 파일에 저장하여 사용
# 삭제 대상 태그 추출 (최근 10개 제외)
az acr manifest list-metadata myregistry.azurecr.io/<repository> \\\\
--query "reverse(sort_by([],&createdTime))[10:].{d:digest,t:tags[0]}" -o tsv | \\\\
awk '{print $2}' | grep -v "^$" > /tmp/tags_to_delete.txt
# 파일 기반으로 삭제
while IFS= read -r tag; do
az acr repository delete --name myregistry --image "<repository>:$tag" --yes
done < /tmp/tags_to_delete.txt
5.6 Soft Delete Preview 관련 알려진 문제
- Microsoft Q&A에서 보존 기간 만료 후에도 영구 삭제되지 않는 버그가 보고됨
- Soft Delete와 Retention Policy는 같은 레지스트리에서 동시 사용 불가
- Retention Policy는 Premium SKU에서만 사용 가능
6. ACR Blob Store — Portal에서 볼 수 없는 이유
Azure Portal의 ACR 섹션에서 볼 수 있는 것:
- Repositories → 리포지토리 목록
- Tags → 각 리포지토리의 태그 목록
- Manifests → manifest 목록과 메타데이터
하지만 Blob Store(레이어 저장소)는 Portal에 노출되지 않습니다. ACR은 내부적으로 OCI Distribution Specification을 구현하며, Blob Store는 이 구현의 내부 컴포넌트이기 때문입니다.
레이어 정보 확인은 CLI로만 가능합니다:
# 특정 이미지의 레이어 목록
az acr manifest show myregistry.azurecr.io/<repository>:<tag> \\\\
--query "layers[].{digest:digest, size:size}" -o table
# 전체 스토리지 사용량 (Blob Store 포함)
az acr show-usage --name myregistry -o table
az acr show-usage 결과에는 Blob Store의 총 사용량이 포함되어 있지만, 개별 blob을 나열하거나 어떤 blob이 어떤 이미지에서 참조되는지를 직접 확인하는 Portal UI는 없습니다.
7. 비용 최적화 Best Practice
7.1 자동 정리: ACR Purge Task (모든 SKU)
가장 권장되는 방법입니다. ACR Task로 스케줄링하여 자동 실행:
az acr task create \\\\
--name weeklyPurge \\\\
--registry myregistry \\\\
--cmd "acr purge \\\\
--filter 'myapp-worker-common:.*' \\\\
--filter 'myapp-worker-batch:.*' \\\\
--filter 'myapp-worker-scheduler:.*' \\\\
--ago 30d --keep 10 --untagged" \\\\
--schedule "0 1 * * Sun" \\\\
--context /dev/null
- -ago 30d: 30일 이상 된 이미지 대상
- -keep 10: 최신 10개 태그 유지
- -untagged: untagged manifest도 삭제
- -schedule: cron 표현식으로 주기 설정
- -dry-run: 실제 삭제 없이 미리보기 가능
7.2 Dockerfile 최적화
레이어 공유를 극대화하면 스토리지를 절약할 수 있습니다:
| 방법 | 효과 |
| 변경 빈도 낮은 레이어를 위에 배치 | 레이어 캐시 활용 극대화 |
| Multi-stage build | 빌드 도구가 최종 이미지에 포함되지 않음 |
| Alpine/Distroless base image | 이미지 크기 대폭 감소 |
| 동일한 base image 사용 | 리포지토리 간 레이어 공유 극대화 |
7.3 Soft Delete 보존 기간 최소화
# 7일 → 1일로 단축 (필요 시)
az acr config soft-delete update --registry myregistry --status enabled --days 1
보존 기간이 길수록 soft-deleted 아티팩트의 스토리지 비용이 누적됩니다.
7.4 정기 모니터링
# 스토리지 사용량 확인
az acr show-usage --name myregistry -o table
# 리포지토리별 매니페스트 수 확인
az acr manifest list-metadata myregistry.azurecr.io/<repository> --query "length(@)"
7.5 수동 정리 시 체크리스트
- az acr config soft-delete show --registry myregistry → Soft Delete 상태 확인
- Soft Delete enabled이면 → 비활성화 후 삭제 → 재활성화
- 삭제 대상 목록은 manifest list-metadata에서 추출하여 파일로 저장
- show-tags API는 stale 데이터 포함하므로 삭제 확인용으로 사용하지 않음
- 현재 운영 중인 이미지 태그 확인 후 삭제 대상에서 제외
- Portal에서 최종 확인
8. AWS ECR vs Azure ACR — 이미지 Lifecycle 관리 비교
AWS ECR을 사용해 본 경험이 있다면, ECR의 Lifecycle Policy가 얼마나 편리한지 알 것입니다. JSON으로 정책을 선언하면 자동으로 오래된 이미지를 정리해 줍니다. Azure ACR에도 이런 기능이 있을까요?
8.1 빌트인 Lifecycle Policy 비교
| 항목 | AWS ECR Lifecycle | Policy Azure ACR |
| 빌트인 정책 | O (네이티브) | Retention Policy (Premium SKU만, Preview) |
| 대상 | 태그/untagged 모두 | untagged manifest만 |
| 태그 기반 정리 | O (prefix, count, age) | X (Retention Policy로는 불가) |
| 모든 SKU 지원 | O (Free tier 포함) | X (Premium만) |
| 추가 비용 | 무료 | - |
결론: ACR에는 ECR처럼 "태그된 이미지까지 포함하는 빌트인 Lifecycle Policy"가 없습니다.
ACR의 Retention Policy는 Premium SKU($50/month)에서만 사용 가능하고, untagged manifest만 대상으로 합니다. 태그가 달린 오래된 이미지를 자동 삭제하는 빌트인 기능은 존재하지 않습니다.
8.2 ACR의 대안: ACR Purge Task
ECR Lifecycle Policy와 가장 유사한 기능은 ACR Purge Task입니다. 빌트인이 아니라 ACR Task로 직접 스케줄링해야 합니다:
az acr task create \\\\
--name weeklyPurge \\\\
--registry myregistry \\\\
--cmd "acr purge \\\\
--filter 'myapp-worker-common:.*' \\\\
--ago 30d --keep 10 --untagged" \\\\
--schedule "0 1 * * Sun" \\\\
--context /dev/null
8.3 상세 기능 비교
| 기능 | ECR Lifecycle | Policy ACR Purge Task |
| 설정 방식 | JSON 정책 선언 | CLI로 Task 생성 |
| 태그 필터 | prefix 매칭 | 정규식 (--filter) |
| 개수 기반 유지 | countNumber | --keep N |
| 기간 기반 삭제 | sinceImagePushed | --ago 30d |
| Untagged 삭제 | untagged rule | --untagged |
| 스케줄링 | 자동 (정책 적용 즉시) | cron 표현식 |
| 비용 | 무료 | Task 실행 비용 (~$0.0001/sec) |
| Dry-run | X | --dry-run 지원 |
| SKU 제한 | 없음 | 없음 (모든 SKU) |
| 우선순위 규칙 | O (여러 규칙 순서 지정) | X (단일 필터) |
8.4 ECR이 더 나은 점
- 빌트인: 별도 Task 생성 없이 정책만 선언하면 자동 적용
- 규칙 우선순위: 여러 규칙을 순서대로 평가 가능 (예: "prod-*는 100개 유지, dev-*는 5개 유지")
- 추가 비용 없음: Lifecycle Policy 실행에 별도 과금 없음
- UI 지원: AWS Console에서 시각적으로 규칙 생성/관리
ECR Lifecycle Policy 예시:
{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 10 prod images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["prod-"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Delete images older than 30 days",
"selection": {
"tagStatus": "any",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 30
},
"action": { "type": "expire" }
}
]
}
8.5 ACR Purge가 더 나은 점
- 정규식 필터: ECR의 prefix보다 유연한 패턴 매칭 (예: -filter 'repo:v[0-9]+\\\\\\\\..*')
- Dry-run: 실제 삭제 전에 대상 목록을 미리 확인 가능
- -keep 옵션: 최신 N개를 간단하게 유지 (ECR은 countNumber로 유사하게 가능)
8.6 실무 권장사항
AWS에서 Azure로 마이그레이션하는 경우, ECR Lifecycle Policy를 ACR에서 재현하려면:
- ACR Purge Task로 대체 — 모든 SKU에서 사용 가능, 주간/일간 스케줄 설정
- Retention Policy는 보조적으로만 — Premium SKU라면 untagged manifest 정리용으로 병행
- Soft Delete 보존 기간 최소화 — 삭제 후에도 스토리지가 즉시 줄어들지 않는 점 주의
# ECR Lifecycle "30일 이상, 최근 10개 유지"와 동등한 ACR Purge Task
az acr task create \\\\
--name lifecyclePurge \\\\
--registry myregistry \\\\
--cmd "acr purge \\\\
--filter 'myapp:.*' \\\\
--ago 30d --keep 10 --untagged" \\\\
--schedule "0 2 * * *" \\\\
--context /dev/null
9. SKU 선택 가이드
| 사용 패턴 | 권장 SKU | 이유 |
| 개발/테스트, 소규모 | Basic ($5/mo) | 10 GiB 내 사용, 비용 최소 |
| 프로덕션, 중규모 | Standard ($20/mo) | 100 GiB 포함, 대부분의 요구 충족 |
| 대규모, 다중 리전, 보안 중시 | Premium ($50/mo) | Geo-replication, Private Link, Retention Policy |
ACR Purge Task는 모든 SKU에서 사용 가능하므로, Retention Policy가 필요하지 않다면 Basic이나 Standard로 충분합니다.
마치며
ACR의 스토리지를 효율적으로 관리하려면 네 가지를 이해해야 합니다:
- ACR은 레이어 단위로 저장한다 — 이미지 크기 × 이미지 수 = 실제 스토리지가 아닙니다. Content-addressable storage 덕분에 동일한 레이어는 리포지토리를 넘어 1번만 저장됩니다.
- Soft Delete는 즉시 삭제가 아니다 — CLI가 성공을 반환해도 실제로는 soft-deleted 상태로 전환만 된 것이며, 보존 기간 동안 스토리지 비용이 계속 발생합니다. 대량 삭제 시에는 Soft Delete를 임시 비활성화하는 것이 효과적입니다.
- ECR과 달리 빌트인 Lifecycle Policy가 없다 — AWS ECR처럼 JSON 정책만 선언하면 끝나는 구조가 아닙니다. ACR Purge Task를 직접 생성하고 스케줄링해야 합니다.
- 자동화가 답이다 — ACR Purge Task를 스케줄링하면 수동 관리 없이 오래된 이미지를 자동으로 정리할 수 있습니다. ECR Lifecycle Policy와 동등한 수준의 정리가 가능합니다.
참고 자료
'CLOUD > AZURE' 카테고리의 다른 글
| Azure AKS 요금제와 운영 선택지 정리 (0) | 2026.02.05 |
|---|---|
| Azure DevOps Agent - 비용, 사용량 확인, Self-hosted vs Microsoft-hosted, 전환 전략 (0) | 2025.12.30 |
| Azure App Registrations (0) | 2025.10.27 |
| Azure Service Principal 생성 및 환경 변수 설정 가이드 (3) | 2025.08.14 |
| Azure Application Gateway에서 HostName 중복과 Any Host 리스너 동작 원리 (0) | 2025.08.10 |
댓글