infra
Platform

모듈 맵

[Docker] 사용하지 않는 이미지 정리와 최적의 태그 아카이빙 전략

0 / 27 완료

펼치기
0 / 27 완료0%

Docker · 08 / 27

[Docker] 사용하지 않는 이미지 정리와 최적의 태그 아카이빙 전략

디스크 가득 찬 CI 서버를 살리는 이미지 정리 기술, 롤백 가능한 태그 전략, 폐쇄망 아카이빙까지 실무 이미지 운영 전체를 다룹니다

🚨INCIDENT ALERT
HIGH

새벽 3시 22분, CI 서버에서 빌드 파이프라인이 멈췄다는 알림이 왔습니다. 에러 메시지는 no space left on device 한 줄뿐이었습니다.

빌드마다 생긴 이미지와 캐시가 정리되지 않은 채 쌓였고, 50GB 디스크는 조용히 가득 찼습니다. 어떤 이미지를 지워도 되는지, 어떤 태그로 롤백할 수 있는지, 폐쇄망에는 이미지를 어떻게 옮길지 정해두지 않으면 이미지도 운영 장애의 원인이 됩니다.

Docker 이미지 운영 — 정리·태그 전략·아카이빙

새벽 3시 22분, 슬랙 알림이 울렸습니다. CI 서버에서 빌드 파이프라인이 죽었습니다. 에러 메시지는 딱 한 줄이었습니다 — no space left on device. 빌드마다 생성되던 이미지들이 정리되지 않은 채 쌓였고, 50GB 디스크는 조용히 가득 찼습니다. 로그는 못 쓰고, 새 이미지는 빌드가 안 되고, 서비스 배포는 전면 중단이었습니다. 이 상황을 겪고 나서야 "이미지 운영"이 개발만큼 중요하다는 걸 알게 됩니다. 이미지를 어떻게 쌓이게 둘 것인지, 어떤 기준으로 지울 것인지, 태그는 어떻게 관리할 것인지 — 이 챕터는 그 실무를 다룹니다.


이번 챕터에서 배울 것

CI 서버 디스크가 꽉 차거나 롤백이 안 되는 상황을 예방하는 실무 이미지 운영 기술을 익힙니다. 정리·태그·아카이빙 세 축을 모두 다룹니다.

  • 1docker system df와 docker system df -v로 Docker 디스크 사용 구조 파악
  • 2dangling 이미지 vs unused 이미지의 차이 — prune과 prune -a 영향 범위
  • 3안전한 정리 순서 — image → volume → system, 데이터 손실 없이 공간 회수
  • 4이미지 태그 전략 — latest 금지, git SHA + 날짜 조합, immutable tag 원칙
  • 5CI cron 자동 정리 — docker image prune --filter until=72h 설정
  • 6docker save / load로 이미지 아카이빙 — 폐쇄망 전달과 백업
실습 환경 준비

이미 Docker를 사용 중인 환경이라면 system df 출력에서 실제 사용량을 바로 확인할 수 있습니다. 이미지가 없는 깨끗한 환경이라면 실습용 이미지 pull 단계를 먼저 진행하세요.

Docker 버전 확인 (20.10 이상 권장)
docker --version
현재 디스크 사용 상태 미리 확인
docker system df
실습용 이미지 여러 개 pull (dangling 이미지 실습 준비)
docker pull nginx:1.24 && docker pull nginx:1.25 && docker pull alpine:3.18
실습용 디렉토리 생성
mkdir -p ~/image-ops-lab && cd ~/image-ops-lab
실습 후 정리 명령어 (실습 완료 후 사용)

docker system prune -a --volumes -f

💡개념

docker system df — 디스크 사용 구조를 한눈에 파악하기

CI 서버 디스크가 갑자기 꽉 찼습니다. 어디서 공간을 잡아먹고 있는지 모른 채 무작정 파일을 지우면 실행 중인 컨테이너나 중요한 볼륨 데이터까지 날릴 수 있습니다. docker system df는 Docker가 사용하는 공간을 유형별로 정리해서 보여주는 진단 명령입니다. 먼저 전체 그림을 파악하고, 그다음 어디를 정리할지 판단해야 안전합니다. 이 ConceptBlock에서는 docker system df-v 플래그의 출력을 읽는 방법과 각 항목의 의미를 다룹니다.

