Skip to main content
Summary

레지스트리는 이미지를 공유하는 저장소다

지금까지는 내 컴퓨터 안에서 이미지를 만들고 실행했다. 하지만 실제 개발에서는 이미지가 한 컴퓨터에만 머물러 있으면 곤란하다. 팀원이 같은 이미지를 내려받아 실행해야 하고, 테스트 서버와 운영 서버도 같은 실행 산출물을 사용해야 한다.

이때 사용하는 곳이 이미지 레지스트리다. 레지스트리는 이름과 태그가 붙은 컨테이너 이미지를 저장하고 배포하는 시스템이다.1 Git 저장소가 소스 코드를 공유하는 장소라면, 이미지 레지스트리는 실행 가능한 애플리케이션 이미지를 공유하는 장소라고 볼 수 있다.

기본 흐름은 단순하다.

docker build -t my-node-web:1.0 .
docker tag my-node-web:1.0 사용자명/my-node-web:1.0
docker login
docker push 사용자명/my-node-web:1.0
docker pull 사용자명/my-node-web:1.0

핵심은 docker push 이후다. 이미지를 레지스트리에 올리면 내 컴퓨터의 파일이 아니라 팀과 서버가 함께 사용할 수 있는 배포 단위가 된다. 서버에서는 소스 코드를 다시 빌드하지 않고, 검증된 이미지를 docker pull로 내려받아 실행할 수 있다.

Docker Hub와 이미지 레지스트리 활용AI 생성 이미지

어떤 레지스트리를 사용할까

대표적인 선택지는 Docker Hub, GitHub Container Registry, 사설 레지스트리다.

종류이미지 이름 예주로 쓰는 상황
Docker Hubusername/my-node-web:1.0학습, 공개 이미지 배포, 범용적인 이미지 공유
GitHub Container Registryghcr.io/org/my-node-web:1.0GitHub 저장소, GitHub Actions, 조직 권한과 함께 이미지 관리
사설 레지스트리registry.example.com/team/my-node-web:1.0회사 내부 배포, 보안 정책, 폐쇄망, 자체 운영 환경

Docker Hub는 가장 익숙한 공개 레지스트리다. nginx, mysql, redis, node 같은 이미지를 받을 때 대부분 Docker Hub를 사용해 왔다. 개인 프로젝트나 오픈소스 이미지를 배포하기 쉽고, 학습용으로도 가장 접근성이 좋다.

GitHub Container Registry, 줄여서 GHCR은 GitHub와 함께 쓰기 좋다. 이미지 이름은 보통 ghcr.io/NAMESPACE/IMAGE_NAME:TAG 형식을 사용한다. 여기서 NAMESPACE는 개인 계정이나 조직 이름이다. GitHub Actions에서 이미지를 빌드하고 푸시할 때 GITHUB_TOKEN이나 패키지 권한을 활용할 수 있어 GitHub 중심의 팀에 잘 맞는다.2

사설 레지스트리는 회사나 조직이 직접 관리하는 이미지 저장소다. 클라우드 제공자의 관리형 레지스트리나 자체 구축한 레지스트리가 여기에 속한다. 외부 공개가 어려운 서비스, 보안 심사가 필요한 이미지, 내부망에서만 배포해야 하는 환경에서 사용한다. 사설 레지스트리에 이미지를 올릴 때는 이미지 이름 앞에 레지스트리 주소와 포트를 붙인다.3

docker tag my-node-web:1.0 registry.example.com/team/my-node-web:1.0
docker push registry.example.com/team/my-node-web:1.0

처음에는 Docker Hub로 흐름을 익히면 충분하다. 이후 GitHub Actions를 중심으로 자동 배포를 구성한다면 GHCR을, 회사 정책과 보안 요구가 강하다면 사설 레지스트리를 검토하면 된다.

이미지 이름은 주소다

Docker 이미지 이름은 단순한 별명이 아니다. 어느 레지스트리의 어느 저장소에 있는 어떤 버전인지를 나타내는 주소다. Docker 공식 문서는 이미지 참조 형식을 다음과 같이 설명한다.4

HOST[:PORT]/PATH[:TAG]

예를 들어 다음 이미지를 보자.

docker.io/library/nginx:latest

각 부분은 이렇게 나뉜다.

  • docker.io: 레지스트리 호스트다. Docker Hub를 뜻한다.

  • library/nginx: 이미지 저장소 경로다. library는 Docker Hub의 공식 이미지 네임스페이스다.

  • latest: 태그다.

우리가 평소에 실행하던 명령은 더 짧다.

docker run nginx

하지만 Docker는 이것을 사실상 다음 이미지로 해석한다.

docker.io/library/nginx:latest

