Theme:

docker pull nginx를 실행하면 어떤 버전이 받아질까요? 오늘과 내일 받아지는 이미지가 같을 거라는 보장이 있을까요?

이미지 이름의 구조

Docker 이미지의 전체 이름(reference)은 다음과 같은 구조입니다.

PLAINTEXT
[레지스트리 호스트/][네임스페이스/]이미지이름[:태그|@다이제스트]
BASH
# Docker Hub 공식 이미지 (라이브러리 네임스페이스)
nginx:1.25-alpine
# 실제 전체 경로: docker.io/library/nginx:1.25-alpine

# Docker Hub 사용자 이미지
myuser/myapp:v1.0.0
# 실제 전체 경로: docker.io/myuser/myapp:v1.0.0

# GitHub Container Registry
ghcr.io/myorg/myapp:latest

# AWS ECR
123456789.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v2.1.0

# 다이제스트로 참조
nginx@sha256:abc123def456...

태그의 본질

태그는 이미지에 붙이는 가변(mutable) 라벨입니다. 같은 태그가 다른 이미지를 가리킬 수 있다는 점이 중요합니다.

BASH
# 같은 이미지에 여러 태그 부여
docker tag myapp:latest myapp:v1.0.0
docker tag myapp:latest myapp:stable

# 이후 새 빌드에서 latest를 덮어쓸 수 있음
docker build -t myapp:latest .
# 이제 latest는 새 이미지를 가리키지만, v1.0.0은 이전 이미지를 가리킴

latest의 함정

latest는 특별한 태그가 아닙니다. 단순히 태그를 명시하지 않았을 때의 기본값일 뿐입니다.

  • 자동으로 최신 버전을 가리키지 않습니다
  • 누군가 docker push myapp:latest를 하면 덮어씌워집니다
  • 어떤 버전인지 추적할 수 없습니다
BASH
# 이 두 명령어는 동일
docker pull nginx
docker pull nginx:latest

# 하지만 오늘의 nginx:latest와 내일의 nginx:latest가
# 같은 이미지라는 보장은 없습니다

태그 전략

Semantic Versioning (SemVer)

BASH
myapp:1.2.3      # 정확한 버전 (patch)
myapp:1.2        # 마이너 버전 (1.2.x 중 최신)
myapp:1          # 메이저 버전 (1.x.x 중 최신)
myapp:latest     # 최신 안정 버전

공식 이미지들이 흔히 사용하는 패턴입니다.

BASH
node:20.12.2           # 정확한 버전
node:20.12             # 패치 업데이트 자동
node:20                # 마이너 업데이트 자동
node:20-alpine         # 변형(variant) 포함
node:20.12.2-alpine3.19 # 가장 구체적인 태그

Git SHA 태그

BASH
myapp:a1b2c3d    # Git 커밋 해시 (짧은 형태)
myapp:main-a1b2c3d  # 브랜치 + 커밋 해시

장점: 코드와 이미지의 1:1 매핑이 가능하여 추적이 쉽습니다.

BASH
# CI에서 자동 태깅 예시
GIT_SHA=$(git rev-parse --short HEAD)
docker build -t myapp:${GIT_SHA} -t myapp:latest .

날짜 기반 태그

BASH
myapp:20260319        # 빌드 날짜
myapp:20260319-a1b2c3d  # 날짜 + Git SHA

추천 전략: 복합 태깅

BASH
# 하나의 빌드에 여러 태그를 부여
docker build \
    -t myapp:v1.2.3 \
    -t myapp:v1.2 \
    -t myapp:v1 \
    -t myapp:latest \
    -t myapp:$(git rev-parse --short HEAD) \
    .
  • 프로덕션 배포: v1.2.3 (정확한 버전)
  • 디버깅/추적: a1b2c3d (Git SHA)
  • 개발 환경: latest
  • 롤백: 이전 SemVer 태그로 빠르게 전환

다이제스트 — 불변의 식별자

태그와 달리 다이제스트(digest)는 이미지 내용의 SHA256 해시입니다. 내용이 바뀌면 다이제스트도 바뀝니다.

BASH
# 이미지의 다이제스트 확인
docker inspect --format='{{index .RepoDigests 0}}' nginx:1.25-alpine
# nginx@sha256:a1b2c3d4e5f6...

# 다이제스트로 pull (100% 재현 가능)
docker pull nginx@sha256:a1b2c3d4e5f6...

프로덕션에서 정확한 재현성이 필요할 때 다이제스트를 사용합니다.

DOCKERFILE
# 태그 대신 다이제스트 사용 (가장 안전)
FROM nginx@sha256:a1b2c3d4e5f6...

레지스트리 비교

Docker Hub

BASH
# 로그인
docker login