docker system df — 이미지, 컨테이너, 볼륨, 빌드 캐시 사용량

docker system df 기본 출력 읽기

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

docker system df

출력 예시:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          23        4         8.2GB     6.1GB (74%)
Containers      7         2         124MB     98MB (79%)
Local Volumes   5         3         2.3GB     800MB (34%)
Build Cache     -         -         1.1GB     1.1GB

각 컬럼의 의미:

컬럼의미
TOTALDocker가 알고 있는 전체 수량
ACTIVE현재 실행 중인 컨테이너에서 사용 중인 수량
SIZE해당 유형이 차지하는 디스크 크기
RECLAIMABLE지금 당장 정리해도 안전한 공간 (괄호 안은 비율)

RECLAIMABLE이 높을수록 정리 효과가 크고 위험도는 낮습니다. 위 예시에서는 이미지에서만 6.1GB를 회수할 수 있습니다.

docker system df -v — 항목별 상세 조회

로컬 터미널
docker system df -v

출력 예시 (일부):

Images space usage:

REPOSITORY    TAG       IMAGE ID       CREATED        SIZE      SHARED SIZE   UNIQUE SIZE   CONTAINERS
nginx         1.25      a6bd71249a7e   2 weeks ago    187MB     72.8MB        114MB         0
nginx         1.24      a8758716bb6a   4 months ago   187MB     72.8MB        114MB         0
<none>        <none>    d1a364dc548d   3 days ago     187MB     72.8MB        114MB         0
alpine        3.18      c1afedef4846   1 month ago    7.34MB    0B            7.34MB        0

Containers space usage:
...

Local Volumes space usage:
...

<none>:<none> 항목이 dangling 이미지입니다. TAG도 없고 REPOSITORY도 없으며 CONTAINERS가 0입니다. 이것들이 가장 먼저 정리할 대상입니다.

-v 출력에서 확인할 핵심 정보:

  • CONTAINERS 컬럼이 0인 이미지 — 어떤 컨테이너도 이 이미지를 사용하지 않음
  • UNIQUE SIZE — 이 이미지만 차지하는 고유 레이어 크기 (삭제 시 실제 회수량)
  • SHARED SIZE — 다른 이미지와 공유하는 레이어 크기 (삭제해도 회수 안 됨)
🔍실행 후 확인할 것
  • docker system df 출력에서 Images, Containers, Local Volumes, Build Cache 항목을 구분했는가?
  • RECLAIMABLE 컬럼에서 지금 회수 가능한 공간을 확인했는가?
  • docker system df -v 출력에서 <none>:<none> dangling 이미지를 찾을 수 있는가?
  • CONTAINERS 컬럼이 0인 이미지와 사용 중인 이미지를 구분했는가?

실습: dangling 이미지 vs unused 이미지 — prune 영향 범위 직접 확인

dangling 이미지와 unused 이미지를 혼동하면 필요한 이미지까지 지우거나, 반대로 지워야 할 이미지를 남길 수 있습니다. 차이를 직접 만들어보고 prune이 각각 어떻게 동작하는지 확인합니다.

dangling 이미지 만들기

동일한 태그로 새 이미지를 빌드하거나 pull하면 이전 이미지는 태그가 떨어져 나가면서 dangling 상태가 됩니다.

로컬 터미널
# 임시 Dockerfile 생성
cat > /tmp/Dockerfile.test << 'EOF'
FROM alpine:3.18
RUN echo "version 1" > /version.txt
EOF

# 같은 태그로 두 번 빌드 — 첫 번째 이미지가 dangling이 됨
docker build -t test-dangling:latest -f /tmp/Dockerfile.test /tmp
docker build -t test-dangling:latest --no-cache -f /tmp/Dockerfile.test /tmp

# dangling 이미지 확인 (TAG가 <none>인 항목)
docker images -f dangling=true
# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# <none>       <none>    a1b2c3d4e5f6   10 seconds ago   7.5MB