호스트를 생략하면 기본적으로 Docker Hub를 사용한다. 태그를 생략하면 기본적으로 latest 태그를 사용한다. 그래서 nginx라고만 입력해도 이미지가 내려받아진다.

개인 Docker Hub 저장소에 이미지를 올릴 때는 보통 다음 형식을 쓴다.

사용자명/저장소명:태그

예시는 다음과 같다.

alice/my-node-web:1.0
alice/my-node-web:2026.07.15
alice/my-node-web:git-a1b2c3d

여기서 alice는 네임스페이스다. 개인 계정 이름일 수도 있고 조직 이름일 수도 있다. my-node-web은 저장소 이름이다. 1.0, 2026.07.15, git-a1b2c3d는 태그다.

이미지 이름과 저장소 이름은 소문자 중심으로 작성하는 것이 안전하다. 실무에서는 my-node-web, payment-api, backend-worker처럼 역할이 드러나는 이름을 많이 쓴다.

latest 태그는 최신이라는 보장이 아니다

초보자가 가장 헷갈리는 태그가 latest다. 이름만 보면 언제나 최신 버전처럼 보인다. 하지만 latest는 특별한 자동 업데이트 기능이 아니다. 단지 태그 이름이 latest일 뿐이다.

누군가 오늘 my-app:latest를 푸시하고, 내일 다른 이미지를 같은 태그로 다시 푸시할 수 있다. 그러면 같은 명령을 실행해도 시점에 따라 다른 이미지가 내려받아질 수 있다.

docker pull my-app:latest

개발 중에는 latest가 편리하다. 하지만 운영 배포에서는 위험할 수 있다. 장애가 났을 때 정확히 어떤 이미지가 실행 중이었는지 추적하기 어렵기 때문이다.

운영과 테스트에서는 다음처럼 명확한 태그를 사용하는 것이 좋다.

my-app:1.4.0
my-app:1.4.0-git-a1b2c3d
my-app:2026.07.15-1530

latest를 완전히 쓰지 말라는 뜻은 아니다. 다만 latest는 '현재 기본으로 보여 줄 이미지' 정도로만 사용하고, 실제 배포 기록은 버전 태그나 커밋 해시 태그로 남겨야 한다.

실습: Docker Hub에 이미지 올리기

이번 실습에서는 앞 장에서 만든 my-node-web:1.0 이미지를 Docker Hub에 올려 보자. 아직 이미지가 없다면 프로젝트 디렉터리에서 다시 빌드한다.

docker build -t my-node-web:1.0 .

먼저 로컬 이미지 목록을 확인한다.

docker image ls my-node-web

이제 Docker Hub 계정 이름을 사용해 이미지를 새 이름으로 태그한다. 아래 명령에서 YOUR_DOCKERHUB_USERNAME은 자신의 Docker Hub 사용자명으로 바꾼다.

docker tag my-node-web:1.0 YOUR_DOCKERHUB_USERNAME/my-node-web:1.0

docker tag는 이미지를 복사하는 명령이 아니다. 같은 이미지에 새 이름표를 하나 더 붙이는 명령에 가깝다. 확인해 보자.

docker image ls

같은 이미지 ID에 my-node-web:1.0과 YOUR_DOCKERHUB_USERNAME/my-node-web:1.0이 함께 보일 수 있다. 이제 Docker Hub에 로그인한다.

docker login

인증이 끝나면 이미지를 푸시한다.

docker push YOUR_DOCKERHUB_USERNAME/my-node-web:1.0

푸시할 때 Docker는 이미지 레이어를 레지스트리로 업로드한다. 이미 레지스트리에 있는 레이어는 다시 올리지 않을 수 있다. 그래서 비슷한 이미지를 여러 번 푸시할 때 매번 전체가 업로드되는 것은 아니다.

권한 오류가 난다면 다음을 확인한다.

  • Docker Hub 사용자명이 정확한가?

  • docker login이 성공했는가?

  • 저장소 이름이 올바른가?

  • 계정이나 조직 정책상 저장소를 먼저 만들어야 하는가?

  • 이미지 이름에 대문자나 허용되지 않는 문자가 들어갔는가?

이제 다른 환경에서 이미지를 내려받는 상황을 흉내 내 보자.

docker pull YOUR_DOCKERHUB_USERNAME/my-node-web:1.0

내려받은 이미지로 컨테이너를 실행한다.

docker run --rm -p 3000:3000 YOUR_DOCKERHUB_USERNAME/my-node-web:1.0

브라우저에서 http://localhost:3000에 접속해 애플리케이션이 실행되는지 확인한다. 이제 이 이미지는 내 컴퓨터에서만 만든 결과물이 아니다. Docker Hub를 통해 다른 개발자와 서버가 같은 이미지를 받을 수 있다.

