Skip to main content

8. Docker Compose

이 문서는 도커 컴포즈 개념을 다룹니다.

개요

도커 컴포즈는 여러 컨테이너로 구성된 애플리케이션을 정의하고 관리하기 위한 도구

docker-compose.yml YAML 파일을 사용하여 컨테이너, 네트워크, 볼륨 등 애플리케이션의 모든 설정을 한곳에서 정의하고, 단일 명령어로 전체 서비스를 생성하고 실행할 수 있어 복잡한 애플리케이션을 쉽게 관리할 수 있습니다.

쉽게 말해 여러 컨테이너를 yaml로 정의하여 한번에 실행하는 앱-으로 이해했습니다.

구성 요소와 특징

  • docker-compose.yml: 설정 파일. 구성하는 모든 요소를 한 파일에 YAML로 작성.
  • 컨테이너 관리: 여러 컨테이너를 하나의 서비스로 묶어 관리하며, 각 컨테이너의 이미지, 환경 변수, 포트, 볼륨, 네트워크 등 세부 설정을 지정할 수 있습니다.
  • 실행: docker-compose up과 같은 단일 명령어를 통해 파일에 정의된 모든 컨테이너와 서비스를 한 번에 생성하고 실행할 수 있습니다.
  • 애플리케이션 배포: 복잡한 애플리케이션 스택을 간단하게 관리하고 배포하는 데 사용할 수 있습니다.

여러 컨테이너를 연결하여 하나의 앱처럼 구동해야하는 경우, (ex: LAMP 스택의 개발 서버) 터미널에 여러 컨테이너를 매번 run | start | stop 하는 것이 번거로울 뿐만 아니라, 실수 및 에러 발생을 일으키기도 쉬워보입니다. 따라서 일반적인 CI/CD 환경에서처럼, yaml 스크립트로 관리하는 것이 효율적이겠습니다.

Compose Commands

# 도커 yaml에 따라 컨테이너들을 빌드-생성-시작 -d : detached mode. background 실행
docker compose up -d
# up 상태의 컴포즈를 down
docker compose down -v {remove_volume}
# 컨테이너 삭제 없이 서비스를 중단.
docker compose stop
# 중지된 서비스를 시작
docker compose start
# 컴포즈로 올라간 컨테이너, 서비스를 보여줌. -a 는 중지 상태를 포함한 모든 컨테이너 표시
docker compose ps -a
docker compose logs # 로그 출력
docker compose build # docker-compose.yaml에 정의된 이미지를 (재)빌드
# docker exec 옵션과 동일. 실행 중인 서비스 컨테이너에 명령어 실행
docker compose exec {name} bash
# 일회성 작업을 위한 특정 서비스 컨테이너 실행 명령어
docker compose run # db 마이그레이션 등, 앱 실행 전에 한번만 수행되면 될 작업들

docker-compose.yaml

도커 컴포즈의 배포 스크립트입니다. 일반적인 yaml 배포 스크립트와 유사성이 있습니다. 그래선지 "여러 대의 컨테이너를 묶은 하나의 앱"이라는 설명이 더 잘 와닿습니다. 또한 이전 글의 개념들인 도커 빌드, 네트워크, 볼륨이 잘 정의되어 있어 학습하기 좋습니다.

다음 예시를 통해 배포 스크립트의 각 역할을 살펴봅니다.


version: "3.9" # (선택사항) Compose 파일의 버전 지정. 최신 Docker에서는 경고가 뜹니다.

services: # 컨테이너 서비스 정의 (가장 핵심 부분)
├── cont-app: # 첫 번째 서비스 이름 (임의의 이름 가능)
│ ├── build: . # Dockerfile을 기준으로 이미지 빌드할 경로
│ ├── image: myapp:latest # (선택사항) 직접 지정한 이미지 사용 가능
│ ├── container_name: myapp # (선택사항) 컨테이너 이름 지정
│ ├── command: uvicorn src.main:app --reload # 컨테이너 실행 시 명령어
│ ├── ports: # 호스트 ↔ 컨테이너 포트 매핑
│ │ ├── - "8000:8000"
│ │ └── - "5678:5678"
│ ├── volumes: # 디렉터리 또는 파일을 컨테이너에 마운트
│ │ └── - .:/code
│ ├── environment: # 환경 변수 설정
│ │ ├── - DEBUG=True
│ │ └── - ENV=dev
│ ├── depends_on: # 의존성 설정 (먼저 실행되어야 하는 서비스)
│ │ ├── - cont-db
│ │ └── - cont-redis
│ ├── networks: # 사용할 네트워크 지정
│ │ └── - backend
│ └── restart: always # 컨테이너 중단 시 재시작 정책

├── cont-db: # 데이터베이스 서비스
│ ├── image: postgres:16
│ ├── environment:
│ │ ├── - POSTGRES_USER=admin
│ │ ├── - POSTGRES_PASSWORD=secret
│ │ └── - POSTGRES_DB=mydb
│ ├── volumes:
│ │ └── - ./data/db:/var/lib/postgresql/data
│ ├── ports:
│ │ └── - "5432:5432"
│ └── networks:
│ └── - backend
└── cont-redis: # 캐시 또는 큐용 서비스
├── image: redis:latest
├── ports:
│ └── - "6379:6379"
├── restart: unless-stopped
└── networks:
└── - backend

