포스트

Docker 기초 (8) - Docker Compose and Operations

compose.yaml 작성부터 healthcheck 기반 depends_on, 디스크 정리, 자주 밟는 운영 함정까지 Docker Compose 운영을 정리합니다.

Docker 기초 (8) - Docker Compose and Operations

Docker 기초 시리즈의 8편입니다. 전체 목차는 0편에 있습니다.

앱과 DB 구성

5편에서 service 하나짜리 compose.yaml과 기본 명령을 익혔습니다. 실제 프로젝트는 앱과 DB처럼 container 여러 개가 세트로 움직이고, 이번 편은 그 구성과 운영을 다룹니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://postgres:dev@db:5432/postgres
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: dev
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  pgdata:
1
2
3
4
docker compose up -d          # 전부 띄우기 (--build를 붙이면 재빌드부터)
docker compose logs -f        # 모든 service의 로그
docker compose down           # container와 network 삭제, volume은 유지
docker compose down -v        # volume까지 삭제. 데이터가 사라진다

읽는 포인트는 세 가지입니다.

  • run 옵션이 yaml 항목으로 그대로 대응됩니다. -p는 ports, -e는 environment, -v는 volumes입니다
  • Compose는 network를 자동으로 만들고 service 이름이 hostname이 됩니다. 앱이 DB에 db라는 이름으로 접속하는 이유이고, 7편의 원리 그대로입니다
  • depends_on은 기본적으로 시작 순서만 보장합니다. DB가 실제로 준비될 때까지 기다리려면 위처럼 healthcheck와 condition: service_healthy를 함께 씁니다. 이것이 없으면 앱이 먼저 떠서 첫 접속에 실패하는 경쟁 상태가 생깁니다

compose.yaml은 저장소에 커밋되므로, 새 팀원은 저장소를 받아 docker compose up 한 줄로 전체 개발 환경을 얻습니다. MLflow와 Airflow를 이 방식으로 구동한 기록이 MLflow 해부 6편Airflow 해부 6편, NYC 택시 프로젝트 2편에 있습니다.

디스크 관리

image, 종료된 container, 안 쓰는 volume, build cache가 조용히 수십 GB를 차지합니다. 확인과 정리 명령을 세트로 기억합니다.

1
2
3
4
docker system df        # image, container, volume, build cache별 사용량
docker system prune     # 중지된 container, 안 쓰는 network, dangling image 정리
docker system prune -a  # 어떤 container도 쓰지 않는 image까지 정리
docker builder prune    # build cache 정리

system prune은 기본적으로 volume을 건드리지 않습니다. volume까지 정리하려면 --volumes를 명시해야 하고, 그만큼 신중해야 합니다.

자주 밟는 함정

  1. 어느 날 갑자기 빌드가 깨집니다. 원인은 base image의 latest나 폭이 넓은 tag가 새 버전을 가리키게 된 것입니다. tag를 구체적으로 고정하고, 재현성이 중요한 배포라면 digest(@sha256:...)까지 고정합니다
  2. down 했더니 데이터가 사라졌습니다. down -v를 습관적으로 쓰거나 volume 선언 없이 container 안에 데이터를 둔 경우입니다. 상태는 volume으로 빼고, -v 플래그는 지워질 대상을 확인하고 씁니다
  3. 고친 코드가 반영되지 않습니다. image를 재빌드하지 않았거나 cache가 옛 layer를 재사용한 경우입니다. docker compose up -d --build로 재빌드를 명시하고, 의심스러우면 --no-cache로 전체 재빌드해 확인합니다
  4. 맥에서 만든 image가 서버에서 exec format error로 종료됩니다. Apple Silicon(arm64)과 서버(amd64)의 아키텍처 불일치입니다. docker build --platform linux/amd64로 대상 아키텍처를 명시합니다. ECR 배포에서 이 문제를 만난 기록이 AWS 해부 5편에 있습니다
  5. 디스크가 가득 찼습니다. 재빌드마다 옛 image와 build cache가 쌓인 것입니다. 위의 prune 명령을 주기적으로 실행합니다

다음 편은 마지막으로, 이 시리즈를 ML 학습과 서빙 이미지에 적용합니다.

다음 글: Docker 기초 (9) - ML Training and Serving Images

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.