← 전체 글로 돌아가기

Docker

Docker rollback을 위해 이전 이미지를 남겨두기

배포 후 문제가 생기면 빨리 이전 버전으로 돌아가야 한다. 그럴 때 이미지가 없으면 곤란하다.

배포 후 문제가 발생하면, 가장 빠른 해결책은 이전 버전으로 돌아가는 것이다. 그런데 Docker 이미지를 지워버렸다면? 다시 빌드해야 하고, 그 사이에 서비스는 다운된다.

문제: 이미지 정리 과다

# 배포 후 이미지를 깔끔하게 하려고...
docker image prune -a --force
# → 모든 이미지 삭제!

# 문제 발생
docker run myapp:v1.0  # 이미지 없음!

운영 중에 이런 일이 생기면 서비스 복구가 매우 어렵다.

해결책: 이미지 태그 전략

기본 원칙: 최소 2개의 이미지를 항상 보관

# 현재 배포된 이미지
myapp:latest

# 이전 배포 이미지
myapp:v1.0
myapp:previous

# 개발 이미지
myapp:dev
myapp:staging

1단계: 새 버전으로 빌드

docker build -t myapp:v1.1 .

2단계: 기존 이미지를 previous 태그로 백업

# 현재 latest가 뭔지 확인
docker images myapp | grep latest

# 현재 latest를 previous로 태그
docker tag myapp:latest myapp:previous

3단계: 새 이미지를 latest로 배포

docker tag myapp:v1.1 myapp:latest
docker push myapp:latest

# 또는 Docker Compose
docker compose up -d

4단계: 문제 발생시 빠른 롤백

# previous로 돌아가기
docker tag myapp:previous myapp:latest

# 컨테이너 재시작
docker compose up -d

# 또는 Swarm/Kubernetes
docker service update myapp --image myapp:previous

Docker Compose 예시

version: '3.8'
services:
  myapp:
    image: myapp:latest
    container_name: myapp_prod
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
    restart: always

배포 스크립트

#!/bin/bash

# 1. 현재 이미지를 previous로 백업
echo "Backing up current image..."
current=$(docker images myapp | grep latest | awk '{print $3}')
if [ ! -z "$current" ]; then
  docker tag myapp:latest myapp:previous
fi

# 2. 새 이미지 빌드
echo "Building new image..."
docker build -t myapp:latest .

# 3. 컨테이너 시작
echo "Starting container..."
docker compose up -d

# 4. 헬스 체크
echo "Health check..."
sleep 5
curl -f http://localhost:3000/health || {
  echo "Health check failed! Rolling back..."
  docker tag myapp:previous myapp:latest
  docker compose up -d
  exit 1
}

echo "Deployment successful!"

Kubernetes 배포

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
    - port: 3000
      targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v1.1
        ports:
        - containerPort: 3000

롤백

# 이전 버전 확인
kubectl rollout history deployment/myapp

# 롤백
kubectl rollout undo deployment/myapp

# 또는 특정 버전으로
kubectl rollout undo deployment/myapp --to-revision=2

저장소 관리

로컬 저장소에는 최소 2-3개 버전을 유지하자.

# 이미지 목록
docker images myapp

# 결과:
# REPOSITORY  TAG        IMAGE ID      CREATED
# myapp       latest     abc123...     5 minutes ago
# myapp       v1.1       abc123...     5 minutes ago
# myapp       v1.0       def456...     2 days ago
# myapp       previous   def456...     2 days ago

불필요한 이미지만 정리

# dangling 이미지만 삭제 (안전)
docker image prune -f

# 특정 버전 삭제
docker rmi myapp:v0.9

# 모든 이미지 삭제 (위험!)
docker image prune -a -f  # 하지 말 것!

레지스트리에 보관

Docker Hub나 Private Registry에도 여러 버전을 보관하면 더 안전하다.

# 빌드 및 푸시
docker build -t myregistry.azurecr.io/myapp:v1.1 .
docker push myregistry.azurecr.io/myapp:v1.1

# 태그도 푸시
docker tag myregistry.azurecr.io/myapp:v1.1 myregistry.azurecr.io/myapp:latest
docker push myregistry.azurecr.io/myapp:latest

# 롤백할 때 레지스트리에서 가져오기
docker pull myregistry.azurecr.io/myapp:v1.0
docker run myregistry.azurecr.io/myapp:v1.0

모니터링 및 자동 롤백

배포 후 문제를 감지하면 자동 롤백하는 게 가장 좋다.

#!/bin/bash

# 배포
docker compose up -d

# 헬스 체크 (반복)
for i in {1..30}; do
  if curl -f http://localhost:3000/health >/dev/null 2>&1; then
    echo "✓ Health check passed"
    exit 0
  fi
  echo "Waiting for service... ($i/30)"
  sleep 2
done

# 30초 후에도 실패면 롤백
echo "✗ Service failed to start, rolling back..."
docker tag myapp:previous myapp:latest
docker compose up -d
exit 1

정리

Rollback은 배포 전략의 가장 중요한 부분이다. 항상 이전 버전의 이미지를 보관하고, 배포 후 헬스 체크를 실행하고, 문제시 빠르게 롤백할 수 있게 준비하자. 시간이 걸리지 않는 롤백이 최고의 장애 대응이다. "배포 1시간, 정상 확인 1분, 롤백 30초" 이 정도면 충분한 준비다.