infra
Platform

모듈 맵

[Docker] 레이어 캐싱 원리와 커스텀 이미지 레지스트리 태그 전략

0 / 27 완료

펼치기
0 / 27 완료0%

도커 & 컨테이너 · 06 / 27

[Docker] 레이어 캐싱 원리와 커스텀 이미지 레지스트리 태그 전략

레이어 아키텍처를 이해하고 Docker Hub에서 이미지를 pull/push합니다

🚨INCIDENT ALERT
HIGH

아침 배포 직후 운영 서버가 어제와 다른 nginx:latest 이미지를 내려받았습니다. 코드 변경은 없었는데 컨테이너 안의 패키지 버전이 달라져 장애 원인을 재현하기 어려웠습니다.

이미지는 레이어로 저장되고 태그는 언제든 다른 이미지를 가리킬 수 있습니다. Docker Hub에서 무엇을 pull했는지, 어떤 태그를 신뢰할지, 디스크가 찰 때 무엇을 지워도 되는지 모르면 배포와 정리가 모두 위험해집니다.

Docker 이미지 구조와 Registry

Docker의 강력함은 단순히 컨테이너를 실행하는 것에 그치지 않습니다. 이미지의 레이어 아키텍처를 이해하면 왜 docker pull이 빠른지, 왜 동일 베이스 이미지를 쓰는 컨테이너들이 디스크를 공유하는지 이해할 수 있습니다. 이 챕터에서는 이미지의 내부 구조부터 레지스트리 활용까지 살펴봅니다.


이번 챕터에서 배울 것

앞 모듈에서 pull/build/tag/push 워크플로우를 익혔다면, 이번엔 이미지가 내부적으로 어떻게 저장되는지, 레지스트리 생태계를 어떻게 활용하는지 깊이 들어갑니다.

  • 1Union Filesystem(OverlayFS)과 Copy-on-Write로 레이어가 디스크에 저장되는 방식을 설명할 수 있다
  • 2Docker Hub, GitHub Container Registry(GHCR), 사설 Registry를 비교해 선택할 수 있다
  • 3이미지 다이제스트(digest)와 immutable 태그 전략으로 :latest를 쓰면 안 되는 이유를 설명할 수 있다
  • 4docker system df와 prune으로 디스크 공간을 관리할 수 있다
실습 환경 준비

push 실습은 Docker Hub 계정이 필요합니다. 계정이 없으면 pull/inspect 실습만으로도 충분합니다.

Docker 실행 중인지 확인
docker info | grep 'Server Version'
Docker Hub 계정 생성 (무료)

https://hub.docker.com — push 실습 시 필요

Docker Hub 로그인
docker login
실습용 이미지 pull
docker pull ubuntu:22.04 && docker pull alpine:3.19
💡개념

레이어 아키텍처와 UnionFS — 이미지가 저장되는 방식

docker pull로 이미지를 받을 때 줄마다 'Pull complete', 'Already exists'가 번갈아 표시됩니다. 이게 레이어입니다. 이 구조를 이해하면 왜 같은 Alpine 이미지를 기반으로 한 이미지 10개가 디스크를 중복해서 차지하지 않는지, 컨테이너를 100개 실행해도 이미지가 100배로 늘어나지 않는지 설명됩니다. Dockerfile에서 명령어 순서가 빌드 속도에 영향을 주는 이유도 레이어 캐시 구조에서 나옵니다. 이 ConceptBlock에서는 레이어가 실제 디스크에 어떻게 저장되는지와 Copy-on-Write 전략을 다룹니다.

UnionFS 레이어 아키텍처 — 읽기 전용 레이어와 컨테이너 쓰기 레이어확대

레이어(Layer)란?

Docker 이미지는 여러 개의 읽기 전용 레이어가 쌓인 구조입니다. 각 레이어는 Dockerfile의 한 명령어(RUN, COPY, ADD 등)가 만들어내는 파일시스템 변경 사항의 스냅샷입니다.

위에서 아래로 쌓인 레이어 구조입니다 (위가 최신).

  • 컨테이너 레이어 (읽기/쓰기) ← docker run 시 생성
  • 레이어 4: COPY . /app (앱 소스코드) — 읽기 전용
  • 레이어 3: RUN pip install -r requirements.txt — 읽기 전용
  • 레이어 2: RUN apt-get install python3 — 읽기 전용
  • 레이어 1: FROM ubuntu:22.04 (베이스 이미지) — 읽기 전용

각 레이어는 SHA256 해시로 식별되며, Docker는 이 해시를 사용해 레이어를 캐시하고 재사용합니다.

UnionFS와 Copy-on-Write

Docker는 OverlayFS(또는 overlay2)라는 Union 파일시스템을 사용합니다. UnionFS는 여러 디렉토리(레이어)를 하나의 가상 파일시스템으로 병합하여 보여주는 기술입니다.

컨테이너에서 파일 읽기:
  1. 최상위 쓰기 레이어 확인
  2. 없으면 아래 레이어 순서대로 탐색
  3. 처음 발견된 파일 반환

컨테이너에서 파일 수정(Copy-on-Write):
  1. 해당 파일을 하위 읽기 전용 레이어에서 쓰기 레이어로 복사
  2. 쓰기 레이어에서 파일 수정
  3. 이후 읽기 시 쓰기 레이어의 파일이 우선

레이어 공유의 장점

동일한 베이스 이미지를 사용하는 여러 이미지는 하위 레이어를 공유합니다:

레이어이미지 A (python-app)이미지 B (node-app)
4COPY python-appCOPY node-app
3pip installnpm install
2python3 설치nodejs 설치
1ubuntu:22.04ubuntu:22.04 (← 공유!)

ubuntu:22.04 레이어는 디스크에 한 번만 저장되며, 여러 이미지가 이를 공유합니다. 이는 디스크 절약과 pull 속도 향상으로 이어집니다.

OverlayFS 실제 구조 확인

Docker의 레이어는 호스트 파일시스템에서 직접 확인할 수 있습니다. overlay2 드라이버가 각 레이어를 별도 디렉토리로 관리하는 방식을 보면, 왜 동일 베이스 이미지를 쓰는 수십 개의 컨테이너가 디스크를 거의 추가로 차지하지 않는지 이해됩니다.

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/docker/part2/exam_6 && cd /tmp/docker/part2/exam_6

# overlay2 드라이버 사용 확인
docker info | grep "Storage Driver"
# Storage Driver: overlay2

# 이미지 레이어 실제 저장 위치
sudo ls /var/lib/docker/overlay2/