docker image prune — dangling만 삭제

로컬 터미널
# dangling 이미지만 삭제 (태그 있는 이미지는 건드리지 않음)
docker image prune -f

# 출력:
# Deleted Images:
# deleted: sha256:a1b2c3d4e5f6...
# Total reclaimed space: 7.5MB

prune 단독 실행은 안전합니다. 태그가 붙어 있는 이미지는 하나도 삭제되지 않습니다.

docker image prune -a — unused 이미지 전체 삭제

로컬 터미널
# 현재 컨테이너에서 사용 중이지 않은 이미지를 모두 삭제
# (태그 있어도 사용 중인 컨테이너가 없으면 삭제됨)
docker image prune -a -f

# 출력:
# Deleted Images:
# untagged: nginx:1.24
# deleted: sha256:a8758716bb6a...
# untagged: nginx:1.25
# deleted: sha256:a6bd71249a7e...
# Total reclaimed space: 6.1GB

-a는 강력하지만 다음 빌드 시 베이스 이미지를 다시 pull해야 하는 비용이 생깁니다. CI 서버에서는 유용하지만 개발 머신에서는 신중하게 사용해야 합니다.

두 명령의 차이 정리

명령어삭제 대상태그 있는 이미지사용 중 이미지
docker image prunedangling 이미지만건드리지 않음건드리지 않음
docker image prune -a사용 중이지 않은 모든 이미지삭제됨건드리지 않음

두 경우 모두 현재 실행 중이거나 중지된 컨테이너에서 사용 중인 이미지는 삭제하지 않습니다.


💡개념

안전한 정리 순서 — 데이터 손실 없이 공간 회수하기

docker system prune -a --volumes를 한 번에 실행하면 가장 많은 공간을 회수할 수 있습니다. 하지만 이 명령은 볼륨 데이터까지 삭제합니다. 데이터베이스 볼륨이 포함되어 있다면 데이터 전체를 잃을 수 있습니다. 안전한 정리는 단계적으로 진행하고, 각 단계에서 무엇이 사라지는지 확인한 다음 넘어가야 합니다. 이 ConceptBlock에서는 위험도가 낮은 순서부터 정리하는 4단계 전략을 다룹니다.

안전한 정리 순서 — 이미지 → 컨테이너 → 볼륨 단계별 접근

1단계: 이미지 정리 (가장 안전)

로컬 터미널
# dangling 이미지만 삭제 (가장 안전)
docker image prune -f

# 72시간 이상 된 미사용 이미지 삭제 (필터 활용)
docker image prune -a -f --filter "until=72h"

이미지는 컨테이너가 삭제된 뒤에도 남는 캐시 역할을 합니다. 정리해도 필요하면 다시 pull할 수 있어 위험도가 낮습니다.

2단계: 중지된 컨테이너 정리

로컬 터미널
# 중지된 컨테이너 목록 확인
docker ps -a --filter status=exited

# 중지된 컨테이너 모두 삭제
docker container prune -f

실행 중인 컨테이너는 건드리지 않습니다. 중지된 컨테이너의 로그와 파일시스템 레이어만 삭제됩니다.

3단계: 사용하지 않는 볼륨 정리 (신중하게)

로컬 터미널
# 어떤 컨테이너에도 연결되지 않은 볼륨 목록 확인 (먼저 확인!)
docker volume ls -f dangling=true

# 볼륨 이름과 용도를 파악한 뒤 삭제 결정

볼륨 정리는 가장 위험한 단계입니다. 데이터베이스 볼륨, 업로드 파일 볼륨이 포함될 수 있습니다. 반드시 docker volume ls -f dangling=true로 목록을 확인하고, 용도를 파악한 뒤 삭제하세요.

4단계: 빌드 캐시 정리

Docker
# 빌드 캐시만 삭제 (이미지/컨테이너/볼륨은 건드리지 않음)
docker builder prune -f

# 24시간 이상 된 빌드 캐시만 삭제
docker builder prune --filter "until=24h" -f

한 번에 정리할 때 — system prune