# 네트워크 정의 (서비스 간 통신용 가상 네트워크)
networks:
└── backend:
├── driver: bridge # 기본 네트워크 드라이버 (bridge, overlay 등)
└── external: false # false면 docker-compose가 새로 생성, true면 기존 네트워크 사용

# 볼륨 정의 (데이터 영속성)
volumes:
└── db-data: # db 컨테이너에서 사용하는 볼륨 이름
└── driver: local
  • 들여쓰기(spaces)로 계층을 구분하며, 탭(tab)은 절대 사용하면 안 됩니다.
  • depends_on: 서비스 간 의존 관계 설정. 어떤 서비스가 다른 서비스보다 먼저 실행되어야 하는지를 정의합니다.
    • 위의 예시에선 cont-db -> cont-redis -> cont-app 순서대로 실행됩니다.
  • networks: 여러 대의 컨테이너가 서로 통신할 수 있도록 연결하는 Docker 내부 네트워크.
    • 기본적으로 Docker Compose는 프로젝트 이름 기반의 기본 네트워크를 자동 생성합니다.

이처럼 컴포즈는 여러 컨테이너의 세부 설정을 종합적으로 설정할 수 있습니다. 이러한 설정을 배포 스크립트에서 코드 단위로 정의할 수 있다는 점이 매력적입니다.

ollama-docker 예시

docker-compose-1.png

제가 자주 사용하는 ollama-docker를 사용 중이어서, 공유된 docker-compose.yml 파일을 분석해봅니다.

services:
app: # FastAPI (또는 Python 기반) 애플리케이션 서비스 정의
build: . # 현재 디렉터리의 Dockerfile로 이미지 빌드
ports:
- 8000:8000 # 호스트 8000 포트를 컨테이너 8000 포트에 매핑 (API 접근용)
- 5678:5678 # 디버깅용 포트 (예: VSCode 디버거 연결)
volumes:
- .:/code # 현재 프로젝트 디렉토리를 컨테이너의 /code에 마운트 (실시간 코드 반영)
command: uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload
# 컨테이너 실행 시 FastAPI 서버를 자동으로 시작 (--reload는 코드 변경 시 자동 리로드)
restart: always # 컨테이너가 중지되면 항상 재시작
depends_on:
- ollama # ollama 서비스가 먼저 시작되도록 의존성 설정
- ollama-webui # ollama-webui도 시작 후 app이 실행되도록
networks:
- ollama-docker # ollama-docker 네트워크에 연결 (서비스 간 통신용)

ollama: # Ollama LLM 백엔드 서비스 정의 (로컬 LLM 실행용)
image: docker.io/ollama/ollama:latest # Ollama 공식 Docker 이미지 사용
ports:
- 7869:11434 # 호스트 7869 포트를 컨테이너의 Ollama API 포트(11434)로 연결
volumes:
- .:/code # 코드 디렉토리 공유 (필요 시 모델 관리)
- ./ollama/ollama:/root/.ollama # Ollama 모델 데이터 저장소를 로컬 폴더에 영속화
container_name: ollama # 컨테이너 이름 지정
pull_policy: always # 항상 최신 이미지를 가져오도록 설정
tty: true # TTY 활성화 (콘솔 상호작용 가능)
restart: always # 컨테이너 중지 시 항상 재시작
environment:
- OLLAMA_KEEP_ALIVE=24h # 모델을 메모리에 24시간 유지 (성능 향상)
- OLLAMA_HOST=0.0.0.0 # 외부 접속 허용
networks:
- ollama-docker # 같은 네트워크 상의 다른 컨테이너들과 통신 가능

ollama-webui: # Ollama를 위한 Web UI (Open WebUI)
image: ghcr.io/open-webui/open-webui:main # Open WebUI 최신 버전 이미지 사용
container_name: ollama-webui # 컨테이너 이름 지정
volumes:
- ./ollama/ollama-webui:/app/backend/data # WebUI 데이터(설정, 히스토리 등) 영속 저장
depends_on:
- ollama # Ollama 서비스가 먼저 실행되어야 함
ports:
- 8080:8080 # 호스트 8080 포트를 WebUI의 8080 포트로 연결 (웹 브라우저 접근용)
environment: # 환경변수 설정 (Open WebUI 문서 참고)
- OLLAMA_BASE_URLS=http://host.docker.internal:7869 # Ollama API 엔드포인트 지정
- ENV=dev # 개발 모드
...
extra_hosts:
networks:
- ollama-docker # ollama 및 app과 동일한 네트워크 사용

networks:
ollama-docker: # 서비스 간 통신을 위한 사용자 정의 네트워크
external: false # Docker Compose가 자동으로 생성하도록 설정 (외부 네트워크 아님)