20200825

Docker Compose v2 체감

Docker Compose v2 technical preview 들여다봄. Docker Desktop 2.3에 번들로 들어있음(Linux는 수동 플러그인). v1(Python)이 아니라 Go로 재작성한 거고, CLI도 docker compose ...(스페이스). v1이 docker-compose ...(하이픈). 3월에 alpha 한 번 만져봤는데 이번 preview에서 꽤 정돈.

기존 compose yml은 거의 그대로 돈다. 중요한 건 CLI 진입점 변화.

docker compose up -d
docker compose ps
docker compose logs -f api
docker compose exec api python manage.py shell
docker compose --profile worker up -d

체감 차이 — 정량

  • 시작 속도. docker-compose ps(v1) 298ms vs docker compose ps(v2) 58ms. 5배 차이. 파이썬 import 비용이 큼
  • 스택 up. 8개 서비스 구성 cold start 23s → 14s. 차이는 빌드 병렬화와 BuildKit 기본 덕
  • 오류 메시지. v1은 파이썬 traceback이 노출되어 "yaml 스키마 에러"가 호출 스택과 섞여 보였다. v2는 docker CLI 스타일(컴포넌트/단계 표시)
  • buildx 통합. 이미지 빌드 시 BuildKit이 기본. 멀티 아키텍처(amd64/arm64) 빌드도 docker compose build --platform=linux/amd64,linux/arm64로 가능

구조적 차이

Docker CLI 플러그인 아키텍처를 채택. ~/.docker/cli-plugins/docker-compose 단일 Go 바이너리가 docker CLI에 확장 명령어로 붙는 구조. 이 구조의 이점은 docker context(ECS/ACI/쿠버네티스 원격) 기반으로 compose를 원격 런타임에도 투사할 수 있다는 것. 로컬 개발용 compose.yml을 그대로 ECS에 올리는 실험적 시나리오가 가능.

v1의 docker-py 경유 Engine API 호출 방식은 Docker가 기능을 추가할 때마다 파이썬 바인딩이 뒤쳐지는 고질적 문제가 있었다. v2는 docker CLI와 동일한 gRPC/HTTP 클라이언트를 씀.

실용 기능 몇 개

1. profiles. v1 1.28에 먼저 들어왔고 v2에서 1급 시민. 개발/테스트/프로덕션 마다 일부 서비스만 켜는 운영.

services:
  api:
    image: myorg/api
  worker:
    image: myorg/worker
    profiles: ["worker"]
  mailhog:
    image: mailhog/mailhog
    profiles: ["dev"]
docker compose up -d                    # api만
docker compose --profile worker up -d   # api + worker
docker compose --profile dev up -d      # api + mailhog

2. --wait. healthcheck가 healthy 될 때까지 블록. CI에서 up 직후 통합 테스트 바로 때릴 수 있다.

docker compose up -d --wait
pytest -q tests/integration

3. env_file과 interpolation. 변수 확장 규칙이 더 정밀해짐. ${VAR:-default}(unset이면 default), ${VAR-default}(정의 안 됨이면 default) 구분이 엄격.

4. build.cache_from / cache_to. 레지스트리 기반 분산 빌드 캐시. CI 러너가 여러 대일 때 매 빌드 cold 시작 방지.

마이그레이션 시 걸린 것들

  • compose file version. v2는 version: "3.9" 필드를 사실상 무시. Compose Spec으로 통일 중이라 version을 적지 않아도 됨. 그러나 v1과 병행 운영 중이면 명시 유지
  • links. 이미 deprecated였는데 v2에서 확실히 noop화. 네트워크 경유 서비스 디스커버리가 기본이니 문제는 거의 없음
  • command의 signal handling. v2에서 stop_grace_period 대응이 엄격. 앱이 SIGTERM을 제대로 처리 안 하면 grace 뒤 SIGKILL로 강제 종료되는 타이밍이 v1보다 조금 더 정확. gunicorn/uvicorn 기동 스크립트에서 signal 처리 재확인
  • host-gateway. 컨테이너에서 호스트로 host.docker.internal 식 접근이 macOS/Windows는 기본, Linux는 extra_hosts: ["host.docker.internal:host-gateway"]로 명시 필요. v2는 이 트릭이 안정
  • Windows PATH. 업데이트 후 docker compose가 안 먹는 경우 Docker Desktop 재설치로 해결

관성 대응

손이 docker-compose ...를 계속 친다. shell alias로 처리.

# ~/.zshrc
alias dc="docker compose"
alias dcu="docker compose up -d"
alias dcl="docker compose logs -f"

운영 결정

  1. 로컬 개발: v2 전면 전환. 기동 속도, 오류 메시지 개선 체감
  2. CI: v2로 전환하되 기존 스크립트에서 docker-composedocker compose로 바꾸고, 스택 up 시 --wait 활용
  3. 프로덕션 쪽은 원래 compose를 직접 안 쓰기 때문에 영향 없음(K8s + Helm)

v1은 내년쯤 deprecated 예상. 지금부터 전환해 두는 게 낫다. 호환성은 거의 문제없고, 성능과 UX 이득이 분명.