--volumes 플래그는 명시적으로 지정해야만 볼륨을 삭제합니다. 프로덕션 서버나 개발 DB 볼륨이 있는 환경에서는 절대 -a --volumes를 무심코 실행하지 마세요.

정리 단계별 위험도 요약

단계명령어위험도복구 가능 여부
이미지docker image prune낮음가능 (재pull)
이미지 전체docker image prune -a낮음가능 (재pull)
컨테이너docker container prune낮음불가 (로그 손실 가능)
볼륨docker volume prune높음불가 (데이터 영구 삭제)
전체docker system prune -a --volumes매우 높음불가

실습: 이미지 태그 전략 — latest 금지, immutable tag 설계

태그 전략이 없으면 롤백이 불가능해집니다. 새 버전이 배포된 뒤 latest만 있다면 이전 버전을 찾을 방법이 없습니다.

latest 태그의 문제

Docker
# CI에서 매 빌드마다 latest로 push하는 잘못된 패턴
docker build -t myapp:latest .
docker push myapp:latest

# 문제: 오늘의 latest와 어제의 latest는 다른 이미지
# docker pull myapp:latest  ← 항상 가장 최신 이미지를 가져옴
# 특정 시점으로 롤백하려면 어떤 이미지인지 알 수가 없음

git SHA + 날짜 조합 태그 — immutable tag

로컬 터미널
# git SHA 추출 (단축 7자리)
GIT_SHA=$(git rev-parse --short HEAD)

# 날짜 (YYYYMMDD 형식)
BUILD_DATE=$(date +%Y%m%d)

# 이미지 태그 조합
IMAGE_TAG="${BUILD_DATE}-${GIT_SHA}"

# 빌드 및 태그
docker build -t myapp:${IMAGE_TAG} .

# 예: myapp:20240510-a3f7c91

# 레지스트리 push
docker push myapp:${IMAGE_TAG}

# 참고용으로 latest도 함께 push (운영에서는 SHA 태그만 사용)
docker tag myapp:${IMAGE_TAG} myapp:latest
docker push myapp:latest

latest는 "현재 stable" 참조용으로만 유지하고, 실제 배포와 롤백은 반드시 20240510-a3f7c91처럼 고정된 태그로 합니다.

태그 전략 비교

로컬 터미널
# 나쁜 패턴 — 무엇이 배포됐는지 알 수 없음
myapp:latest

# 좋은 패턴 — 언제, 어떤 커밋인지 명확
myapp:20240510-a3f7c91

# 더 구체적인 패턴 — 브랜치까지 포함
myapp:main-20240510-a3f7c91

# 시맨틱 버저닝 + SHA 조합
myapp:v2.3.1-a3f7c91

태그로 롤백하기

로컬 터미널
# 배포된 버전 확인 (태그 목록)
docker images myapp --format "table {{.Tag}}\t{{.CreatedAt}}\t{{.ID}}"

# 특정 시점으로 롤백
docker run -d --name myapp myapp:20240508-b9e2d14

# 또는 레지스트리에서 이전 태그 pull
docker pull myapp:20240508-b9e2d14

💡개념

CI cron 자동 정리 — 이미지가 쌓이지 않는 파이프라인 만들기

이미지 정리를 수동으로 하면 결국 새벽 3시 경보가 옵니다. CI 서버는 매 빌드마다 이미지를 생성하고, 아무도 정리하지 않으면 디스크는 선형으로 증가합니다. 자동화된 정리 정책이 있어야 이 문제를 예방할 수 있습니다. 이 ConceptBlock에서는 GitHub Actions, Jenkins 등 CI 파이프라인과 시스템 cron에서 이미지 자동 정리를 설정하는 방법을 다룹니다.

CI cron 자동 정리 — 파이프라인과 스케줄 기반 이미지 정리

--filter until 플래그로 안전하게 정리

docker image prune -a -f는 모든 미사용 이미지를 삭제합니다. --filter "until=72h"를 추가하면 72시간 이내에 생성된 이미지는 보존하고 그보다 오래된 이미지만 삭제합니다.

로컬 터미널
# 72시간 이상 된 미사용 이미지 삭제
docker image prune -a -f --filter "until=72h"