# 이미지 push
docker tag myapp:v1.0.0 myuser/myapp:v1.0.0
docker push myuser/myapp:v1.0.0
  • 가장 범용적인 레지스트리
  • 무료 계정: 1개의 프라이빗 리포지토리
  • 공식 이미지의 기본 소스
  • Rate limit: 익명 100회/6시간, 인증 200회/6시간

GitHub Container Registry (GHCR)

BASH
# GitHub PAT로 로그인
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin

# push
docker tag myapp:v1.0.0 ghcr.io/myorg/myapp:v1.0.0
docker push ghcr.io/myorg/myapp:v1.0.0
  • GitHub 계정과 통합
  • GitHub Actions에서 자동 인증 (GITHUB_TOKEN)
  • 리포지토리 권한과 연동 가능
  • 퍼블릭 이미지 무료, 프라이빗도 넉넉한 무료 용량

AWS ECR (Elastic Container Registry)

BASH
# AWS CLI로 로그인 (토큰 12시간 유효)
aws ecr get-login-password --region ap-northeast-2 | \
    docker login --username AWS --password-stdin \
    123456789.dkr.ecr.ap-northeast-2.amazonaws.com

# 리포지토리 생성 (콘솔 또는 CLI)
aws ecr create-repository --repository-name myapp

# push
docker push 123456789.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1.0.0
  • AWS 서비스(ECS, EKS)와 긴밀한 통합
  • IAM 기반 접근 제어
  • 이미지 스캐닝 내장
  • 수명 주기 정책으로 자동 정리

Harbor (자체 호스팅)

BASH
# Harbor 설치 (docker-compose 기반)
# harbor.mydomain.com 같은 도메인으로 접근

docker login harbor.mydomain.com
docker push harbor.mydomain.com/myproject/myapp:v1.0.0
  • CNCF 졸업 프로젝트
  • 자체 인프라에서 운영
  • 취약점 스캐닝(Trivy 내장), RBAC, 감사 로그
  • 이미지 복제(replication) 기능

비교 표

특성Docker HubGHCRECRHarbor
호스팅클라우드클라우드클라우드자체 호스팅
인증Docker IDGitHub TokenIAMLDAP/OIDC
비용무료/유료무료/유료종량제무료 (인프라 비용)
스캐닝Docker Scout없음내장Trivy 내장
CI 통합범용GitHub ActionsCodePipeline범용

이미지 관리 실무

태그 불변성(Immutable Tags)

일부 레지스트리는 태그 덮어쓰기를 방지하는 기능을 제공합니다.

BASH
# ECR: 태그 불변성 활성화
aws ecr put-image-tag-mutability \
    --repository-name myapp \
    --image-tag-mutability IMMUTABLE

이렇게 설정하면 v1.0.0 태그를 한 번 push한 후 같은 태그로 다시 push할 수 없습니다.

이미지 정리 정책

오래된 이미지가 쌓이면 저장소 비용이 증가합니다.

BASH
# ECR 수명 주기 정책 예시
aws ecr put-lifecycle-policy --repository-name myapp --lifecycle-policy-text '{
  "rules": [
    {
      "rulePriority": 1,
      "description": "30일 이상 된 untagged 이미지 삭제",
      "selection": {
        "tagStatus": "untagged",
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 30
      },
      "action": { "type": "expire" }
    },
    {
      "rulePriority": 2,
      "description": "최근 10개 태그만 유지",
      "selection": {
        "tagStatus": "tagged",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": { "type": "expire" }
    }
  ]
}'

미러링 및 프록시

BASH
# Docker Hub Rate Limit 우회를 위한 미러 설정
# /etc/docker/daemon.json
{
  "registry-mirrors": ["https://mirror.gcr.io"]
}

Harbor에서는 프록시 캐시 기능으로 Docker Hub 이미지를 자동으로 캐싱할 수 있습니다.

멀티 아키텍처 이미지

ARM(Apple Silicon, AWS Graviton)과 AMD64를 모두 지원하는 이미지를 만들 수 있습니다.

BASH
# buildx로 멀티 아키텍처 빌드 + push
docker buildx build \
    --platform linux/amd64,linux/arm64 \
    -t myregistry.com/myapp:v1.0.0 \
    --push .
BASH
# 매니페스트 확인
docker manifest inspect nginx:1.25-alpine

정리

  • 이미지 태그는 가변이므로 프로덕션에서는 정확한 버전 태그(v1.2.3)나 다이제스트를 사용합니다.
  • latest는 개발 편의를 위한 것이지, 프로덕션 배포용이 아닙니다.
  • Git SHA 태그를 함께 사용하면 코드와 이미지를 정확히 추적할 수 있습니다.
  • 레지스트리는 팀의 인프라 환경에 맞게 선택합니다. GitHub 중심이면 GHCR, AWS 중심이면 ECR, 자체 관리가 필요하면 Harbor가 적합합니다.
  • 수명 주기 정책을 설정하여 오래된 이미지를 자동 정리하는 것을 잊지 마세요.
댓글 로딩 중...