이미지 대량 마이그레이션
이미지 대량 마이그레이션 (Bulk migrate images)
crane 또는 regctl 도구를 사용해 Docker Hub 조직·네임스페이스 간에 Docker 이미지를 대량으로 마이그레이션하는 방법을 배워볼게요.
출처: 문서
본문
이 가이드는 Docker Hub 조직 또는 네임스페이스 간에 Docker 이미지를 대량으로 마이그레이션하는 방법을 보여줘요. 저장소를 통합하거나, 조직 구조를 바꾸거나, 이미지를 새 계정으로 옮기는 경우, 이러한 기법들은 이미지 무결성을 유지하면서 효율적으로 마이그레이션하는 데 도움이 돼요.
이 주제는 규모 순으로 구성돼요:
- 단일 이미지 태그 마이그레이션
- 저장소의 모든 태그 마이그레이션
- 여러 저장소 마이그레이션
이 워크플로우에 권장되는 도구는 crane 이에요. 동등한 대안으로 regctl 을 사용하는 방법도 함께 보여줘요. 두 도구 모두 이미지를 로컬로 풀하지 않고 레지스트리 간 복사를 수행하며 멀티 아키텍처 이미지를 보존해요. crane 은 단순성과 이미지 복사에 집중된 워크플로우 때문에 권장돼요. regctl 도 좋은 선택인데, 특히 이미지 복사 너머의 광범위한 레지스트리 관리 작업에 이미 사용 중이라면 더 좋아요.
참고: 이 주제의 주요 워크플로우는 태그가 붙은 이미지에 대해서만 동작해요. 태그가 없는 매니페스트나 태그에서 더 이상 도달할 수 없는 콘텐츠는 마이그레이션되지 않아요. 실제로 보통 이런 것들은 사용하지 않는 아티팩트지만, 마이그레이션 전에 이 제한을 알고 있어야 해요. digest 참조를 사용해 특정 태그 없는 매니페스트를 마이그레이션할 수는 있지만, 저장소의 태그 없는 매니페스트를 열거하는 API는 없어요.
사전 요구 사항
시작하기 전에 다음이 있는지 확인해요:
- 다음 중 하나가 설치되어
$PATH에 있어야 해요:craneregctl
- 소스와 대상 조직 양쪽에 대한 푸시 접근 권한
- 선택한 도구에 대한 레지스트리 인증 구성
레지스트리에 인증하기
두 도구 모두 레지스트리에 직접 인증해요. crane 은 Docker credential helper와 ~/.docker/config.json을 사용해요. crane 문서 를 참고해요. regctl 은 자체 구성 파일을 사용하고 Docker 자격 증명을 가져올 수 있어요. regctl 문서 를 참고해요. 자신의 레지스트리와 도구에 맞는 인증 지침을 따르세요.
단일 이미지 태그 마이그레이션
이것이 가장 단순하고 흔한 마이그레이션 시나리오예요. 다음 예시 스크립트는 이미지 매니페스트를 레지스트리 간에 직접 복사하고 멀티 아키텍처 이미지가 있으면 보존해요. 마이그레이션하려는 각 태그에 대해 이 과정을 반복해요. 환경 변수 값을 소스·대상 조직 이름, 저장소 이름, 태그로 바꿔요.
#!/usr/bin/env bash
set -euo pipefail
SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"
SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"
# Using crane (recommended)
crane cp "${SRC_IMAGE}" "${DEST_IMAGE}"
# Using regctl (alternative)
# regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}"
digest로 마이그레이션
태그 대신 digest로 특정 이미지를 마이그레이션하려면 소스 참조에 digest를 사용해요. 태그가 업데이트되었어도 정확한 이미지 버전을 마이그레이션해야 할 때 유용해요. 환경 변수 값을 소스·대상 조직 이름, 저장소 이름, digest, 태그로 바꿔요. 복사 작업에 crane과 regctl 중 선택할 수 있어요.
#!/usr/bin/env bash
set -euo pipefail
SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
DIGEST="sha256:abcd1234..."
TAG="stable"
SRC_IMAGE="${SRC_ORG}/${REPO}@${DIGEST}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"
# Using crane
crane cp "${SRC_IMAGE}" "${DEST_IMAGE}"
# Using regctl
# regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}"
저장소의 모든 태그 마이그레이션
저장소의 모든 태그가 붙은 이미지를 마이그레이션하려면 Docker Hub API를 사용해 태그를 열거하고 각각을 복사해요. 다음 예시 스크립트는 주어진 저장소의 모든 태그를 가져와 루프로 마이그레이션해요. 이 방식은 로컬 리소스를 압도하지 않고 태그가 많은 저장소로 확장 가능해요. Docker Hub 요청에는 rate limit이 있으므로 대규모 저장소에서는 지연(delays) 또는 페이지네이션 처리를 추가해야 할 수 있어요. 환경 변수 값을 소스·대상 조직 이름과 저장소 이름으로 바꿔요. 소스 저장소가 비공개라면 풀 접근 권한이 있는 자격 증명으로 HUB_USER와 HUB_TOKEN도 설정해요. 복사 작업에 crane과 regctl 중 선택할 수도 있어요.
#!/usr/bin/env bash
set -euo pipefail
# Use environment variables if set, otherwise use defaults
SRC_ORG="${SRC_ORG:-oldorg}"
DEST_ORG="${DEST_ORG:-neworg}"
REPO="${REPO:-myapp}"
# Optional: for private repositories
# HUB_USER="your-username"
# HUB_TOKEN="your-access-token"
# AUTH="-u ${HUB_USER}:${HUB_TOKEN}"
AUTH=""
TOOL="crane" # or: TOOL="regctl"
TAGS_URL="https://hub.docker.com/v2/repositories/${SRC_ORG}/${REPO}/tags?page_size=100"
while [[ -n "${TAGS_URL}" && "${TAGS_URL}" != "null" ]]; do
RESP=$( curl -fsSL ${AUTH} "${TAGS_URL}" )
echo "${RESP}" | jq -r '.results[].name' | while read -r TAG; do
[[ -z "${TAG}" ]] && continue
SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"
echo "Migrating ${SRC_IMAGE} → ${DEST_IMAGE}"
case "${TOOL}" in
crane) crane cp "${SRC_IMAGE}" "${DEST_IMAGE}" ;;
regctl) regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}" ;;
esac
done
TAGS_URL=$( echo "${RESP}" | jq -r '.next' )
done
참고: 계정에 권한이 있다면 Docker Hub가 첫 푸시 시 대상 저장소를 자동으로 만들어요.
여러 저장소 마이그레이션
여러 저장소를 마이그레이션하려면 목록을 만들고 각 저장소에 대해 단일 저장소 스크립트를 실행해요. 예를 들어 저장소 이름이 담긴 repos.txt 파일을 만들어요:
api
web
worker
이전 섹션의 스크립트를 migrate-single-repo.sh로 저장해요. 그런 다음 파일의 각 저장소를 처리하는 다음 예시 스크립트를 실행해요. 환경 변수 값을 소스·대상 조직 이름으로 바꿔요.
#!/usr/bin/env bash
set -euo pipefail
SRC_ORG="oldorg"
DEST_ORG="neworg"
while read -r REPO; do
[[ -z "${REPO}" ]] && continue
echo "==== Migrating repo: ${REPO}"
SRC_ORG="${SRC_ORG}"
DEST_ORG="${DEST_ORG}"
REPO="${REPO}"
./migrate-single-repo.sh
done < repos.txt
마이그레이션 무결성 검증
복사 후에 digest를 비교해 소스와 대상이 일치하는지 확인해요.
기본 digest 검증
다음 예시 스크립트는 소스와 대상 모두에서 특정 태그의 이미지 digest를 가져와 비교해요. digest가 일치하면 마이그레이션이 성공한 것이에요. 환경 변수 값을 소스·대상 조직 이름, 저장소 이름, 태그로 바꿔요. digest를 가져오는 데 crane과 regctl 중 선택할 수 있어요.
#!/usr/bin/env bash
set -euo pipefail
SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"
SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"
# Using crane
SRC_DIGEST=$( crane digest "${SRC_IMAGE}" )
DEST_DIGEST=$( crane digest "${DEST_IMAGE}" )
# Using regctl (alternative)
# SRC_DIGEST=$(regctl image digest "${SRC_IMAGE}")
# DEST_DIGEST=$(regctl image digest "${DEST_IMAGE}")
echo "Source: ${SRC_DIGEST}"
echo "Destination: ${DEST_DIGEST}"
if [[ "${SRC_DIGEST}" == "${DEST_DIGEST}" ]]; then
echo "✓ Migration verified: digests match"
else
echo "✗ Migration failed: digests do not match"
exit 1
fi
멀티 아키텍처 검증
멀티 아키텍처 이미지의 경우 매니페스트 목록도 검증해 모든 플랫폼이 올바르게 복사되었는지 확인해요. 환경 변수 값을 소스·대상 조직 이름, 저장소 이름, 태그로 바꿔요. 매니페스트를 가져오는 데 crane과 regctl 중 선택할 수 있어요.
#!/usr/bin/env bash
set -euo pipefail
SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"
SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"
# Using crane
SRC_MANIFEST=$( crane manifest "${SRC_IMAGE}" )
DEST_MANIFEST=$( crane manifest "${DEST_IMAGE}" )
# Using regctl (alternative)
# SRC_MANIFEST=$(regctl image manifest --format raw-body "${SRC_IMAGE}")
# DEST_MANIFEST=$(regctl image manifest --format raw-body "${DEST_IMAGE}")
# Check if it's a manifest list (multi-arch)
if echo "${SRC_MANIFEST}" | jq -e '.manifests' > /dev/null 2>&1; then
echo "Multi-arch image detected"
# Compare platform list
SRC_PLATFORMS=$( echo "${SRC_MANIFEST}" | jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture)"' | sort )
DEST_PLATFORMS=$( echo "${DEST_MANIFEST}" | jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture)"' | sort )
if [[ "${SRC_PLATFORMS}" == "${DEST_PLATFORMS}" ]]; then
echo "✓ Platform list matches:"
echo "${SRC_PLATFORMS}"
else
echo "✗ Platform lists do not match"
echo "Source platforms:"
echo "${SRC_PLATFORMS}"
echo "Destination platforms:"
echo "${DEST_PLATFORMS}"
exit 1
fi
else
echo "Single-arch image"
fi
마이그레이션 완료
이미지를 마이그레이션한 후 다음 추가 단계를 완료해요:
- Docker Hub UI 또는 API로 저장소 메타데이터 복사:
- README 콘텐츠
- 저장소 설명
- 토픽과 태그
- 저장소 설정이 소스와 일치하도록 구성:
- 공개 범위(public 또는 private)
- 팀 권한 및 접근 제어
- 대상 조직에서 통합 재구성:
- 웹훅
- 자동 빌드
- 보안 스캐너
- 프로젝트에서 이미지 참조 업데이트:
- Dockerfile에서
FROM oldorg/repo:tag를FROM neworg/repo:tag로 변경 - 배포 구성을 업데이트
- 문서를 업데이트
- Dockerfile에서
- 이전 위치 폐기:
- 새 위치를 가리키도록 소스 저장소 설명을 업데이트
- 이전 저장소를 private 또는 read-only로 만들기 전에 유예 기간을 두는 것을 고려