# 24시간 이상 된 dangling 이미지 삭제
docker image prune -f --filter "until=24h"

# 라벨 기준 필터링 — 특정 프로젝트 이미지만 정리
docker image prune -a -f --filter "label=project=myapp"

GitHub Actions에서 자동 정리

YAML
# .github/workflows/cleanup.yml
name: Docker Image Cleanup

on:
  schedule:
    - cron: '0 2 * * *'   # 매일 새벽 2시 실행
  workflow_dispatch:        # 수동 실행도 허용

jobs:
  cleanup:
    runs-on: self-hosted    # CI 서버 러너 (self-hosted)
    steps:
      - name: Remove unused images older than 72h
        run: |
          docker image prune -a -f --filter "until=72h"
          docker builder prune -f --filter "until=24h"
          
      - name: Show disk status after cleanup
        run: docker system df

시스템 cron으로 자동 정리 (Linux 서버)

로컬 터미널
# crontab -e 로 추가
# 매일 새벽 3시에 72시간 이상 된 미사용 이미지 정리
0 3 * * * /usr/bin/docker image prune -a -f --filter "until=72h" >> /var/log/docker-cleanup.log 2>&1

# 매주 일요일 새벽 4시에 빌드 캐시 정리
0 4 * * 0 /usr/bin/docker builder prune -f >> /var/log/docker-cleanup.log 2>&1

Jenkins 파이프라인 마지막 단계에 정리 추가

GROOVY
// Jenkinsfile (선언형 파이프라인)
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t myapp:${BUILD_DATE}-${GIT_COMMIT[0..6]} .'
            }
        }
        stage('Push') {
            steps {
                sh 'docker push myapp:${BUILD_DATE}-${GIT_COMMIT[0..6]}'
            }
        }
    }
    post {
        always {
            // 빌드 완료 후 dangling 이미지 정리
            sh 'docker image prune -f'
        }
        cleanup {
            // 워크스페이스 정리
            cleanWs()
        }
    }
}

post { always { } } 블록에 docker image prune -f를 넣으면 빌드 성공·실패에 관계없이 항상 dangling 이미지를 정리합니다.


실습: docker save / load로 이미지 아카이빙

인터넷이 차단된 폐쇄망 환경, 오프라인 납품, 이미지 백업이 필요할 때 docker savedocker load를 사용합니다.

이미지를 tar 파일로 저장

로컬 터미널
# 단일 이미지 저장
docker save -o nginx-alpine.tar nginx:alpine

# 저장된 파일 확인
ls -lh nginx-alpine.tar
# -rw------- 1 user user 8.1M ... nginx-alpine.tar

# gzip으로 압축하여 크기 줄이기
docker save nginx:alpine | gzip > nginx-alpine.tar.gz
ls -lh nginx-alpine.tar.gz
# -rw-r--r-- 1 user user 3.2M ... nginx-alpine.tar.gz  (약 60% 압축)

여러 이미지를 하나의 파일로 묶기

로컬 터미널
# nginx와 redis를 하나의 tar에 저장
docker save -o app-bundle.tar nginx:alpine redis:7-alpine

# gzip 압축까지
docker save nginx:alpine redis:7-alpine | gzip > app-bundle.tar.gz

# 파일 전송 (scp 예시)
scp app-bundle.tar.gz deploy@192.168.1.100:/tmp/

다른 호스트에서 이미지 복원

로컬 터미널
# tar 파일에서 이미지 로드
docker load -i nginx-alpine.tar

# 출력:
# Loaded image: nginx:alpine

# gzip 압축 파일 로드
docker load -i nginx-alpine.tar.gz
# 또는 파이프 사용
gunzip -c nginx-alpine.tar.gz | docker load

# 복원 확인
docker images nginx
# REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
# nginx        alpine    c1afedef4846   2 weeks ago   41.4MB

이미지 무결성 검증 (폐쇄망 납품 시)

로컬 터미널
# 전송 전: 이미지 다이제스트(sha256) 기록
docker inspect nginx:alpine --format '{{.Id}}'
# sha256:c1afedef4846b6c6a93f62f4db7af...

