Skip to content

Docker Hub ​

마지막 업데이트: 2026년 9월 11일

개요 ​

Docker Hub는 Docker CLI에서 레지스트리를 생략할 때 사용하는 기본 이미지 레지스트리입니다. Docker Official Images, Verified Publishers, 커뮤니티 이미지를 제공하며, 개인 및 팀을 위한 프라이빗 저장소 기능도 지원합니다.

Docker Hub의 세 가지 이미지 신뢰 등급인 Official Images, Verified Publishers, Community Images를 나란히 배치하여 각 등급의 검증 주체와 nginx, bitnami/, user/myapp 같은 예시 이미지를 보여준다.

Docker Hub의 세 가지 이미지 신뢰 등급인 Official Images, Verified Publishers, Community Images를 나란히 배치하여 각 등급의 검증 주체와 nginx, bitnami/, user/myapp 같은 예시 이미지를 보여준다.전체 화면으로 열기 ↗

Docker Hub 플랜 비교 ​

플랜별 기능 ​

기능PersonalProTeamBusiness
가격기본 무료 할당월간 $11 / 연간 약정 월 $9월간 $16 / 연간 약정 월 $15, 사용자당현재 요금표·계약 확인
공개 저장소무제한무제한무제한무제한
프라이빗 저장소1개무제한무제한무제한
팀 기능❌❌✅✅
보안·관리 기능플랜별 범위 확인플랜별 범위 확인조직 기능 확인SSO·감사 등 계약 범위 확인
기존 Automated Builds 병렬 수미지원51515

요금은 2026-09-11 공식 요금표의 USD 표시 기준이며 세금·결제 조건을 별도로 확인합니다. Automated Builds는 폐기 예정 기능이며 2027-04-01 종료가 공지돼 있습니다. 새 빌드는 아래 외부 CI/CD 예제를 사용합니다.

Rate Limits (Pull 제한) ​

아래는 공식 사용량 문서의 6시간 기준 표입니다. 실제 계정의 조건과 응답 헤더를 확인하고, 별도의 abuse/fair-use 제한도 고려합니다:

인증 상태Rate Limit기준
익명100 pulls / 6시간IPv4 주소 또는 IPv6 /64 대역당
Personal (인증됨)200 pulls / 6시간계정에 귀속되는 사용량
Pro무제한-
Team무제한-
Business무제한-

Rate Limit 확인 방법:

bash
# 현재 rate limit 상태 확인
TOKEN=$(curl -fsS "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -er .token)

curl -s -H "Authorization: Bearer $TOKEN" \
  -I "https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest" 2>&1 | \
  grep -i ratelimit

# 출력 예시:
# ratelimit-limit: 100;w=21600
# ratelimit-remaining: 95;w=21600

Kubernetes에서 Docker Hub 사용 ​

imagePullSecrets 설정 ​

1. Docker Hub 자격 증명으로 Secret 생성:

Secret과 이를 사용하는 Pod/ServiceAccount는 같은 namespace에 있어야 합니다. 운영에서는 읽기 전용 PAT를 사용하고 셸 히스토리나 CI 로그에 값을 직접 적지 않습니다.

bash
kubectl create secret docker-registry dockerhub-secret \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=<username> \
  --docker-password=<password-or-access-token> \
  --docker-email=<email> \
  -n default

2. Pod에서 Secret 참조:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp
  namespace: default
spec:
  containers:
  - name: myapp
    image: username/myapp:v1.0.0
  imagePullSecrets:
  - name: dockerhub-secret

3. ServiceAccount에 기본 imagePullSecrets 설정:

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp-sa
  namespace: default
imagePullSecrets:
- name: dockerhub-secret
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      serviceAccountName: myapp-sa
      containers:
      - name: myapp
        image: username/myapp:v1.0.0
        # imagePullSecrets 자동 적용

Access Token 사용 (권장) ​

비밀번호 대신 Access Token 사용을 권장합니다:

bash
# Docker Hub > Account Settings > Security > Access Tokens

# Access Token으로 Secret 생성
kubectl create secret docker-registry dockerhub-secret \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=<username> \
  --docker-password=<access-token> \
  -n default

Access Token 권한 범위:

  • Read-only: 이미지 pull만 허용
  • Read & Write: pull + push 허용
  • Read, Write & Delete: 전체 권한

Docker Hub Rate Limit 대응 전략 ​

Docker Hub Rate Limit 발생 여부를 확인한 뒤 환경에 따라 ECR Pull-through Cache, Harbor Pull Replication, containerd 미러 중 하나를 적용하거나 인증된 Pull로 사전에 예방하여 최종적으로 Rate Limit을 해소하는 의사결정 흐름을 보여준다.

Docker Hub Rate Limit 발생 여부를 확인한 뒤 환경에 따라 ECR Pull-through Cache, Harbor Pull Replication, containerd 미러 중 하나를 적용하거나 인증된 Pull로 사전에 예방하여 최종적으로 Rate Limit을 해소하는 의사결정 흐름을 보여준다.전체 화면으로 열기 ↗

전략 1: Pull-through Cache (containerd) ​

containerd 자체를 캐시 서버로 만드는 설정은 아닙니다. 별도로 구성한 레지스트리 미러를 가리키도록 설정합니다. 폐기된 registry.mirrors 대신 현재 hosts.toml 설정을 사용합니다.

toml
# containerd 1.x: /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry]
  config_path = "/etc/containerd/certs.d"
toml
# containerd 2.x: 위의 1.x 플러그인 설정 대신 사용
[plugins."io.containerd.cri.v1.images".registry]
  config_path = "/etc/containerd/certs.d"
toml
# /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://registry-1.docker.io"
[host."https://mirror.gcr.io"]
  capabilities = ["pull"]

공개 미러는 모든 이미지나 프라이빗 이미지를 보장하지 않습니다. 태그→digest 해석(resolve) 권한은 신뢰할 수 있는 미러에만 부여합니다. 관리형 노드에서는 지원되는 부트스트랩/노드 설정 경로를 사용합니다.

전략 2: Amazon ECR Pull-through Cache ​

ECR을 Docker Hub의 프록시 캐시로 사용합니다. Docker Hub 자격 증명은 동일 계정·리전의 ecr-pullthroughcache/ 접두어를 가진 Secrets Manager secret에 먼저 저장하고 실제 ARN을 사용합니다.

bash
# 이름이 ecr-pullthroughcache/dockerhub인 secret을 먼저 생성한 예
PTC_SECRET_ARN=$(aws secretsmanager describe-secret \
  --secret-id ecr-pullthroughcache/dockerhub --region ap-northeast-2 \
  --query ARN --output text)
# ECR pull-through cache 규칙 생성
aws ecr create-pull-through-cache-rule \
  --ecr-repository-prefix docker-hub \
  --upstream-registry-url registry-1.docker.io \
  --credential-arn "$PTC_SECRET_ARN" \
  --region ap-northeast-2

# 사용 예시 (원본 -> 캐시)
# docker.io/library/nginx:latest
# -> 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/docker-hub/library/nginx:latest

Kubernetes에서 사용:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        # ECR pull-through cache 사용
        image: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/docker-hub/library/nginx:1.30.4

전략 3: Harbor Pull Replication ​

Harbor에서 Docker Hub registry endpoint와 대상 프로젝트를 만든 뒤 필요한 이미지를 주기적으로 복제합니다. 아래는 UI에 설정할 조건을 설명하는 표기이며, 실제 Harbor API payload나 Kubernetes 매니페스트가 아닙니다:

yaml
# Harbor replication rule
Source: docker.io
Destination: harbor.internal/docker-cache
Filter:
  - library/nginx
  - library/redis
  - bitnami/**
Trigger: Scheduled (every 6 hours)

전략 4: 인증된 Pull 사용 ​

각 namespace에서 실제 사용하는 ServiceAccount에 pull 자격 증명을 설정합니다. kube-system의 default ServiceAccount를 수정해도 다른 namespace나 다른 ServiceAccount에 전파되지 않으며 이미 생성된 Pod도 갱신하지 않습니다.

yaml
# default namespace의 default ServiceAccount를 쓰는 새 Pod에 적용
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default
imagePullSecrets:
- name: dockerhub-secret

자동화된 빌드 (Automated Builds) ​

Docker Hub Automated Builds는 폐기 예정이며 2027-04-01에 종료됩니다. 아래 설정·훅은 기존 GitHub/Bitbucket 연동을 이해하기 위한 레거시 참고입니다. GitLab은 GitLab CI로 이미지를 빌드해 push하며, 새 파이프라인은 공식 마이그레이션 안내를 따릅니다.

GitHub 연동 설정 ​

1. Docker Hub에서 GitHub 계정 연결:

  • Docker Hub > Account Settings > Linked Accounts > GitHub

2. Automated Build 저장소 생성:

  • Create Repository > GitHub에서 저장소 선택
  • Build Rules 설정

Build Rules 예시:

Source TypeSourceDocker TagDockerfile Location
Branchmainlatest/Dockerfile
Branchdevelopdev/Dockerfile
Tag/^v([0-9.]+)$/{\1}/Dockerfile

빌드 훅 (Build Hooks) ​

빌드 프로세스를 커스터마이징하는 훅 스크립트:

bash
# hooks/build
#!/bin/bash
# 커스텀 빌드 명령
docker build \
  --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
  --build-arg VCS_REF=$(git rev-parse --short HEAD) \
  -t $IMAGE_NAME .
bash
# hooks/post_push
#!/bin/bash
# 추가 태그 푸시
docker tag $IMAGE_NAME $DOCKER_REPO:$SOURCE_COMMIT
docker push $DOCKER_REPO:$SOURCE_COMMIT

GitHub Actions 대안 (권장) ​

Docker Hub Automated Builds 대신 GitHub Actions 사용:

yaml
# .github/workflows/docker-publish.yml
name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: docker.io
  IMAGE_NAME: my-dockerhub-org/myapp # 미리 생성한 Docker Hub 리포지터리로 변경

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: docker/setup-buildx-action@v3

    - name: Login to Docker Hub
      uses: docker/login-action@v3
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}

    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=semver,pattern={{version}}
          type=sha,prefix=

    - name: Build and push
      uses: docker/build-push-action@v6
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

공개 이미지 보안 사례 ​

Supply Chain Attack 사례 ​

사례 1: Typosquatting (가상의 이름 비교이며 실제 게시자 평가가 아님)

text
approved-vendor/myapp
approved-vend0r/myapp   # 문자 o와 숫자 0의 차이

사례 2: 계정 탈취

  • 인기 이미지 메인테이너 계정 탈취
  • 악성 코드가 포함된 새 버전 푸시

사례 3: Base Image 오염

dockerfile
# 검증되지 않은 base image
FROM some-random-user/python:3.11  # 위험!

안전한 이미지 선택 가이드 ​

1. Official Images 우선:

text
공식 이미지 이름 예: docker.io/library/nginx, docker.io/library/postgres
실제 배포: 현재 유지보수 중인 버전과 검증한 전체 digest를 선택

2. Verified Publishers:

bash
# 게시자의 현재 카탈로그에서 선택한 실제 태그/digest를 먼저 확인
docker buildx imagetools inspect "$VERIFIED_VENDOR_IMAGE"
docker pull "$VERIFIED_VENDOR_IMAGE"

게시자 배지가 특정 태그의 현재 존재 여부나 취약점 부재를 보장하지는 않습니다. 예전 Bitnami/Grafana 태그나 카탈로그 접근 조건을 그대로 가정하지 않습니다.

3. 이미지 검증:

bash
# 이미지 다이제스트 확인
docker pull nginx:1.30.4
docker image inspect nginx:1.30.4 --format='{{index .RepoDigests 0}}'
# 출력된 전체 repository@sha256:... 값을 workload의 image에 사용

4. Content Trust의 적용 범위 확인:

bash
# Docker Content Trust 활성화
DOCKER_CONTENT_TRUST=1 docker pull "$DCT_SIGNED_IMAGE"
# DCT/Notary 메타데이터가 구성된 이미지에만 적용

Docker Official/Verified 배지는 특정 태그가 DCT로 서명됐거나 취약점이 없다는 보장이 아닙니다. DOCKER_CONTENT_TRUST는 Docker CLI 동작을 바꾸며 Kubernetes/containerd의 pull이나 admission에 자동으로 적용되지 않습니다.

Kubernetes Admission Control ​

다음은 허용한 이미지 출처를 점검하는 정책이며 서명이나 스캔 결과를 검증하지 않습니다. Kyverno가 설치된 환경의 registry-demo namespace에서 Audit 결과를 먼저 확인한 뒤 정책을 운영 요건에 맞게 조정합니다.

yaml
# Kyverno 출처 제한 예시 (서명 검증 정책이 아님)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: allowed-image-sources
spec:
  validationFailureAction: Audit
  rules:
  - name: verify-image-source
    match:
      any:
      - resources:
          kinds:
          - Pod
          namespaces:
          - registry-demo
    validate:
      message: "Use an approved, fully qualified image reference."
      pattern:
        spec:
          =(initContainers):
          - image: "docker.io/library/* | docker.io/my-approved-org/*"
          =(ephemeralContainers):
          - image: "docker.io/library/* | docker.io/my-approved-org/*"
          containers:
          - image: "docker.io/library/* | docker.io/my-approved-org/*"

서명 검증에는 신뢰할 공개키/서명자와 digest 검증이 필요하며, 취약점 attestation 검증에는 신뢰할 스캐너 서명과 허용 기준이 추가로 필요합니다. 이미지 보안과 Kyverno 출처 제한 예제를 구분해 읽습니다.


Docker Hub API 활용 ​

인증 ​

기존 /v2/users/login은 deprecated입니다. 공식 Hub API의 /v2/auth/token은 identifier와 secret을 받고 access_token을 반환합니다. 이 토큰은 10분 후 만료되며 Registry pull용 auth.docker.io 토큰과 별개입니다. 비밀번호 대신 필요한 권한만 가진 PAT를 사용합니다.

bash
set -euo pipefail
# Load these from secure shell input or CI secrets; do not commit their values.
: "${DOCKER_USER:?Set Docker Hub username}"
: "${DOCKER_PAT:?Load a Docker Hub personal access token}"
export DOCKER_USER DOCKER_PAT
HUB_TOKEN=$(jq -n '{identifier: env.DOCKER_USER, secret: env.DOCKER_PAT}' | \
  curl -fsS -X POST https://hub.docker.com/v2/auth/token \
    -H 'Content-Type: application/json' --data-binary @- | jq -er '.access_token')
HUB_NAMESPACE=${HUB_NAMESPACE:-$DOCKER_USER}
export HUB_TOKEN HUB_NAMESPACE

리포지터리와 태그 조회 ​

HUB_NAMESPACE는 기본적으로 로그인 사용자이며 조직을 조회하려면 해당 조직명과 권한을 설정합니다. 아래 명령은 권한 범위 내 첫 페이지만 조회합니다. page_size 최댓값은 100이며 전체 결과에는 응답의 next를 따라가야 합니다.

bash
: "${DOCKER_REPO:?Set repository name}"
curl -fsS -H "Authorization: Bearer $HUB_TOKEN" \
  "https://hub.docker.com/v2/namespaces/$HUB_NAMESPACE/repositories?page_size=100" | \
  jq '.results[] | {name, is_private}'

curl -fsS -H "Authorization: Bearer $HUB_TOKEN" \
  "https://hub.docker.com/v2/namespaces/$HUB_NAMESPACE/repositories/$DOCKER_REPO/tags?page_size=100" | \
  jq '.results[] | {name, last_updated}'

정리 대상 검토용 전체 태그 목록 ​

첫 100개 태그만 보고 나머지를 삭제하거나, 서버가 특정 정렬을 보장한다고 가정하지 않습니다. 다음 독립 Bash 스크립트는 모든 페이지를 모아 갱신일로 정렬할 뿐 삭제하지 않습니다. 삭제 전에는 실행 중인 workload의 digest, 롤백 보존 기간과 보호 태그를 별도로 확인하고 Hub 관리 화면이나 현재 공식 API에 문서화된 기능을 사용합니다.

bash
#!/usr/bin/env bash
set -euo pipefail
: "${HUB_TOKEN:?Create a current Hub API access token}"
: "${HUB_NAMESPACE:?Set namespace}"
: "${DOCKER_REPO:?Set repository}"
registry_tag_index=$(mktemp)
trap 'rm -f "$registry_tag_index"' EXIT
registry_next="https://hub.docker.com/v2/namespaces/$HUB_NAMESPACE/repositories/$DOCKER_REPO/tags?page_size=100"
while [ -n "$registry_next" ]; do
  case "$registry_next" in
    https://hub.docker.com/*) ;;
    *) printf '%s\n' 'Unexpected pagination host' >&2; exit 1 ;;
  esac
  registry_page=$(curl -fsS -H "Authorization: Bearer $HUB_TOKEN" "$registry_next")
  printf '%s' "$registry_page" | jq -c '.results[]' >> "$registry_tag_index"
  registry_next=$(printf '%s' "$registry_page" | jq -r '.next // empty')
done
# Read-only inventory. No DELETE request is made.
jq -s 'sort_by(.last_updated // "") | reverse | .[] | {name, last_updated}' "$registry_tag_index"

취약점 확인 ​

bash
# Docker Scout 사용 가능 범위는 계정/플랜/리포지터리 설정을 확인
# 이 예제는 문서화된 CLI를 사용하며 임의의 /tags/TAG/vulnerabilities API를 가정하지 않음
docker scout cves nginx:1.30.4

프라이빗 리포지터리 생성 ​

조직 namespace를 관리할 권한과 플랜의 리포지터리 허용량을 먼저 확인합니다.

bash
jq -n --arg ns "$HUB_NAMESPACE" \
  '{namespace:$ns, name:"myapp", description:"My application", is_private:true}' | \
  curl -fsS -X POST "https://hub.docker.com/v2/namespaces/$HUB_NAMESPACE/repositories" \
    -H "Authorization: Bearer $HUB_TOKEN" \
    -H 'Content-Type: application/json' --data-binary @-

CI/CD 통합 ​

GitLab CI 예시 ​

아래는 Docker executor 러너의 privileged DinD 및 /certs/client 공유가 준비됐다는 전제입니다. GitLab의 TLS DinD 설정을 먼저 적용합니다. 스캔은 Docker socket 마운트 대신 빌드 산출물 tar를 읽습니다. 운영에서는 CI 이미지도 검증한 digest로 고정합니다.

yaml
# .gitlab-ci.yml
stages:
  - build
  - scan
  - push

variables:
  DOCKER_IMAGE: myapp:$CI_COMMIT_SHA
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_CERTDIR: "/certs"
  DOCKER_TLS_VERIFY: "1"
  DOCKER_CERT_PATH: "/certs/client"

build:
  stage: build
  image: docker:29.8.0-cli
  services:
    - name: docker:29.8.0-dind
      alias: docker
  script:
    - docker build -t "$DOCKER_IMAGE" .
    - docker save "$DOCKER_IMAGE" > image.tar
  artifacts:
    paths:
      - image.tar

scan:
  stage: scan
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  script:
    - trivy image --input image.tar --exit-code 1 --severity HIGH,CRITICAL

push:
  stage: push
  image: docker:29.8.0-cli
  services:
    - name: docker:29.8.0-dind
      alias: docker
  script:
    - docker load < image.tar
    - printf '%s' "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
    - docker tag "$DOCKER_IMAGE" "$DOCKERHUB_USERNAME/myapp:$CI_COMMIT_TAG"
    - docker push "$DOCKERHUB_USERNAME/myapp:$CI_COMMIT_TAG"
  only:
    - tags

Jenkins Pipeline ​

groovy
// Jenkinsfile
pipeline {
    agent any

    environment {
        DOCKERHUB_CREDENTIALS = credentials('dockerhub-creds')
        IMAGE_NAME = 'username/myapp'
    }

    stages {
        stage('Build') {
            steps {
                sh "docker build -t ${IMAGE_NAME}:${BUILD_NUMBER} ."
            }
        }

        stage('Scan') {
            steps {
                sh "trivy image --exit-code 1 --severity HIGH,CRITICAL ${IMAGE_NAME}:${BUILD_NUMBER}"
            }
        }

        stage('Push') {
            steps {
                sh 'printf "%s" "$DOCKERHUB_CREDENTIALS_PSW" | docker login -u "$DOCKERHUB_CREDENTIALS_USR" --password-stdin'
                sh "docker push ${IMAGE_NAME}:${BUILD_NUMBER}"
                sh "docker tag ${IMAGE_NAME}:${BUILD_NUMBER} ${IMAGE_NAME}:latest"
                sh "docker push ${IMAGE_NAME}:latest"
            }
        }
    }

    post {
        always {
            sh "docker logout"
        }
    }
}

모범 사례 ​

1. 보안 ​

yaml
# ✅ 권장
- Official Images 또는 Verified Publishers 사용
- 이미지 다이제스트로 고정
- 런타임에 맞는 서명·attestation 검증 정책 구성
- 정기적인 취약점 스캐닝

# ❌ 비권장
- 검증되지 않은 커뮤니티 이미지
- :latest 태그 사용
- 비밀번호 직접 사용 (Access Token 사용)

2. Rate Limit 관리 ​

yaml
# ✅ 권장
- Pro/Team 플랜 (프로덕션)
- Pull-through cache 구성
- 인증된 pull 사용

# ❌ 비권장
- 익명 pull (프로덕션)
- 캐시 없이 직접 pull

3. 저장소 관리 ​

yaml
# ✅ 권장
- 의미 있는 저장소/태그 명명
- README 및 설명 작성
- 불필요한 태그 정리

# ❌ 비권장
- 개인 정보 포함 저장소 이름
- 설명 없는 저장소
- 태그 무분별한 누적

4. 자격 증명 관리 ​

bash
# Access Token 생성 (권장)
# Docker Hub > Account Settings > Security > New Access Token

# 범위 최소화
# - CI/CD push: Read & Write
# - Kubernetes pull: Read-only

# 정기적 로테이션
# - 90일마다 토큰 갱신

요약 ​

항목권장 사항
플랜사용량·팀 권한·지원 요구에 맞는 플랜 선택
이미지Official Images, Verified Publishers
태그버전 고정, 다이제스트 사용
인증Access Token (비밀번호 대신)
Rate LimitPull-through cache, 인증된 pull
보안서명·attestation 검증, 취약점 스캐닝
CI/CDGitHub Actions 권장

참고 자료 ​