# 특정 이미지의 레이어 ID 확인
docker image inspect nginx --format '{{json .RootFS.Layers}}'

💡개념

Docker Hub와 이미지 태그 관리

docker pull nginx를 실행하면 이미지가 내려옵니다. 그런데 이 nginx 이미지를 누가 관리하는지, 보안 패치는 제때 이루어지는지 확인하셨나요? Docker Hub에는 공식 이미지부터 누구나 올릴 수 있는 커뮤니티 이미지까지 수백만 개가 혼재합니다. 이름만 보고 신뢰하면 악의적으로 패키징된 이미지를 내려받을 수 있고, :latest 태그를 그대로 프로덕션에 사용하면 오늘과 내일의 배포 결과가 달라지는 상황을 만납니다. "어제까지 잘 됐는데 오늘 배포만 실패한다"는 문제의 절반은 태그 관리 부재에서 비롯됩니다. 이 ConceptBlock에서는 Docker Hub 이미지 신뢰 등급과 태그 전략을 다룹니다.

Docker Hub 이미지 등급 — 공식, 검증된 퍼블리셔, 커뮤니티확대

Docker Hub 이미지 종류

Docker Hub(hub.docker.com)는 세계 최대의 컨테이너 이미지 레지스트리입니다. 이미지는 신뢰 수준에 따라 구분됩니다.

공식 이미지 (Official Images)

Docker Inc.와 해당 소프트웨어 커뮤니티가 직접 관리합니다. 이미지 이름에 슬래시(/)가 없으며 Docker Hub에서 파란 "Official Image" 배지를 확인할 수 있습니다.

로컬 터미널
# 공식 이미지 예시 (사용자명 없음)
docker pull nginx          # Nginx 공식 이미지
docker pull postgres        # PostgreSQL 공식 이미지
docker pull python          # Python 공식 이미지
docker pull node            # Node.js 공식 이미지
docker pull ubuntu          # Ubuntu 공식 이미지
docker pull alpine          # Alpine Linux 공식 이미지

검증된 퍼블리셔 이미지 (Verified Publisher)

Docker가 신원을 확인한 기업/조직이 제공합니다.

로컬 터미널
# 검증된 퍼블리셔 이미지 (조직명/이미지명)
docker pull elastic/elasticsearch:8.11.0
docker pull bitnami/postgresql:15

커뮤니티 이미지

누구나 올릴 수 있는 이미지입니다. 사용 전 반드시 Dockerfile과 관리 상태를 검토해야 합니다.

로컬 터미널
# 커뮤니티 이미지 (사용자명/이미지명)
docker pull myusername/myapp:latest

태그(Tag) 관리의 중요성

태그는 이미지의 특정 버전을 식별하는 레이블입니다. 이미지 전체 참조 형식은 다음과 같습니다:

[레지스트리호스트:포트/][사용자명/]이미지명[:태그]

예시:
  nginx                              # Docker Hub 공식, latest 태그
  nginx:1.25.3                       # Docker Hub 공식, 특정 버전
  myuser/myapp:v2.1                  # Docker Hub 커뮤니티
  registry.example.com/myapp:1.0.0  # 프라이빗 레지스트리
  gcr.io/google-containers/pause:3.9 # Google Container Registry

:latest 태그의 위험성

:latest는 고정된 버전이 아닙니다. 누군가 새 이미지를 push할 때마다 가리키는 대상이 바뀝니다.

로컬 터미널
# 위험한 패턴 — 언제 이미지가 바뀔지 모름
FROM python:latest  # ❌ 프로덕션에서 절대 금지

# 안전한 패턴 — 정확한 버전 고정
FROM python:3.11.7-slim-bookworm  # ✅ 재현 가능한 빌드

:latest는 단순히 "가장 최근에 push된 이미지"를 가리키는 일반 태그입니다. 특별한 의미가 없으며, 이미지 관리자가 새 버전을 push할 때마다 변경될 수 있습니다.

태그 전략 예시

CI/CD 파이프라인에서 이미지를 빌드할 때는 버전 번호, Git SHA, 환경명을 조합해 태그를 붙입니다.

로컬 터미널
# 시맨틱 버저닝 기반 태그 전략
docker tag myapp:latest myapp:2.1.3      # 정확한 버전
docker tag myapp:latest myapp:2.1        # 마이너 버전
docker tag myapp:latest myapp:2          # 메이저 버전
docker tag myapp:latest myapp:stable     # 안정화 채널
docker tag myapp:latest myapp:latest     # 최신 (개발용)

# Git 커밋 해시 기반 태그 (CI/CD에서 많이 사용)
GIT_SHA=$(git rev-parse --short HEAD)
docker tag myapp:latest myapp:$GIT_SHA

Alpine vs slim vs 기본 이미지

공식 이미지는 보통 여러 변형(variant)을 제공합니다:

변형특징크기
python:3.11Debian 기반, 모든 패키지 포함~900MB
python:3.11-slimDebian 기반, 최소 패키지~125MB
python:3.11-alpineAlpine Linux, musl libc~50MB

Alpine은 크기가 작지만 musl libc 사용으로 일부 Python 패키지 빌드에 문제가 생길 수 있습니다. 일반적으로 slim 변형이 크기와 호환성의 균형이 좋습니다.

이미지 레지스트리 선택 기준
오픈소스 프로젝트 또는 퍼블릭 이미지 배포가 필요할 때Docker Hub가장 널리 사용, 무료 퍼블릭 레포 무제한, 공식 이미지 접근 용이
GitHub Actions CI/CD와 연동하고 GitHub에 이미지를 함께 관리할 때GHCR (GitHub Container Registry)GitHub 토큰으로 인증, private 레포 무료, Actions 통합 간편
AWS 인프라에서 ECS/EKS를 사용하는 팀Amazon ECRIAM 기반 인증, VPC 내 빠른 pull, AWS 서비스와 네이티브 통합
온프레미스 또는 에어갭 환경에서 완전한 레지스트리 제어가 필요할 때Harbor오픈소스 셀프 호스팅, 이미지 스캔 및 접근 제어 내장
멀티 클라우드 환경에서 단일 레지스트리로 통합 관리할 때Google Artifact Registry 또는 JFrog Artifactory다양한 형식 지원, 세밀한 접근 제어, 멀티 리전 복제 가능

docker pull과 이미지 관리 기본 명령어

목표

Docker Hub에서 다양한 이미지를 pull하고, 로컬 이미지를 효율적으로 관리하는 방법을 익힙니다.

이 실습은 Docker Hub와 로컬 이미지를 다루는 순수 명령어 실습입니다. 별도 파일 생성 없이 바로 진행할 수 있습니다.