# 전송 후 복원된 이미지의 다이제스트와 비교
docker inspect nginx:alpine --format '{{.Id}}'
# 동일한 sha256이면 전송 중 손상 없음

빌드 또는 pull 중 no space left on device 에러가 발생했습니다. CI 파이프라인이 멈춘 상태에서 빠르게 공간을 확보해야 합니다.

즉시 진단

로컬 터미널
# Docker 공간 사용 현황 파악
docker system df

# 호스트 디스크 전체 상태 확인
df -h /var/lib/docker

빠른 공간 확보 (순서대로)

로컬 터미널
# 1단계: dangling 이미지 삭제 (가장 안전, 즉시 실행)
docker image prune -f

# 2단계: 중지된 컨테이너 삭제
docker container prune -f

# 3단계: 빌드 캐시 삭제
docker builder prune -f

# 공간 확인
docker system df && df -h /var/lib/docker

빠른 효과가 필요할 때 (볼륨 제외)

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

Docker 미사용 리소스 긴급 정리

안전한 실행 조건: CI 서버 디스크 부족처럼 긴급 공간 확보가 필요하고 볼륨 삭제가 포함되지 않는 경우에만 실행합니다.

실행 전 반드시 확인

  • docker system df로 회수 가능 공간을 확인했다
  • 실행 중인 서비스에 필요한 이미지가 영향을 받지 않는지 확인했다
  • 볼륨 삭제가 포함되지 않는 명령임을 확인했다
docker system prune -a -f

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

이미지, 컨테이너, 네트워크, 빌드 캐시를 한 번에 삭제합니다. 볼륨은 건드리지 않으므로 --volumes를 붙이지 않으면 데이터는 안전합니다.

근본 원인 해결 — 예방 정리 설정

로컬 터미널
# crontab -e 에 추가 (매일 새벽 3시)
0 3 * * * /usr/bin/docker image prune -a -f --filter "until=72h"

이 에러가 다시 발생하지 않도록 CI 서버에 정기 정리 cron을 반드시 추가하세요.

증상

로컬에서 태그를 붙이고 push했는데, 레지스트리에서 해당 이미지를 찾을 수 없습니다.

로컬 터미널
docker tag myapp:latest myapp:v1.0.0
docker push myapp:v1.0.0
# Using default tag: latest
# The push refers to repository [docker.io/library/myapp]
# denied: requested access to the resource is denied

원인 진단

로컬 터미널
# 현재 이미지 태그 확인
docker images | grep myapp
# myapp    v1.0.0    abc123    2 min ago   512MB
# → 레지스트리 prefix 없이 로컬 이름만 있음

# docker.io/library/ 는 Docker Hub 공식 이미지 경로
# 개인/조직 이미지는 docker.io/<username>/<image> 형식이어야 함

해결

로컬 터미널
# 올바른 태그 형식으로 다시 태깅
# Docker Hub: docker.io/<username>/<image>:<tag>
docker tag myapp:v1.0.0 myusername/myapp:v1.0.0
docker push myusername/myapp:v1.0.0

# GHCR: ghcr.io/<org>/<image>:<tag>
docker tag myapp:v1.0.0 ghcr.io/myorg/myapp:v1.0.0
docker push ghcr.io/myorg/myapp:v1.0.0

# ECR: <account>.dkr.ecr.<region>.amazonaws.com/<repo>:<tag>
docker tag myapp:v1.0.0 123456789.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1.0.0
docker push 123456789.dkr.ecr.ap-northeast-2.amazonaws.com/myapp:v1.0.0

증상

오프라인 환경에 이미지를 전달하려고 docker save로 내보내고 docker load로 불러왔는데, 이미지 이름이 사라집니다.

로컬 터미널
# 내보내기
docker save abc123 > myapp.tar  # 이미지 ID로 저장

# 다른 서버에서 불러오기
docker load < myapp.tar
# Loaded image ID: sha256:abc123...

docker images
# REPOSITORY   TAG       IMAGE ID
# <none>       <none>    abc123...  ← 이름이 없음

