레지스트리와 이미지 관리
이미지는 어디에 사는가
docker pull nginx:latest를 실행하면 이미지가 어딘가에서 내려온다. 그 "어딘가"가 레지스트리(Registry)다. 레지스트리는 컨테이너 이미지의 저장소이자 배포 인프라다. 개발자 로컬에서 빌드한 이미지가 프로덕션 서버에 도달하는 전 과정을 레지스트리가 중계한다.
이미지 이름의 완전한 형태는 [registry]/[namespace]/[repository]:[tag]이다.
docker.io/library/nginx:1.25.3
^^^^^^^^^^ ← 레지스트리 (생략 시 docker.io)
^^^^^^^ ← 네임스페이스 (library = Docker 공식 이미지)
^^^^^ ← 저장소 이름
^^^^^^ ← 태그레지스트리 생태계
(docker.io) GitHub Container Registry
(ghcr.io) 누구나 pull 가능
Rate limit 존재
Google Artifact Registry
Azure Container Registry IAM 통합, 취약점 스캔
클라우드 인프라와 긴밀하게 연동
(CNCF Distribution) 완전한 제어권
에어갭(air-gap) 환경
OCI Distribution Spec: 왜 중요한가
OCI(Open Container Initiative) Distribution Spec은 레지스트리가 이미지를 어떻게 저장하고 제공하는지에 대한 표준 API를 정의한다. v1.1(2024년 3월)에서 가장 중요한 변화는 아티팩트 관계(Reference Type)다. 이미지에 서명, SBOM(소프트웨어 부품 목록), 취약점 보고서를 별도 아티팩트로 첨부할 수 있게 됐다.
이 표준 덕분에 docker pull, crane, skopeo 같은 도구가 Docker Hub든 ECR이든 Harbor든 동일하게 동작한다.
Docker Hub: 가장 큰 공개 레지스트리
Docker Hub는 800만 개 이상의 이미지를 보유한 세계 최대 컨테이너 레지스트리다.
Rate Limit 현황 (2025-2026):
| 구분 | Pull 한도 |
|---|---|
| 비인증(익명) | 100회 / 6시간 |
| 무료 계정(인증) | 200회 / 6시간 |
| Pro/Team/Business | 무제한 |
CI/CD 파이프라인에서는 인증 여부만으로 한도가 2배 차이 난다. docker login 설정 하나가 파이프라인 안정성에 영향을 미친다.
Docker는 2025년 4월에 예정했던 강화된 Rate Limit 정책을 무기한 연기했고, 정책 변경 전 최소 6개월 공지를 약속했다.
Amazon ECR: AWS 클라우드의 레지스트리
인증 방법
ECR은 자체 사용자/비밀번호가 없다. IAM으로 권한을 제어하고 단기 토큰으로 로그인한다.
# 12시간 유효 토큰을 발급받아 docker login
aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-northeast-2.amazonaws.com
# 이미지 push
docker tag myapp:1.0 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:1.0
docker push 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:1.0수명주기 정책(Lifecycle Policy)
오래된 이미지를 자동 삭제해 스토리지 비용을 절감한다.
{
"rules": [
{
"rulePriority": 1,
"description": "최신 10개 이미지만 유지",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "untagged 이미지 7일 후 삭제",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
}
]
}Immutable Tags: 태그 덮어쓰기를 방지한다. 한 번 push한 v1.2.3은 다른 이미지로 교체할 수 없다. 배포 신뢰성이 크게 높아진다.
Harbor: 엔터프라이즈 자체 레지스트리
Harbor는 CNCF에서 졸업(graduated)한 오픈소스 레지스트리다. 단순한 이미지 저장을 넘어 기업 환경에 필요한 기능을 제공한다.
접근 제어 프로젝트·사용자·역할
단위 세밀한 권한 관리
(Trivy) Push 시 자동 스캔
CVE 기반 위험 이미지 차단
(Replication) 다른 Harbor·ECR·GCR 등으로
멀티 DC 복제
웹훅·서명 Cosign/Notation 지원
스토리지 자동 정리
Harbor는 Kubernetes 위에 Helm Chart로 배포하는 것이 일반적이다. 에어갭(인터넷 차단) 환경에서 Docker Hub 미러로도 활용된다.
이미지 태깅 전략
:latest 태그 하나에만 의존하는 것은 프로덕션 장애의 흔한 원인이다.
배포 이력 추적 용이
코드 커밋과 1:1 대응
CI/CD 자동화에 적합
release 빌드: SemVer
개발/CI 빌드: SHA
→ 의도치 않은 이미지 교체
→ 롤백 불가
멀티 아키텍처 이미지 (Multi-arch)
Apple Silicon(arm64)과 x86 서버(amd64)를 동시에 지원해야 하는 상황이 일반화됐다. Docker Buildx는 하나의 태그로 여러 아키텍처 이미지를 제공하는 매니페스트 리스트를 만들 수 있다.
# Buildx 빌더 생성 (컨테이너 드라이버로 크로스 빌드 지원)
docker buildx create --name multi --driver docker-container --use
# amd64 + arm64 동시 빌드 & push
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:1.0.0 \
--push . # 멀티 아키텍처 이미지는 레지스트리에 push 필수docker pull myapp:1.0.0을 실행하면 Docker 데몬이 자동으로 현재 호스트 아키텍처에 맞는 이미지를 선택한다.
크로스 컴파일로 QEMU 오버헤드 줄이기: Go처럼 크로스 컴파일을 지원하는 언어는 빌드 스테이지를 호스트 아키텍처에서 실행시켜 에뮬레이션 없이 빌드할 수 있다.
FROM --platform=$BUILDPLATFORM golang:1.22 AS builder
ARG TARGETOS TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /app .
FROM alpine
COPY --from=builder /app /usr/local/bin/$BUILDPLATFORM은 빌드 호스트(예: amd64)에서 네이티브로 실행되고, 결과 바이너리만 타겟 플랫폼 이미지에 복사된다.
이미지 취약점 스캔
취약점 스캔은 CI 파이프라인에 통합해 "보안 게이트"로 사용하는 것이 현재 실무 표준이다.
| 도구 | 특징 | 적합한 상황 |
|---|---|---|
| Trivy (Aqua) | 컨테이너·IaC·시크릿·라이선스 통합 스캔, Harbor 기본 스캐너 | 단일 도구로 포괄적 커버리지 |
| Grype (Anchore) | 순수 취약점 스캔, amd64 이미지 30초 이내 | 고속 대용량 스캔 |
| Snyk Container | IDE 통합, 컨텍스트 기반 우선순위화 | 개발자 친화적 워크플로 |
# Trivy로 로컬 이미지 스캔
trivy image myapp:1.2.3
# 레지스트리 이미지 직접 스캔 (pull 없이)
trivy image 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:1.2.3
# CRITICAL만 필터링, 발견 시 exit code 1 (CI 게이트)
trivy image --severity CRITICAL --exit-code 1 myapp:1.2.3이미지 서명: DCT에서 Sigstore/Cosign으로
코드 서명처럼 컨테이너 이미지도 서명해 위변조를 방지할 수 있다. 2025년을 기점으로 업계 표준이 Notary v1(DCT)에서 Sigstore/Cosign으로 이동했다.
Cosign 키리스 서명 흐름:
# 서명 (GitHub Actions OIDC 환경에서 키리스)
cosign sign --yes myapp:1.2.3
# 검증
cosign verify \
--certificate-identity "https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
myapp:1.2.3- CI가 GitHub OIDC로 인증 → Fulcio가 단기 코드 서명 인증서 발급
- Cosign이 이미지 다이제스트에 서명 → 서명과 인증서를 Rekor 투명성 로그에 기록
- 개인 키를 보관할 필요 없음 — 서명 신원은 GitHub Actions 워크플로 URL
Pull-Through Cache: Rate Limit 우회
Docker Hub Rate Limit를 완화하거나 내부 네트워크 속도를 높이기 위해 레지스트리를 캐시로 사용할 수 있다.
// /etc/docker/daemon.json
{
"registry-mirrors": ["https://my-mirror.internal:5000"]
}처음 pull 요청이 오면 업스트림(Docker Hub)에서 이미지를 가져와 저장하고, 이후 동일 이미지는 캐시에서 바로 제공한다.
주의: 표준 Docker 데몬은 Docker Hub만 미러링 대상으로 지원한다. BuildKit은 buildkitd.toml을 통해 여러 레지스트리 미러를 지정할 수 있다.
Skopeo / Crane: 데몬 없는 이미지 조작
Docker 데몬 없이도 레지스트리 작업을 수행할 수 있는 CLI 도구들이 있다. CI/CD 환경에서 도커 소켓을 마운트하지 않아도 된다.
| 도구 | 주요 기능 | 강점 |
|---|---|---|
| Skopeo (RedHat) | copy (레지스트리 간 복사), sync, inspect | 검증된 안정성, Red Hat 지원 |
| Crane (Google) | ls (태그 목록), cp, digest | 단순하고 스크립팅 친화적 |
| Regctl | 위 두 도구의 기능 + 이미지 메타데이터 직접 수정 | 가장 포괄적인 기능 |
# Skopeo: 레지스트리 간 이미지 복사 (pull/push 없이)
skopeo copy \
docker://docker.io/library/nginx:1.25 \
docker://my-harbor.internal/mirror/nginx:1.25
# Crane: 레지스트리의 태그 목록 조회
crane ls myapp
# Crane: 이미지 다이제스트 확인
crane digest myapp:1.2.3가비지 컬렉션: 레지스트리 스토리지 관리
이미지를 계속 push하면 레지스트리 스토리지가 계속 증가한다. 태그를 삭제해도 실제 레이어(Blob) 데이터는 남아 있다. 가비지 컬렉션(GC)이 미참조 데이터를 삭제한다.
2단계 GC 프로세스:
- Mark 단계: 모든 매니페스트를 스캔해 참조되는 Blob 다이제스트 집합을 구성한다.
- Sweep 단계: 모든 Blob을 스캔해 Mark 집합에 없는 것들을 삭제한다.
# registry:2 가비지 컬렉션 (dry-run 먼저)
registry garbage-collect --dry-run /etc/registry/config.yml
# 실제 실행 (레지스트리 쓰기 중단 후 실행)
registry garbage-collect /etc/registry/config.yml중요: GC 실행 중 이미지 push가 발생하면 진행 중인 업로드의 레이어가 삭제될 수 있다. 반드시 레지스트리를 읽기 전용 모드로 전환하거나 일시 중단한 뒤 실행한다.
전체 이미지 배포 파이프라인
(GitHub) → CI 빌드
docker buildx → 취약점 스캔
trivy / grype → 이미지 서명
cosign sign → 레지스트리 Push
ECR / Harbor
amd64 + arm64 → CRITICAL 발견 시
파이프라인 중단 → Rekor 로그 기록
감사 추적 확보 → 수명주기 정책으로
오래된 이미지 자동 삭제
References
- Docker Hub pull usage and limits — Docker Docs
- OCI Image and Distribution Specs v1.1 Releases — Open Container Initiative
- Automate the cleanup of images with lifecycle policies — Amazon ECR
- Preventing image tags from being overwritten in Amazon ECR
- Harbor: Enterprise-grade container registry — CNCF Blog
- Multi-platform builds — Docker Docs
- Signing Containers — Sigstore Docs
- Migrating from Docker Content Trust to Sigstore — Cloudsmith
- Trivy vs Grype (2026): Container Security Compared — AppSecSanta
- Mirror the Docker Hub library — Docker Docs
- Skopeo vs Crane vs Regctl — Alexandre Vazquez
- Transition from Container Registry — Google Cloud Docs
- Revisiting Docker Hub Policies — Docker Blog