실습

1단계: 이미지 검색

실습 전 디렉토리와 예제 파일을 먼저 준비합니다.

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/docker/part1/exam_3 && cd /tmp/docker/part1/exam_3

# 이미지 태그 목록 확인용 스크립트 생성
cat > list-tags.sh << 'EOF'
#!/bin/bash
IMAGE=${1:-nginx}
echo "=== Docker Hub 이미지 태그 목록: $IMAGE ==="
curl -s "https://registry.hub.docker.com/v2/repositories/library/${IMAGE}/tags/?page_size=10" \
  | python3 -c "import sys,json; [print(t['name']) for t in json.load(sys.stdin)['results']]" 2>/dev/null \
  || echo "curl/python3 없는 환경에서는 docker search ${IMAGE} 사용"
EOF
chmod +x list-tags.sh

이제 실습을 진행합니다.

로컬 터미널
# Docker Hub에서 이미지 검색
docker search nginx

# NAME                              DESCRIPTION                      STARS   OFFICIAL
# nginx                             Official build of Nginx.          19000+  [OK]
# unit                              Official build of NGINX Unit.     108     [OK]
# ...

# 공식 이미지만 필터링
docker search --filter is-official=true nginx

# 별점 100개 이상 이미지 필터링
docker search --filter stars=100 python

2단계: 이미지 pull

특정 버전 태그나 SHA256 다이제스트로 pull하면 동일한 이미지를 재현할 수 있습니다.

로컬 터미널
# 기본 pull (latest 태그)
docker pull ubuntu

# 특정 버전 태그로 pull
docker pull ubuntu:20.04
docker pull ubuntu:22.04

# 특정 다이제스트(SHA256)로 pull (가장 안전한 방법)
docker pull ubuntu@sha256:b6b83d3c331794420340093eb706a6f152d9c1be1f6377a2e1f7b9b9a1d6e6c2

# 멀티플랫폼 이미지: 특정 아키텍처 명시
docker pull --platform linux/arm64 nginx:1.25

3단계: 로컬 이미지 목록 확인

pull한 이미지는 로컬에 캐시됩니다. 태그, ID, 크기를 확인하고 필요 없는 이미지는 정리합니다.

로컬 터미널
# 기본 목록
docker images
# REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
# ubuntu       22.04     c6b84b685f35   2 weeks ago    77.8MB
# ubuntu       20.04     1c5c8d0b973a   3 months ago   72.8MB
# nginx        latest    a6bd71f48f68   4 days ago     187MB

# 모든 이미지 (중간 레이어 포함)
docker images -a

# 특정 이미지만 필터링
docker images ubuntu

# 이미지 ID만 출력
docker images -q

# 포맷 지정 출력
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

4단계: 이미지 상세 정보 확인

로컬 터미널
# 전체 메타데이터 출력 (JSON)
docker image inspect ubuntu:22.04

# 레이어 구조만 확인
docker image inspect ubuntu:22.04 --format '{{json .RootFS.Layers}}' | python3 -m json.tool

# 환경 변수 확인
docker image inspect nginx --format '{{json .Config.Env}}'

# 노출 포트 확인
docker image inspect nginx --format '{{json .Config.ExposedPorts}}'

# 이미지 히스토리 (각 레이어 생성 명령어)
docker history nginx
# IMAGE          CREATED      CREATED BY                                      SIZE
# a6bd71f48f68   4 days ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B
# ...

5단계: 이미지 태그 추가

로컬 터미널
# 이미지에 새 태그 추가 (이미지 복사가 아닌 참조 추가)
docker tag ubuntu:22.04 my-ubuntu:latest
docker tag ubuntu:22.04 registry.mycompany.com/base/ubuntu:22.04

# 태그 확인
docker images ubuntu
docker images my-ubuntu
🔍실행 후 확인할 것
  • pull 단계 먼저: docker pull 출력에서 "Already exists"와 "Pull complete"를 구분 — Already exists는 로컬에 이미 있는 공유 레이어, Pull complete는 새로 내려받은 레이어
  • 레이어 압축률 판단: docker image inspect의 Size(바이트)와 실제 다운로드 크기를 비교 — 압축률이 원본 대비 50% 이하면 레이어 캐싱 효율 양호. 레이어가 5개 이상이고 총 크기가 1GB 넘으면 Dockerfile 최적화 검토 시점
  • Already exists + 레이어 수 조합 해석: 동일 Alpine 기반 이미지 여러 개 pull 시 하위 레이어가 Already exists이면 → 디스크 공유 동작 중. 모두 Pull complete이면 → 베이스 이미지가 달라 공유 없음

💡개념

push와 pull이 레지스트리와 주고받는 대화 — 인증부터 매니페스트 커밋까지

docker push myuser/app:1.0 한 줄에도 Layer already exists가 섞여 나오고, 마지막에 digest: sha256:...가 찍힙니다. docker pull은 이 대화를 거의 반대로 진행합니다. push/pull이 레지스트리와 어떤 단계로 주고받는지 알면 401403이 무엇이 다른지, 왜 코드 한 줄만 바꾼 재배포는 작은 레이어만 오가는지, 태그와 다이제스트가 어디서 갈리는지를 단계로 짚을 수 있습니다.

TEXT
[내 PC]  docker push myuser/app:1.0
   │
   ① 로그인·토큰 획득           (docker login → 레지스트리가 저장소 push 토큰 발급)
   │
   ② 준비: 매니페스트·레이어 목록  (로컬 이미지의 config + 레이어 digest 목록 산출)
   │
   ③ 레이어 존재 확인           (각 레이어 digest를 레지스트리에 질의)
   │    → 이미 있음: "Layer already exists" (업로드 생략)
   │    → 없음: 다음 단계로
   │
   ④ 없는 레이어만 업로드        (blob 업로드 → 레지스트리가 digest 재계산·검증)
   │
   ⑤ 매니페스트 커밋           (config + 레이어 목록을 태그 이름으로 등록 → 매니페스트 digest 확정)
   ▼
[레지스트리]  myuser/app:1.0 태그가 방금 만든 매니페스트 digest 를 가리킴

   ※ pull은 역방향: ⑤ 매니페스트 조회 → ③ 로컬에 없는 레이어 판별 → ④ 다운로드

각 단계에서 무슨 일이 일어나고, 막히면 어떤 증상인가:

단계하는 일여기서 막히면
① 로그인·토큰docker login으로 자격 증명을 넘기면 레지스트리가 해당 저장소용 토큰을 발급. 토큰에 read/write 범위가 담김로그인 안 함·토큰 만료 → 401 Unauthorized (누구인지 증명 실패)
② 준비올릴 이미지의 config와 레이어 digest 목록을 만든다. 이름이 레지스트리/계정/저장소:태그 형식이어야 함계정·레지스트리 주소 누락 → denied: requested access to the resource is denied
③ 존재 확인각 레이어 digest가 레지스트리에 이미 있는지 물어봐, 있으면 업로드를 건너뜀같은 베이스를 쓰는 재배포는 대부분 Layer already exists — 바뀐 상위 레이어만 남아 전송량 급감
④ 업로드없는 레이어 blob만 올리고, 레지스트리가 받은 내용의 digest를 다시 계산해 무결성 검증인증은 됐지만 이 저장소 쓰기 권한 없음 → 403 Forbidden / 네트워크 끊김 → 업로드 재시도
⑤ 매니페스트 커밋레이어가 다 올라간 뒤 config와 레이어 목록을 묶은 매니페스트를 태그로 등록. 이 매니페스트를 해시한 값이 이미지의 다이제스트레이어 일부 누락 상태로 커밋 → manifest blob unknown

핵심은 401403의 갈림입니다 — 401은 "누구인지 모름"(①의 로그인·토큰 문제), 403은 "누구인지는 알지만 이 저장소에 쓸 권한이 없음"(④의 권한 문제)입니다. 로그인부터 다시 할지, 권한을 받을지가 여기서 갈립니다. 태그 vs 다이제스트도 ⑤에서 갈립니다 — 태그(:1.0)는 매니페스트에 붙이는 가변 이름이라 같은 태그를 다시 push하면 새 매니페스트 digest를 가리키도록 바뀌지만, @sha256:... 다이제스트는 매니페스트 내용 그 자체의 해시라 언제나 같은 실체를 가리킵니다. 재배포가 빠른 이유는 ③에서 안 바뀐 레이어를 전부 건너뛰고 바뀐 상위 레이어와 작은 매니페스트만 오가기 때문이고, pull이 manifest unknown으로 실패하면 대칭적으로 ⑤(그 태그의 매니페스트가 레지스트리에 없음)를 의심하면 됩니다.

Docker Hub 로그인과 이미지 push

목표

Docker Hub 계정에 로그인하고, 로컬에서 빌드한 이미지를 Docker Hub에 push합니다.

사전 조건

  • Docker Hub 계정 (hub.docker.com에서 무료 가입)
  • 로컬에 빌드된 이미지

실습

1단계: Docker Hub 로그인

로컬 터미널
# 대화형 로그인
docker login

# 사용자명과 패스워드 직접 지정 (CI/CD에서 사용)
docker login -u myusername -p mypassword

# Access Token 사용 (패스워드 대신 권장)
# Docker Hub → Account Settings → Security → New Access Token
docker login -u myusername --password-stdin << EOF
dckr_pat_xxxxxxxxxxxxxxxxxxxx
EOF

# 프라이빗 레지스트리 로그인
docker login registry.mycompany.com

2단계: 간단한 이미지 빌드

로컬 터미널
# 테스트용 Dockerfile 생성
mkdir -p /tmp/myapp && cat > /tmp/myapp/Dockerfile << 'EOF'
FROM alpine:3.18
RUN echo "Hello from my custom image" > /hello.txt
CMD ["cat", "/hello.txt"]
EOF

# 이미지 빌드 (myusername을 실제 Docker Hub 계정명으로 교체)
docker build -t myusername/hello-docker:1.0 /tmp/myapp

3단계: 이미지 push

로컬 터미널
# Docker Hub에 push
docker push myusername/hello-docker:1.0

# 여러 태그 동시 push
docker tag myusername/hello-docker:1.0 myusername/hello-docker:latest
docker push myusername/hello-docker:latest

# push 결과 확인 (Docker Hub 웹사이트에서도 확인 가능)
# https://hub.docker.com/r/myusername/hello-docker

4단계: push한 이미지 확인

로컬 터미널
# 로컬 이미지 삭제
docker rmi myusername/hello-docker:1.0
docker rmi myusername/hello-docker:latest

# Docker Hub에서 다시 pull
docker pull myusername/hello-docker:1.0

# 실행 확인
docker run --rm myusername/hello-docker:1.0
# Hello from my custom image

5단계: 로그아웃

로컬 터미널
# Docker Hub 로그아웃
docker logout

# 프라이빗 레지스트리 로그아웃
docker logout registry.mycompany.com

Dangling 이미지와 디스크 공간 관리

목표

이미지 빌드와 업데이트 과정에서 쌓이는 불필요한 이미지를 정리하여 디스크 공간을 확보합니다.

Dangling 이미지란?

docker build를 반복 실행하면 이전 빌드의 이미지가 태그 없이 남습니다. 이런 이미지를 Dangling 이미지라고 합니다.

Docker
# 첫 번째 빌드
docker build -t myapp:latest .
# → myapp:latest 생성 (이미지 ID: abc123)

# 코드 수정 후 두 번째 빌드
docker build -t myapp:latest .
# → myapp:latest는 새 이미지 (ID: def456)를 가리킴
# → abc123 이미지는 태그 없이 남음 (Dangling)

# Dangling 이미지 확인
docker images -f dangling=true
# REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
# <none>       <none>    abc123...      10 minutes ago  200MB

디스크 사용량 확인 및 정리

로컬 터미널
# Docker가 사용하는 디스크 공간 전체 확인
docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          10        3         2.5GB     1.8GB (72%)
# Containers      5         2         100MB     50MB (50%)
# Local Volumes   3         2         500MB     100MB (20%)
# Build Cache     30        0         800MB     800MB

# 상세 내용 확인
docker system df -v

# Dangling 이미지만 삭제
docker image prune

# 사용하지 않는 이미지 모두 삭제 (실행 중 컨테이너와 무관한 이미지)
docker image prune -a

# 개별 이미지 삭제
docker rmi nginx:1.24     # 특정 태그 삭제
docker rmi abc123def456   # 이미지 ID로 삭제

# 사용하지 않는 이미지 한 번에 삭제 (태그 없는 것만)
docker rmi $(docker images -f "dangling=true" -q)
위험 명령어이미지·컨테이너·네트워크와 함께 볼륨 데이터까지 삭제될 수 있습니다.

Docker 리소스와 볼륨 일괄 정리

안전한 실행 조건: 실습 환경이며 삭제 대상 볼륨에 데이터베이스나 업로드 파일이 없음을 확인한 경우에만 실행합니다.