원인

docker save에 이미지 ID만 지정하면 이름/태그 정보가 포함되지 않습니다. 이름과 태그는 이미지 메타데이터에 저장되는데, ID만으로 저장하면 그 정보가 빠집니다.

해결

로컬 터미널
# 올바른 방법: 이미지 이름:태그 형식으로 저장
docker save myapp:v1.0.0 > myapp-v1.tar

# 불러오기
docker load < myapp-v1.tar
# Loaded image: myapp:v1.0.0

# 여러 이미지를 한 파일에 저장
docker save myapp:v1.0.0 myapp:v1.1.0 > myapp-versions.tar

# 또는 gzip 압축
docker save myapp:v1.0.0 | gzip > myapp-v1.tar.gz
docker load < myapp-v1.tar.gz

💼
실무 맥락
현업 패턴

CI/CD 파이프라인에서 이미지 정리 정책 설정하는 실무

인프라 엔지니어나 DevOps 엔지니어로 일하면 "CI 서버 디스크 관리"가 반복적인 운영 업무가 됩니다. 빌드가 빠를수록 이미지는 더 빨리 쌓이고, 팀이 커질수록 문제가 심해집니다.

실무에서 적용하는 이미지 운영 정책의 핵심은 세 가지입니다.

첫째, 태그 규약을 팀 전체가 따르도록 Makefile이나 CI 스크립트에 고정합니다. make build를 실행하면 자동으로 $(date +%Y%m%d)-$(git rev-parse --short HEAD) 형식의 태그가 붙도록 합니다. 개발자가 수동으로 태그를 결정하면 규칙이 흐트러집니다.

둘째, 정리 cron은 CI 서버 초기 세팅 시 반드시 포함합니다. 나중에 추가하려면 이미 터진 디스크 사고를 수습하면서 해야 합니다. ansible-playbook이나 terraform으로 서버를 프로비저닝할 때 crontab 설정을 같이 넣으면 빠뜨리지 않습니다.

셋째, 레지스트리 retention policy를 함께 설정합니다. ECR(AWS), GCR(GCP), GHCR(GitHub)은 모두 이미지 보관 정책을 지원합니다. "최근 10개만 보관", "30일 이상 된 이미지 삭제" 같은 정책을 레지스트리에서도 적용하면 CI 서버와 레지스트리 양쪽에서 불필요한 이미지가 쌓이는 것을 막을 수 있습니다.

로컬 터미널
# AWS ECR 예시 — 30일 이상 된 이미지 자동 삭제 정책
aws ecr put-lifecycle-policy \
  --repository-name myapp \
  --lifecycle-policy-text '{
    "rules": [{
      "rulePriority": 1,
      "description": "Keep last 10 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": { "type": "expire" }
    }]
  }'

이미지 운영 정책이 없으면 인프라 엔지니어는 주기적으로 수동 정리를 해야 하고, 결국 어느 날 새벽에 파이프라인 장애로 불려 나오게 됩니다. 처음 설정할 때 10분을 쓰면 그 이후의 새벽 비상 대응을 막을 수 있습니다.

다음 모듈에서는 컨테이너의 휘발성을 다루고, Named Volume과 Bind Mount로 데이터가 컨테이너 삭제 후에도 유지되도록 설계합니다.

지식 확인

퀴즈 — 3문제

Q1

`docker system df`와 `docker system df -v`의 차이는 무엇인가요?

Q2

CI 파이프라인에서 이미지 태그로 `latest` 대신 `git SHA + 날짜` 조합을 사용해야 하는 핵심 이유는?

Q3

`docker image prune`과 `docker image prune -a`의 삭제 범위 차이로 옳은 것은?

0 / 3 답변

🧪 실습으로 확인하기

Docker Compose 멀티 서비스 구성

초급

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

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

이것도 배워보세요

docker중급 · 50
[Docker] Docker 네트워크 드라이브 구조와 DNS 기반 컨테이너 연결
Docker 트랙 계속
networking입문 · 45
[Network] OSI 7계층과 TCP/IP 4계층 모델 실무적 관점 분석
Networking 트랙 시작점