GHCR에 올릴 때의 차이

GitHub Container Registry를 사용할 때도 기본 명령은 같다. 차이는 이미지 이름 앞에 ghcr.io가 붙고, GitHub 토큰으로 로그인하는 경우가 많다는 점이다.

echo $CR_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin

CR_PAT에는 GitHub에서 발급한 토큰 값을 넣는다. 공개 이미지를 내려받는 것은 익명으로 가능할 수 있지만, 이미지를 올리거나 비공개 이미지를 받으려면 권한이 필요하다.

이미지를 GHCR 형식으로 태그한다.

docker tag my-node-web:1.0 ghcr.io/YOUR_GITHUB_USERNAME/my-node-web:1.0

그리고 푸시한다.

docker push ghcr.io/YOUR_GITHUB_USERNAME/my-node-web:1.0

내려받을 때도 같은 이름을 사용한다.

docker pull ghcr.io/YOUR_GITHUB_USERNAME/my-node-web:1.0

GitHub 저장소와 이미지 권한을 함께 관리하고 싶다면 GHCR이 편리하다. 특히 GitHub Actions에서 테스트를 통과한 이미지를 자동으로 빌드하고 푸시하는 흐름을 만들기 좋다.

버전 태그와 Git 커밋 해시를 함께 쓰기

실무에서 가장 중요한 것은 '나중에 추적할 수 있는 이미지'를 만드는 것이다. 단순히 latest만 사용하면 어떤 소스 코드에서 만들어진 이미지인지 알기 어렵다.

좋은 태그 전략은 사람이 읽기 쉬운 버전과 기계적으로 추적 가능한 값을 함께 쓰는 것이다.

my-app:1.4.0
my-app:1.4.0-git-a1b2c3d
my-app:git-a1b2c3d

예를 들어 현재 Git 커밋 해시를 이용해 이미지를 빌드하고 태그할 수 있다.

VERSION=1.4.0
GIT_SHA=$(git rev-parse --short HEAD)
IMAGE=YOUR_DOCKERHUB_USERNAME/my-node-web

docker build \
  -t $IMAGE:$VERSION \
  -t $IMAGE:$VERSION-git-$GIT_SHA \
  -t $IMAGE:git-$GIT_SHA \
  .

그다음 필요한 태그를 푸시한다.

docker push $IMAGE:$VERSION
docker push $IMAGE:$VERSION-git-$GIT_SHA
docker push $IMAGE:git-$GIT_SHA

이 방식의 장점은 분명하다.

  • 1.4.0은 사람이 보기 쉬운 릴리스 버전이다.

  • git-a1b2c3d는 어떤 소스 코드에서 만들어졌는지 추적할 수 있다.

  • 장애가 나면 실행 중인 이미지 태그로 해당 커밋을 바로 찾을 수 있다.

  • 롤백할 때 이전 태그를 명확히 지정할 수 있다.

팀에 따라 main, dev, staging 같은 태그도 사용한다. 다만 이런 태그는 계속 바뀌는 이동식 태그다. 실제 배포 기록에는 고정된 버전 태그나 커밋 해시 태그를 반드시 함께 남기는 편이 좋다.

여러 태그를 한 번에 푸시하고 싶다면 docker push --all-tags 저장소명을 사용할 수도 있다. 하지만 의도하지 않은 실험용 태그까지 올라갈 수 있으므로 처음에는 필요한 태그만 명시적으로 푸시하는 습관을 들이자.

정리

이미지 레지스트리는 Docker 이미지를 팀과 서버가 공유하는 중심 저장소다. Docker Hub는 가장 범용적이고, GHCR은 GitHub 기반 워크플로와 잘 맞으며, 사설 레지스트리는 보안과 내부 배포 요구가 강한 환경에 적합하다.

이미지를 배포 가능한 형태로 관리하려면 이름과 태그를 정확히 이해해야 한다. docker tag로 레지스트리 주소가 포함된 이름을 붙이고, docker login으로 인증한 뒤, docker push로 업로드한다. 다른 환경에서는 docker pull로 같은 이미지를 내려받아 실행한다.

무엇보다 latest에만 의존하지 말자. 버전 태그와 Git 커밋 해시를 함께 사용하면 이미지와 소스 코드의 관계가 선명해진다. 이것이 컨테이너를 단순한 실행 도구가 아니라 신뢰할 수 있는 배포 산출물로 다루는 첫걸음이다.

참고

1Using container registries

2Working with the Container registry

3docker image push | Docker Docs

4Build, tag, and publish an image

책 목록

Docker와 Docker Compose 입문: 컨테이너 개발 환경 구축부터 운영 준비까지

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기