실행 전 반드시 확인

  • docker system df -v로 삭제 범위를 확인했다
  • docker volume ls로 보존해야 할 볼륨이 없는지 확인했다
  • --volumes가 데이터 삭제를 포함한다는 점을 이해했다
docker system prune -a --volumes

위 항목을 모두 확인한 후 복사할 수 있습니다

위험 명령어컨테이너가 참조 중인 이미지까지 강제로 삭제하여 재시작·재현 흐름을 깨뜨릴 수 있습니다.

참조 중인 이미지 강제 삭제

안전한 실행 조건: 이미지 ID와 참조 컨테이너를 확인했고 다시 pull 또는 build 가능한 경우에만 실행합니다.

실행 전 반드시 확인

  • docker ps -a --filter ancestor=abc123def456로 참조 컨테이너를 확인했다
  • 삭제 대상 이미지가 운영 롤백에 필요한 태그가 아님을 확인했다
  • 이미지를 다시 받을 수 있는 레지스트리 또는 Dockerfile이 있다
docker rmi -f abc123def456

위 항목을 모두 확인한 후 복사할 수 있습니다

정기적인 정리 자동화

로컬 터미널
# cron으로 매일 새벽 3시에 정리 실행 (dangling 이미지만)
# crontab -e 에 추가:
0 3 * * * docker image prune -f >> /var/log/docker-prune.log 2>&1

