본문 바로가기
CLOUD/AZURE

Azure ACR 이미지 삭제했는데 왜 안 지워질까? — Soft Delete 함정과 스토리지 절약법, 레이어 구조부터 ECR과의 차이

by Rainbound-IT 2026. 2. 25.
반응형

Azure Container Registry의 내부 저장 구조를 이해하고, Soft Delete 함정을 피해 효율적으로 비용을 관리하는 방법

들어가며

CI/CD 파이프라인을 운영하다 보면 Container Registry에 이미지가 계속 쌓입니다. "일단 빌드 잘 되니까"라고 방치하면, 어느 날 스토리지 비용이 예상보다 높거나, 이미지를 삭제하려는데 CLI가 "성공"이라 하면서 실제로는 삭제되지 않는 황당한 상황을 마주할 수 있습니다.

이 글에서는 Azure Container Registry(ACR)를 운영하면서 겪은 실제 경험을 바탕으로:

  1. ACR이 이미지를 어떤 구조로 저장하는지
  2. *레이어 공유(Layer Deduplication)**가 어떻게 작동하는지
  3. Soft Delete 기능이 삭제 작업에 미치는 영향
  4. SKU별 비용 구조와 최적화 방법
  5. 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 추가 주의사항

  1. show-tags API는 stale 데이터 반환: soft-deleted 태그를 포함하여 반환하므로, 삭제 대상 목록을 만들 때 이 API를 반복 호출하면 이미 삭제된 태그가 계속 나옴
  2. az acr manifest delete(preview)는 비정상 동작: exit code 0을 반환하지만 실제 삭제하지 않음
  3. 삭제 대상 태그는 사전에 파일로 저장: 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 수동 정리 시 체크리스트

  1. az acr config soft-delete show --registry myregistry → Soft Delete 상태 확인
  2. Soft Delete enabled이면 → 비활성화 후 삭제 → 재활성화
  3. 삭제 대상 목록은 manifest list-metadata에서 추출하여 파일로 저장
  4. show-tags API는 stale 데이터 포함하므로 삭제 확인용으로 사용하지 않음
  5. 현재 운영 중인 이미지 태그 확인 후 삭제 대상에서 제외
  6. 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에서 재현하려면:

  1. ACR Purge Task로 대체 — 모든 SKU에서 사용 가능, 주간/일간 스케줄 설정
  2. Retention Policy는 보조적으로만 — Premium SKU라면 untagged manifest 정리용으로 병행
  3. 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의 스토리지를 효율적으로 관리하려면 네 가지를 이해해야 합니다:

  1. ACR은 레이어 단위로 저장한다 — 이미지 크기 × 이미지 수 = 실제 스토리지가 아닙니다. Content-addressable storage 덕분에 동일한 레이어는 리포지토리를 넘어 1번만 저장됩니다.
  2. Soft Delete는 즉시 삭제가 아니다 — CLI가 성공을 반환해도 실제로는 soft-deleted 상태로 전환만 된 것이며, 보존 기간 동안 스토리지 비용이 계속 발생합니다. 대량 삭제 시에는 Soft Delete를 임시 비활성화하는 것이 효과적입니다.
  3. ECR과 달리 빌트인 Lifecycle Policy가 없다 — AWS ECR처럼 JSON 정책만 선언하면 끝나는 구조가 아닙니다. ACR Purge Task를 직접 생성하고 스케줄링해야 합니다.
  4. 자동화가 답이다 — ACR Purge Task를 스케줄링하면 수동 관리 없이 오래된 이미지를 자동으로 정리할 수 있습니다. ECR Lifecycle Policy와 동등한 수준의 정리가 가능합니다.

참고 자료

반응형

댓글