# 또는 사용량 임계값 기반 정리 스크립트
#!/bin/bash
THRESHOLD=80  # 디스크 사용률 80% 초과 시 정리
USAGE=$(df /var/lib/docker | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
  echo "디스크 사용률 ${USAGE}% — Docker 이미지 정리 시작"
  docker image prune -af
fi

문제 상황

로컬 터미널
$ docker pull python:3.11
Error response from daemon: failed to register layer: Error processing tar file
(exit status 1): write /usr/lib/...: no space left on device

또는

로컬 터미널
$ docker build -t myapp .
error: failed to solve: failed to create symlink ...:
no space left on device

원인 분석

Docker 이미지, 컨테이너, 볼륨, 빌드 캐시는 기본적으로 /var/lib/docker에 저장됩니다. 이 경로가 속한 파티션의 공간이 부족하면 위 에러가 발생합니다.

진단

로컬 터미널
# 전체 디스크 사용량 확인
df -h /var/lib/docker
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda1        50G   48G  1.2G  98% /

# Docker별 사용량 확인
docker system df

# 가장 큰 이미지 확인
docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -rh | head -10

해결 방법 (긴급 순서대로)

1단계: 즉시 공간 확보

로컬 터미널
# 중지된 컨테이너 모두 삭제
docker container prune -f

# Dangling 이미지 삭제
docker image prune -f

# 전체 미사용 리소스 삭제
위험 명령어BuildKit/빌더 캐시가 삭제되어 이후 이미지 빌드 시간이 크게 늘어날 수 있습니다.

빌드 캐시 강제 삭제

안전한 실행 조건: 디스크 부족 대응 중이고 캐시를 재생성해도 되는 경우에만 실행합니다.

실행 전 반드시 확인

  • docker system df로 Build Cache 용량을 확인했다
  • 현재 진행 중인 빌드가 없음을 확인했다
  • 다음 빌드에서 캐시 미스로 시간이 늘어날 수 있음을 이해했다
docker builder prune -af

위 항목을 모두 확인한 후 복사할 수 있습니다

위험 명령어확인 프롬프트 없이 미사용 이미지·컨테이너·네트워크·빌드 캐시를 삭제합니다.

전체 미사용 Docker 리소스 강제 정리

안전한 실행 조건: 디스크 부족 대응 중이며 삭제 범위를 먼저 확인한 경우에만 실행합니다.

실행 전 반드시 확인

  • docker system df로 Docker 디스크 사용량을 확인했다
  • 실행 중인 컨테이너에서 사용하는 이미지는 삭제되지 않는다는 범위를 이해했다
  • 필요한 로컬 빌드 이미지가 다시 빌드 또는 pull 가능하다
docker system prune -af

위 항목을 모두 확인한 후 복사할 수 있습니다

2단계: Docker 데이터 경로 변경 (근본 해결)

파티션 자체가 작다면 더 큰 파티션으로 Docker 데이터를 이동합니다.

로컬 터미널
# Docker 데몬 설정 파일 편집
sudo nano /etc/docker/daemon.json

# 다음 내용 추가 (새 데이터 경로)
{
  "data-root": "/data/docker"
}

# 새 디렉토리에 기존 데이터 복사
sudo systemctl stop docker
sudo mkdir -p /data/docker
sudo rsync -aP /var/lib/docker/ /data/docker/

# Docker 재시작
sudo systemctl start docker

# 확인
docker info | grep "Docker Root Dir"

3단계: .dockerignore로 빌드 컨텍스트 크기 감소

빌드 컨텍스트가 크면 Docker 데몬에 불필요한 파일까지 전송되어 시간과 공간을 낭비합니다. .dockerignore로 제외할 파일을 명시합니다.

로컬 터미널
# 빌드 컨텍스트 크기 확인 (build 시 "Sending build context" 메시지)
# Sending build context to Docker daemon  500MB   ← 너무 크면 문제

# .dockerignore 파일 생성
cat > .dockerignore << 'EOF'
node_modules
.git
*.log
dist
coverage
.env
*.md
.DS_Store
EOF

문제 상황

로컬 터미널
$ docker pull myapp:production
Error response from daemon: manifest for myapp:production not found:
manifest unknown: manifest unknown

또는

로컬 터미널
$ docker pull mycompany/myapp:v2.5
Error response from daemon: pull access denied for mycompany/myapp,
repository does not exist or may require 'docker login'

원인 분석

에러 메시지원인
manifest unknown지정한 태그가 레지스트리에 없음
pull access denied인증 필요(private 이미지) 또는 이미지 자체가 없음
repository does not exist이미지 이름 오타

해결 방법

태그 오타 확인

로컬 또는 서버
# Docker Hub에서 사용 가능한 태그 목록 확인 (API 사용)
curl -s "https://hub.docker.com/v2/repositories/library/python/tags/?page_size=20" \
  | python3 -m json.tool | grep '"name"'

# 또는 웹 브라우저에서 확인
# https://hub.docker.com/_/python/tags

Private 레지스트리 인증

로컬 터미널
# 로그인 후 재시도
docker login registry.mycompany.com
docker pull registry.mycompany.com/myapp:v2.5

아키텍처 불일치 확인

로컬 터미널
# ARM64 호스트에서 AMD64 전용 이미지 pull 시도 시 에러
# --platform으로 명시적 지정
docker pull --platform linux/amd64 myapp:v2.5

로컬에서 이미지 존재 여부 확인

로컬 터미널
# 로컬 이미지 중 특정 이름 검색
docker images | grep myapp

# 이미지가 로컬에 있는지 확인 후 pull
docker image inspect myapp:v2.5 2>/dev/null && echo "로컬에 존재" || echo "pull 필요"

심화 — 레지스트리는 콘텐츠 주소 저장소다

💡개념

심화: 하나의 태그가 여러 이미지를 가리킨다 — 매니페스트와 멀티아치

docker pull nginx가 하는 일을 '이미지 파일 하나를 통째로 내려받는 것'으로 이해하면, 아키텍처 불일치 같은 함정 앞에서 막힙니다. 레지스트리가 이미지를 어떻게 쪼개 보관하는지 보면 태그 뒤에 숨은 구조가 드러납니다.

  • 이미지 = 매니페스트 + blob: 레지스트리는 콘텐츠 주소(content-addressable) 저장소입니다. 이미지는 매니페스트(설정과 레이어 다이제스트 목록)와 blob(실제 레이어 데이터)으로 나뉘어 저장됩니다. pull은 매니페스트를 먼저 받고, 로컬에 없는 레이어 blob만 내려받습니다. push도 마찬가지라, 레지스트리에 이미 있는 레이어는 Layer already exists로 건너뜁니다 — 그래서 코드 한 줄만 바꾼 재배포는 작은 상위 레이어만 오갑니다.
  • 태그는 매니페스트 리스트일 수 있다: nginx 같은 태그는 흔히 단일 이미지가 아니라 매니페스트 리스트(멀티아치 index) 를 가리킵니다. 그 안에 linux/amd64, linux/arm64 등 아키텍처별 이미지가 묶여 있고, pull하는 클라이언트가 자기 아키텍처에 맞는 매니페스트를 골라 받습니다. 그래서 같은 태그라도 x86 서버와 Apple Silicon 맥에서 다른 실체가 내려옵니다.
  • 다이제스트는 그 실체를 불변으로 고정한다: 태그는 사람이 붙인 가변 이름이라 같은 태그에 다른 이미지가 다시 push될 수 있지만, @sha256:... 다이제스트는 매니페스트 내용을 해시한 값이라 항상 정확히 그 실체를 가리킵니다. 멀티아치 태그를 다이제스트로 핀하면 특정 아키텍처의 특정 이미지까지 못 박을 수 있습니다.

이 구조를 알면 "push가 왜 빠른가", "같은 태그인데 왜 서버마다 다른 게 받아지나"가 한 번에 설명됩니다.

상황: Apple Silicon(arm64) 맥에서 docker build로 이미지를 만들어 레지스트리에 푸시했습니다. 그런데 amd64 운영 서버에서 그 이미지를 pull해 실행하니 exec format error가 나거나, 컨테이너가 아무 로그도 없이 즉시 종료됩니다. 맥에서는 잘 돌던 이미지라 더 당황스럽습니다.

원인: exec format error는 CPU 아키텍처가 맞지 않는 바이너리를 실행하려 할 때 커널이 내는 오류입니다. arm64 맥에서 아무 옵션 없이 빌드하면 arm64 전용 이미지가 만들어지는데, 이를 amd64 서버에서 실행하면 명령어 집합이 달라 바이너리가 돌지 않습니다. 태그는 하나였지만 그 안에 amd64용 이미지가 없었던 것입니다.

진단: docker inspect --format '{{.Architecture}} {{.Os}}' <image>로 이미지의 아키텍처를 확인합니다. arm64로 찍히는데 서버는 x86_64(uname -m)라면 불일치가 확정입니다. 레지스트리의 매니페스트를 docker buildx imagetools inspect <image>로 보면 어떤 플랫폼이 들어 있는지 목록으로 나옵니다.

해결: docker buildx build --platform linux/amd64,linux/arm64 --push멀티아치 이미지를 만들어 매니페스트 리스트로 푸시하면, 서버는 자기 아키텍처(amd64)에 맞는 이미지를 자동으로 받습니다. 배포 대상이 amd64 하나뿐이라면 최소한 --platform linux/amd64로 빌드해 아키텍처를 맞춥니다. 로컬에서 급히 확인만 할 때는 실행 측에서 --platform으로 강제할 수 있지만, 이 경우 QEMU 에뮬레이션으로 느려질 수 있으니 운영 이미지는 대상 아키텍처로 실제 빌드하는 것이 원칙입니다.


💼
실무 맥락
현업 패턴

엔터프라이즈 이미지 관리 체계

현업에서는 Docker Hub 공개 이미지를 그대로 프로덕션에서 사용하지 않고, 조직 내부 레지스트리를 통해 관리합니다.

프라이빗 레지스트리 구성

많은 기업들이 다음 중 하나를 사용합니다:

레지스트리특징적합 환경
Docker Hub (private)가장 간단소규모 팀
AWS ECRAWS 통합AWS 인프라
Google Artifact RegistryGCP 통합GCP 인프라
Harbor오픈소스 자체 호스팅온프레미스
GitLab Container RegistryGitLab 통합GitLab 사용 조직

이미지 보안 스캐닝

외부 이미지를 프로덕션에 그대로 올리면 알려진 CVE를 함께 배포하는 셈입니다. 빌드 단계에서 취약점을 자동으로 검사합니다.

로컬 터미널
# Docker Scout (Docker 공식 보안 스캐닝)
docker scout cves nginx:1.25.3

# Trivy (오픈소스 취약점 스캐너)
trivy image nginx:1.25.3

# 취약점 발견 시 자동으로 빌드 실패시키는 CI/CD 설정 예시
# .github/workflows/security.yml

이미지 라이프사이클 정책

실제 팀에서는 이미지 버전을 언제 삭제할지 정책을 수립합니다:

CI/CD에서의 이미지 빌드와 push

코드가 main 브랜치에 머지될 때마다 이미지를 자동으로 빌드하고 레지스트리에 올리는 것이 표준 패턴입니다. 커밋 SHA를 태그로 쓰면 배포 이력을 그대로 추적할 수 있습니다.

YAML
# GitHub Actions 예시: 코드 push 시 이미지 빌드 및 push
name: Build and Push
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2
      - name: Build and push
        run: |
          IMAGE_TAG=${{ github.sha }}
          docker build -t $ECR_REGISTRY/myapp:$IMAGE_TAG .
          docker push $ECR_REGISTRY/myapp:$IMAGE_TAG
          # main 브랜치는 latest도 함께 태그
          docker tag $ECR_REGISTRY/myapp:$IMAGE_TAG $ECR_REGISTRY/myapp:latest
          docker push $ECR_REGISTRY/myapp:latest

이러한 전략들은 애플리케이션 배포의 안정성과 재현성을 보장하며, 보안 취약점을 조기에 발견할 수 있게 합니다.


💡개념

이미지 이름의 완전한 구조 — registry/namespace/repo:tag@digest

로컬에서 docker build -t myapp:1.0 .으로 이미지를 만든 뒤 docker push myapp:1.0을 실행하면 "denied: access forbidden" 에러가 납니다. 회사 ECR이나 사설 레지스트리에 올리려면 이미지 이름 앞에 레지스트리 주소가 포함되어야 하는데, myapp:1.0은 Docker Hub의 개인 계정을 가정하기 때문입니다. 또 nginx라는 이름은 실제로는 docker.io/library/nginx:latest가 생략된 형태이고, AWS ECR 이미지는 123456.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:latest처럼 보입니다. 이 규칙을 모르면 push 실패, pull 실패, 이미지 이름 혼동이 반복됩니다. 이 ConceptBlock에서는 이미지 이름의 전체 구성과 다이제스트로 불변성을 보장하는 방법을 다룹니다.

이미지 이름 전체 구조 — registry/namespace/repo:tag@digest확대

이미지 이름의 전체 형식

Docker 이미지 이름은 여러 부분으로 구성되며, 생략 시 기본값이 채워집니다.

전체 형식:
[레지스트리호스트[:포트]/][네임스페이스/]저장소[:태그][@다이제스트]

예시:
docker.io/library/nginx:1.25@sha256:abc123...def456
    ↑          ↑       ↑      ↑          ↑
 레지스트리  네임스페이스 저장소  태그     다이제스트
로컬 터미널
# 생략 시 기본값 채우기
nginx                = docker.io/library/nginx:latest
nginx:alpine         = docker.io/library/nginx:alpine
myuser/myapp         = docker.io/myuser/myapp:latest
myuser/myapp:v1.0    = docker.io/myuser/myapp:v1.0

# 다른 레지스트리 사용
ghcr.io/myorg/myapp:latest          # GitHub Container Registry
123456.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:latest  # AWS ECR
asia-northeast1-docker.pkg.dev/project/repo/myapp:latest  # GCP Artifact Registry
myregistry.internal:5000/myapp:v2   # 사설 레지스트리

태그 vs 다이제스트 — 가변 vs 불변

태그는 편하지만 언제든 덮어쓸 수 있어 재현성이 깨질 수 있습니다. 다이제스트는 SHA256 해시이므로 항상 동일한 이미지를 가리킵니다.

로컬 터미널
# 태그: 가변 (같은 태그가 언제든 다른 이미지를 가리킬 수 있음)
docker pull nginx:latest
# 오늘의 latest와 내일의 latest가 다를 수 있음!

# 다이제스트: 불변 (SHA256 해시, 항상 동일한 이미지 보장)
docker pull nginx@sha256:a0bcfe...8d12c
# 언제 어디서 pull해도 완전히 동일한 이미지

# 현재 이미지의 다이제스트 확인
docker image inspect nginx:latest --format '{{.RepoDigests}}'
# [nginx@sha256:a0bcfe...8d12c]

# 다이제스트로 pull (프로덕션 환경 권장)
docker pull nginx@sha256:a0bcfe...8d12c

사설 레지스트리 이미지 관리

로컬에서 빌드한 이미지를 사설 레지스트리에 push할 때는 이미지 이름에 레지스트리 주소를 포함한 태그를 먼저 추가합니다.

로컬 터미널
# 로컬에서 빌드한 이미지를 사설 레지스트리에 push
# 1. 이미지에 레지스트리 주소 포함한 태그 추가
docker tag myapp:latest myregistry.example.com:5000/myapp:latest
docker tag myapp:latest myregistry.example.com:5000/myapp:v1.2.3

# 2. 레지스트리에 push
docker push myregistry.example.com:5000/myapp:latest
docker push myregistry.example.com:5000/myapp:v1.2.3

# 3. 다른 서버에서 pull
docker pull myregistry.example.com:5000/myapp:v1.2.3

# 4. 이미지 목록 API 확인
curl http://myregistry.example.com:5000/v2/_catalog
# {"repositories":["myapp","nginx","redis"]}
curl http://myregistry.example.com:5000/v2/myapp/tags/list
# {"name":"myapp","tags":["latest","v1.2.3","v1.2.2"]}

💡개념

이미지 정리와 디스크 관리 — docker system df와 prune

CI 빌드 서버를 3개월째 운영하다 보면 어느 날 아침 파이프라인 전체가 멈춥니다. docker build 도중 "no space left on device" 에러가 납니다. 원인은 매번 빌드할 때마다 생성되는 dangling 이미지가 아무도 정리하지 않은 채 쌓인 것입니다. 개발 노트북에서도 Docker를 몇 달 쓰면 디스크 수 GB가 Docker 이미지와 빌드 캐시로 채워집니다. docker system df를 처음 실행했을 때 "회수 가능 공간 3.1GB"가 표시되면 당황하기 마련입니다. 정리 명령어는 여러 종류가 있고 영향 범위가 다르므로, 순서와 범위를 알고 써야 실수로 운영 데이터를 지우는 사고를 막을 수 있습니다. 이 ConceptBlock에서는 Docker 디스크 사용량을 파악하고 안전하게 정리하는 방법을 다룹니다.

이미지 정리 순서 — dangling, 미사용, 전체 prune 범위확대

디스크 사용량 파악

Docker를 오래 사용하면 이미지, 컨테이너, 볼륨, 빌드 캐시가 쌓여 디스크를 차지합니다.

로컬 터미널
# Docker 전체 디스크 사용량 확인
docker system df
# TYPE            TOTAL   ACTIVE  SIZE      RECLAIMABLE
# Images          12      3       4.2GB     3.1GB (73%)  ← 회수 가능
# Containers      5       2       12MB      1kB (0%)
# Local Volumes   8       3       2.1GB     800MB (38%)
# Build Cache     23      0       1.5GB     1.5GB        ← 전부 회수 가능

# 상세 목록
docker system df -v

dangling 이미지가 생기는 이유

Docker
# 같은 태그로 재빌드하면 이전 이미지가 <none>:<none> 으로 남음
docker build -t myapp:latest .   # 첫 번째 빌드 → abc123
docker build -t myapp:latest .   # 재빌드 → def456 (새 이미지)
                                  # abc123은 태그를 잃고 <none>:<none>으로 전락

docker images
# REPOSITORY   TAG       IMAGE ID       SIZE
# myapp        latest    def456         200MB  ← 현재 이미지
# <none>       <none>    abc123         200MB  ← dangling 이미지!

단계별 정리 방법

영향 범위가 작은 것부터 순서대로 실행합니다. 운영 환경에서는 prune -a--volumes 사용 전에 반드시 어떤 데이터가 삭제되는지 확인해야 합니다.

로컬 터미널
# 1. dangling 이미지만 삭제 (가장 안전)
docker image prune
# WARNING! This will remove all dangling images.
# 삭제할 공간: 1.2GB

# 2. 사용 중이지 않은 이미지 전체 삭제
docker image prune -a
# 실행 중인 컨테이너에서 사용 중인 이미지는 삭제 안 됨

# 3. 미사용 컨테이너 삭제
docker container prune

# 4. 미사용 볼륨 삭제 (주의: 데이터 영구 삭제!)

# 5. 한 번에 전체 정리
위험 명령어미사용 볼륨 데이터가 영구 삭제되어 데이터베이스나 업로드 파일을 잃을 수 있습니다.

볼륨 포함 Docker 전체 정리

안전한 실행 조건: 삭제 대상이 실습/임시 리소스뿐이고 볼륨 백업이 끝난 경우에만 실행합니다.

실행 전 반드시 확인

  • docker volume ls -f dangling=true로 삭제 후보 볼륨을 확인했다
  • 볼륨 이름과 용도를 확인했다
  • 보존할 데이터의 백업 또는 재생성 방법이 있다
docker system prune -a --volumes

위 항목을 모두 확인한 후 복사할 수 있습니다

자동 정리 설정

--filter 옵션으로 기간이나 라벨을 지정하면 원하는 범위만 정리할 수 있습니다. CI 빌드 서버에는 cron으로 등록해 두면 디스크가 차는 것을 예방할 수 있습니다.

로컬 터미널
# 특정 날짜 이전 이미지만 삭제
docker image prune -a --filter "until=72h"  # 72시간 이상 미사용

# 특정 라벨이 있는 이미지만 삭제
docker image prune --filter "label=stage=dev"

# cron으로 주기적 자동 정리 (매주 일요일 새벽 3시)

정리

핵심 명령어 요약

이 모듈에서 다룬 이미지 관련 명령어를 한 곳에 정리합니다.

로컬 터미널
# 이미지 pull
docker pull ubuntu:22.04

# 로컬 이미지 목록
docker images
docker images -a            # 중간 레이어 포함

# 이미지 상세 확인
docker image inspect ubuntu:22.04
docker history nginx

# 태그 추가
docker tag myapp:1.0 registry.example.com/myapp:1.0

# Docker Hub 로그인/push
docker login
docker push myuser/myapp:1.0

# 이미지 삭제 및 정리
docker rmi nginx:old
docker image prune           # dangling만
docker image prune -a        # 미사용 전체
docker system df             # 디스크 사용량 확인

명령어·단축키 빠른 참조

이 모듈에서 다룬 이미지 pull·검사·태그·정리 명령을 실전 옵션과 함께 모았습니다.

명령어/단축키용도자주 쓰는 예
docker pull태그·다이제스트·플랫폼 지정 내려받기docker pull ubuntu:22.04 / docker pull --platform linux/arm64 nginx:1.25
docker searchDocker Hub 이미지 검색·필터docker search --filter is-official=true nginx / --filter stars=100 python
docker images로컬 이미지 목록·필터docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" / -f dangling=true
docker image inspect레이어·환경·다이제스트 확인docker image inspect nginx --format '{{.RepoDigests}}'
docker history레이어별 생성 명령·크기 보기docker history nginx
docker tag레지스트리 주소 포함 태그 부여docker tag myapp:1.0 registry.example.com/myapp:1.0
docker login / push인증 후 이미지 업로드echo "$PW" | docker login -u user --password-stdindocker push user/app:1.0
docker system dfDocker 디스크 사용·회수 가능량docker system df -v
docker image prunedangling/미사용 이미지 정리docker image prune / docker image prune -a --filter "until=72h"
docker rmi특정 이미지·태그 삭제docker rmi nginx:old / docker rmi $(docker images -f dangling=true -q)
docker info스토리지 드라이버·데이터 경로 확인docker info | grep "Storage Driver"

관련 모듈로 더 깊이:

다음 챕터 예고

다음 모듈에서는 직접 Dockerfile을 작성하여 애플리케이션 이미지를 빌드하는 방법을 학습합니다. FROM, RUN, COPY, CMD 등 핵심 명령어와 레이어 캐시 최적화를 통해 빠르고 작은 이미지를 만드는 기술을 다룹니다.

지식 확인

퀴즈 — 8문제

Q1

Docker 이미지의 레이어(Layer) 아키텍처에서 Copy-on-Write(CoW) 전략이 의미하는 것은?

Q2

Docker Hub에서 이미지를 사용할 때 `:latest` 태그를 프로덕션에서 사용하면 안 되는 이유는?

Q3

`docker image prune -a` 명령어는 어떤 이미지를 삭제하나요?

Q4

동일한 이미지 내용이지만 여러 레지스트리에 push하기 위해 이미지에 새 태그를 붙이는 올바른 명령어는?

Q5

Docker Hub의 공식(Official) 이미지와 검증된(Verified Publisher) 이미지의 차이점은?

Q6

프로덕션에서 'nginx:1.25' 같은 태그 대신 'nginx@sha256:abcd...' 형태의 다이제스트(digest)로 이미지를 지정하면 좋은 점은?

Q7

[심화] docker pull nginx 를 x86 서버와 Apple Silicon 맥에서 각각 받으면 같은 태그인데도 서로 다른 이미지가 내려온다. 이를 가능하게 하는 레지스트리 구조는?

Q8

[심화] Apple Silicon(arm64) 맥에서 빌드해 푸시한 이미지를 amd64 운영 서버에서 실행하니 exec format error 가 나거나 컨테이너가 즉시 죽는다. 원인과 해결로 옳은 것은?

0 / 8 답변

🧪 실습으로 확인하기

Docker Compose 멀티 서비스 구성

초급

docker-compose.yml로 nginx + 앱 컨테이너를 함께 정의하고, 서비스 간 통신과 볼륨 마운트를 구성한다.

35📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요