화. 8월 12th, 2025

G: 안녕하세요! 👋 복잡한 애플리케이션 개발 환경 설정 때문에 머리 아프셨던 경험, 다들 있으실 겁니다. 웹 서버, 데이터베이스, 캐시, 백엔드 서비스 등 여러 컴포넌트가 얽히면 관리하기가 여간 까다로운 게 아니죠. 🤯

하지만 걱정 마세요! Docker Compose가 바로 이 문제를 해결해 줄 마법 같은 도구입니다. Docker Compose를 사용하면 여러 개의 컨테이너를 하나로 묶어 쉽고 일관되게 관리할 수 있습니다. 마치 오케스트라의 지휘자처럼, 모든 컨테이너를 조화롭게 움직이게 할 수 있죠! 🎼

이 가이드에서는 Docker Compose의 핵심 명령어들을 깊이 있게 파헤쳐 보고, 실제 예시와 함께 어떻게 활용할 수 있는지 완벽하게 설명해 드릴게요. 이 글을 다 읽고 나면 여러분은 멀티 컨테이너 환경의 베테랑이 되어 있을 겁니다! 🚀


📚 목차

  1. Docker Compose란 무엇인가요?
  2. docker-compose.yml: 모든 것의 시작점
  3. 핵심 Docker Compose 명령어 파헤치기
    • docker-compose up: 컨테이너 띄우기 (그리고 더 많은 기능!)
    • docker-compose down: 깨끗하게 종료하기
    • docker-compose ps: 현재 상태 확인하기
    • docker-compose logs: 컨테이너 로그 보기
    • docker-compose exec: 실행 중인 컨테이너에 접속하기
    • docker-compose build: 이미지 직접 빌드하기
    • docker-compose stop, start, restart: 컨테이너 제어하기
    • docker-compose rm: 컨테이너 제거하기
    • docker-compose config: 설정 유효성 검사 및 보기
    • docker-compose run: 일회성 명령어 실행하기
  4. Docker Compose 활용 팁 & 베스트 프랙티스
  5. 마무리하며

1. Docker Compose란 무엇인가요?

Docker Compose는 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구입니다. 📦📦📦

쉽게 말해, 웹 애플리케이션을 개발할 때 웹 서버 (Nginx), 애플리케이션 서버 (Node.js/Python), 데이터베이스 (PostgreSQL/MySQL), 캐시 (Redis) 등 여러 개의 컨테이너가 필요하잖아요? 이 모든 컨테이너를 개별적으로 docker run 명령어로 실행하고 연결하는 것은 매우 번거롭습니다.

Docker Compose는 이 모든 과정을 하나의 YAML 파일(docker-compose.yml)로 정의하고, 단일 명령어로 한 번에 빌드, 실행, 연결, 종료할 수 있게 해줍니다. 마치 레시피 하나로 복잡한 요리를 한 번에 완성하는 것과 같아요! 👩‍🍳

💡 왜 중요할까요?

  • 간편한 환경 설정: 복잡한 개발 환경을 몇 줄의 코드로 정의하고 공유할 수 있습니다.
  • 일관된 개발 환경: 팀원 모두가 동일한 환경에서 작업할 수 있어 “내 컴퓨터에서는 되는데…” 문제를 줄여줍니다.
  • 빠른 시작/종료: 애플리케이션 스택을 통째로 쉽게 시작하고 중단할 수 있습니다.
  • 유지보수 용이성: 컨테이너 간의 의존성, 네트워크 설정 등을 한눈에 파악하고 관리할 수 있습니다.

참고: 최신 Docker Desktop 버전에서는 docker-compose 명령 대신 docker compose (띄어쓰기) 명령을 권장하고 있습니다. 기능은 동일하며, 이 가이드에서는 전통적인 docker-compose를 기준으로 설명하지만, docker compose로 대체해서 사용하셔도 무방합니다.


2. docker-compose.yml: 모든 것의 시작점

Docker Compose를 사용하려면 먼저 docker-compose.yml 파일을 작성해야 합니다. 이 파일은 Docker Compose에게 “어떤 컨테이너를 만들고, 어떻게 연결하고, 어떤 설정을 사용할지” 알려주는 설계도와 같습니다. 📝

간단한 docker-compose.yml 예시: Nginx와 간단한 Node.js 웹 애플리케이션, 그리고 PostgreSQL 데이터베이스

# docker-compose.yml
version: '3.8' # Docker Compose 파일 형식 버전

services: # 애플리케이션을 구성하는 서비스들 정의
  web: # 웹 서비스 (Node.js 앱)
    build: . # 현재 디렉토리의 Dockerfile을 사용하여 이미지 빌드
    ports:
      - "80:3000" # 호스트의 80번 포트를 컨테이너의 3000번 포트에 연결 (포트 포워딩)
    volumes:
      - .:/usr/src/app # 현재 디렉토리를 컨테이너의 /usr/src/app에 마운트 (코드 동기화)
    depends_on: # 이 서비스가 시작되기 전에 db 서비스가 시작되어야 함을 명시
      - db
    environment: # 컨테이너 내부에서 사용할 환경 변수 설정
      NODE_ENV: production
      DATABASE_URL: postgres://user:password@db:5432/mydatabase

  db: # 데이터베이스 서비스 (PostgreSQL)
    image: postgres:13 # Docker Hub에서 postgres:13 이미지를 다운로드하여 사용
    environment: # 데이터베이스 환경 변수 설정 (중요!)
      POSTGRES_DB: mydatabase
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db_data:/var/lib/postgresql/data # 데이터 영속성을 위한 볼륨 마운트 (DB 데이터 저장)

volumes: # 명시적으로 볼륨 정의 (컨테이너가 삭제되어도 데이터는 유지)
  db_data:

🤔 이 YAML 파일이 의미하는 것은?

  • version: 사용하려는 Docker Compose 파일의 버전입니다. 최신 기능을 위해 3.8 이상을 사용하는 것이 좋습니다.
  • services: 이 섹션 아래에 애플리케이션을 구성하는 개별 서비스(컨테이너)를 정의합니다.
    • web: web이라는 서비스입니다.
      • build: .: 현재 디렉토리에 있는 Dockerfile을 사용하여 web 서비스의 이미지를 빌드합니다.
      • ports: 호스트_포트:컨테이너_포트 형식으로 포트를 매핑합니다.
      • volumes: 호스트_경로:컨테이너_경로 형식으로 디렉토리를 마운트합니다. 개발 시 코드 변경사항이 즉시 반영되도록 할 때 유용합니다.
      • depends_on: 서비스 간의 시작 순서를 정의합니다. web이 시작되기 전에 db가 시작되어야 합니다.
      • environment: 컨테이너 내부에서 사용할 환경 변수를 설정합니다.
    • db: db라는 서비스입니다.
      • image: postgres:13: Docker Hub에서 postgres:13 이미지를 가져와 사용합니다. build 대신 image를 사용하면 이미 빌드된 이미지를 사용하겠다는 의미입니다.
      • environment: 데이터베이스 초기 설정에 필요한 환경 변수들입니다.
      • volumes: db_data라는 이름의 볼륨을 db 컨테이너의 /var/lib/postgresql/data 경로에 마운트합니다. PostgreSQL 데이터가 컨테이너가 삭제되어도 유지되도록 합니다.
  • volumes: services 섹션에서 사용된 db_data와 같은 명명된 볼륨들을 정의하는 섹션입니다. 컨테이너가 사라져도 데이터가 보존되어야 할 때 주로 사용합니다.

3. 핵심 Docker Compose 명령어 파헤치기

이제 이 docker-compose.yml 파일을 가지고 어떤 명령어들을 사용할 수 있는지 알아봅시다! 🛠️

3.1. docker-compose up: 컨테이너 띄우기 (그리고 더 많은 기능!)

가장 기본적이고 중요한 명령어입니다. docker-compose.yml 파일에 정의된 모든 서비스를 빌드하고, 생성하고, 시작합니다.

  • 기본 사용법:

    docker-compose up

    이 명령어를 실행하면 모든 서비스의 로그가 현재 터미널에 출력됩니다. 컨테이너가 정상적으로 시작되었는지 확인하기 좋습니다.

  • 백그라운드 (detached) 모드로 실행:

    docker-compose up -d

    -d 또는 --detach 플래그를 사용하면 컨테이너들이 백그라운드에서 실행되고 터미널을 다시 사용할 수 있습니다. 서버 애플리케이션을 배포하거나 개발 중에도 터미널을 계속 사용해야 할 때 유용합니다. 👍

  • 이미지 강제 재빌드:

    docker-compose up --build

    docker-compose.yml 파일에서 build 지시어를 사용하는 서비스의 Dockerfile 내용이 변경되었을 때, 이 플래그를 사용하면 Docker 이미지를 강제로 다시 빌드합니다. Dockerfile을 수정했다면 꼭 사용해야 합니다! 🏗️

  • 컨테이너 강제 재생성:

    docker-compose up --force-recreate

    컨테이너의 설정(예: 환경 변수, 포트 매핑)이 변경되었지만 이미지가 바뀌지 않았을 때, 이 플래그를 사용하면 기존 컨테이너를 삭제하고 새로운 설정으로 다시 생성합니다. 때로는 --build와 함께 사용하기도 합니다.

예시:

# 백그라운드에서 모든 서비스를 시작 (가장 흔한 사용법)
docker-compose up -d

# Dockerfile 수정 후, 이미지를 재빌드하고 서비스를 시작
docker-compose up -d --build

# 특정 서비스만 시작 (예: web 서비스만)
docker-compose up -d web

3.2. docker-compose down: 깨끗하게 종료하기

up 명령어로 시작된 모든 서비스와 연결된 네트워크를 중지하고 제거합니다. 개발 환경을 깔끔하게 정리할 때 필수적인 명령어입니다. ✨

  • 기본 사용법:

    docker-compose down

    이 명령어는 컨테이너와 네트워크를 제거하지만, volumes 섹션에 정의된 명명된 볼륨(예: db_data)이나 익명 볼륨은 제거하지 않습니다.

  • 볼륨까지 함께 제거:

    docker-compose down --volumes
    # 또는 줄여서 -v
    docker-compose down -v

    이 플래그를 사용하면 docker-compose.yml에 정의된 명명된 볼륨(db_data)과 익명 볼륨까지 모두 제거합니다. 데이터베이스의 데이터를 완전히 초기화하고 싶을 때 유용합니다. 주의: 데이터가 영구적으로 삭제됩니다! 🗑️

  • 이미지까지 함께 제거:

    docker-compose down --rmi all

    컨테이너를 제거한 후, Docker Compose가 생성한 모든 이미지(web 서비스의 빌드된 이미지 등)까지 제거합니다. 개발 환경을 완전히 초기화하고 싶을 때 사용합니다.

예시:

# 모든 컨테이너와 네트워크를 중지하고 제거
docker-compose down

# 데이터베이스 데이터까지 포함하여 모든 것을 제거 (주의!)
docker-compose down -v

3.3. docker-compose ps: 현재 상태 확인하기

실행 중인 Docker Compose 서비스들의 현재 상태를 보여줍니다. 어떤 컨테이너가 실행 중이고, 어떤 포트가 열려 있으며, 어떤 상태인지 한눈에 확인할 수 있습니다. 👀

  • 기본 사용법:
    docker-compose ps

예시:

$ docker-compose ps
      Name                    Command               State           Ports
---------------------------------------------------------------------------------
myproject_db_1      docker-entrypoint.sh postgres   Up      5432/tcp
myproject_web_1     /bin/sh -c node index.js        Up      0.0.0.0:80->3000/tcp

myproject는 프로젝트 이름인데, 기본적으로 docker-compose.yml 파일이 있는 디렉토리 이름이 사용됩니다.

3.4. docker-compose logs: 컨테이너 로그 보기

특정 서비스 또는 모든 서비스의 로그를 확인할 수 있습니다. 디버깅할 때 매우 유용한 명령어입니다. 🐛

  • 모든 서비스 로그 보기:

    docker-compose logs
  • 특정 서비스 로그 보기:

    docker-compose logs web

    web 서비스의 로그만 보여줍니다.

  • 실시간 로그 확인 (follow):

    docker-compose logs -f web

    -f 또는 --follow 플래그를 사용하면 tail -f처럼 실시간으로 로그를 계속 출력합니다. 개발 중 로그를 모니터링할 때 필수적입니다. 🕵️‍♂️

  • 로그의 마지막 N줄만 보기:

    docker-compose logs --tail 50 web

    --tail 플래그를 사용하면 로그의 마지막 50줄만 보여줍니다.

예시:

# web 서비스의 실시간 로그 확인
docker-compose logs -f web

# db 서비스의 마지막 100줄 로그 확인
docker-compose logs --tail 100 db

3.5. docker-compose exec: 실행 중인 컨테이너에 접속하기

실행 중인 서비스 컨테이너 내에서 명령어를 실행할 수 있습니다. 컨테이너 내부를 탐색하거나 특정 스크립트를 실행할 때 매우 유용합니다. 💻

  • 특정 서비스 컨테이너 내부로 접속 (쉘 접근):

    docker-compose exec web bash
    # 또는 sh, zsh 등 해당 컨테이너에 설치된 쉘

    이 명령어는 web 서비스의 컨테이너 내부로 들어가 쉘 환경에 접근하게 해줍니다. 컨테이너 내부에서 파일을 확인하거나 디버깅 작업을 할 때 많이 사용합니다.

  • 컨테이너 내부에서 특정 명령어 실행:

    docker-compose exec db psql -U user mydatabase

    db 컨테이너 내부에서 psql -U user mydatabase 명령어를 실행하여 PostgreSQL 데이터베이스에 접속합니다.

예시:

# web 컨테이너 안에서 npm install 실행 (만약 패키지 설치가 필요하다면)
docker-compose exec web npm install

# db 컨테이너 안에서 특정 SQL 파일 실행
docker-compose exec db sh -c "psql -U user mydatabase < /tmp/init.sql"

3.6. docker-compose build: 이미지 직접 빌드하기

docker-compose.yml 파일에 build 지시어가 있는 서비스의 이미지를 명시적으로 빌드합니다. docker-compose up --build와 동일한 빌드 과정을 수행하지만, 컨테이너를 시작하지 않고 이미지 빌드만 합니다.

  • 기본 사용법:

    docker-compose build

    모든 build 지시어를 가진 서비스를 빌드합니다.

  • 특정 서비스만 빌드:

    docker-compose build web

    web 서비스의 이미지만 빌드합니다.

예시:

# 새로운 Dockerfile 변경사항을 적용하기 위해 이미지 재빌드
docker-compose build web

3.7. docker-compose stop, start, restart: 컨테이너 제어하기

이 명령어들은 실행 중인 컨테이너의 상태를 제어하는 데 사용됩니다.

  • docker-compose stop: 실행 중인 모든 서비스 또는 특정 서비스를 “우아하게” 중지합니다. 컨테이너는 중지되지만 제거되지는 않으므로, 나중에 start 명령어로 다시 시작할 수 있습니다. ⏸️

    docker-compose stop          # 모든 서비스 중지
    docker-compose stop web      # web 서비스만 중지
  • docker-compose start: 이전에 stop 명령어로 중지된 서비스들을 다시 시작합니다. ⏯️

    docker-compose start         # 중지된 모든 서비스 시작
    docker-compose start web     # 중지된 web 서비스만 시작
  • docker-compose restart: 실행 중인 서비스들을 중지했다가 다시 시작합니다. 컨테이너의 설정을 변경했을 때(단, 이미지 빌드가 필요 없는 경우) 유용합니다. 🔄

    docker-compose restart          # 모든 서비스 재시작
    docker-compose restart web      # web 서비스만 재시작

3.8. docker-compose rm: 컨테이너 제거하기

중지된 서비스 컨테이너를 제거합니다. docker-compose down은 컨테이너와 네트워크를 제거하지만, rm은 이미 중지된 개별 컨테이너를 대상으로 합니다.

  • 기본 사용법:

    docker-compose rm

    현재 중지된 모든 컨테이너를 제거할지 확인 메시지를 띄웁니다.

  • 강제 제거:

    docker-compose rm -f

    -f 또는 --force 플래그를 사용하면 확인 메시지 없이 강제로 제거합니다.

예시:

# 중지된 모든 컨테이너를 확인 없이 강제 제거
docker-compose rm -f

3.9. docker-compose config: 설정 유효성 검사 및 보기

docker-compose.yml 파일의 유효성을 검사하고, Docker Compose가 실제로 해석할 최종 구성을 YAML 형식으로 출력합니다. 파일을 수정했을 때 오류가 없는지 확인하거나, 디버깅할 때 유용합니다. ✅

  • 기본 사용법:

    docker-compose config

    파일에 오류가 있다면 오류 메시지를 출력하고, 아니라면 최종 구성을 보여줍니다.

  • 경고 무시:

    docker-compose config -q

    -q 또는 --quiet 플래그는 경고만 표시하고 구성을 출력하지 않습니다. 파일 유효성만 빠르게 확인하고 싶을 때 좋습니다.

예시:

# docker-compose.yml 파일의 구성을 검증하고 출력
docker-compose config

3.10. docker-compose run: 일회성 명령어 실행하기

docker-compose.yml에 정의된 서비스 컨테이너와 동일한 환경에서 일회성 명령어를 실행합니다. 주로 마이그레이션 스크립트 실행, 테스트 실행, 디버깅 등에 사용됩니다. exec와 달리 새로운 임시 컨테이너를 생성하여 명령어를 실행한 후 종료됩니다. 🏃‍♂️

  • 기본 사용법:

    docker-compose run web npm test

    web 서비스의 이미지와 설정을 기반으로 새로운 컨테이너를 생성하고 npm test 명령어를 실행한 후, 컨테이너를 종료합니다.

  • 포트 매핑 없이 실행:

    docker-compose run --no-deps web bash

    --no-deps 플래그는 depends_on에 정의된 다른 서비스들을 시작하지 않고 해당 서비스만 실행합니다. 필요한 경우 유용합니다.

예시:

# web 서비스 컨테이너에서 데이터베이스 마이그레이션 실행
docker-compose run web npm run db:migrate

# db 서비스 컨테이너에서 PostgreSQL 클라이언트 실행 (새로운 컨테이너로)
docker-compose run db psql -U user mydatabase

4. Docker Compose 활용 팁 & 베스트 프랙티스

  • 환경 변수 관리 (.env 파일): 민감한 정보(비밀번호, API 키 등)나 환경에 따라 달라지는 값들은 docker-compose.yml에 직접 명시하기보다 .env 파일을 활용하는 것이 좋습니다.

    # .env 파일 예시
    POSTGRES_USER=myuser
    POSTGRES_PASSWORD=mypassword

    docker-compose.yml에서 environment 섹션에 변수 이름만 적으면 자동으로 .env 파일에서 값을 가져옵니다.

    # docker-compose.yml
    services:
      db:
        environment:
          POSTGRES_USER: ${POSTGRES_USER} # .env 파일에서 POSTGRES_USER 값을 가져옴
          POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

    .env 파일은 Git에 커밋하지 않도록 .gitignore에 추가하는 것이 보안상 안전합니다. 🔐

  • 여러 환경을 위한 설정 (-f 플래그): 개발, 테스트, 프로덕션 등 여러 환경에 따라 docker-compose.yml 파일이 달라질 수 있습니다. 이때 여러 파일을 사용하여 관리할 수 있습니다.

    • docker-compose.yml (기본 설정)
    • docker-compose.dev.yml (개발 환경 오버라이드)
    • docker-compose.prod.yml (프로덕션 환경 오버라이드)
      
      # 개발 환경으로 실행
      docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

    프로덕션 환경으로 실행

    docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

    
    나중에 오는 파일의 설정이 이전 파일의 설정을 덮어씁니다. 겹치는 서비스 이름이 있다면요! 🔄
  • 자원 제한 (deploy 또는 resources): 컨테이너가 너무 많은 CPU나 메모리를 사용하지 않도록 제한을 걸 수 있습니다. 특히 개발 환경에서 노트북 자원을 보호할 때 유용합니다. (Docker Compose v3.x에서는 deploy 섹션 아래 resources를 사용합니다)

    services:
      web:
        # ...
        deploy:
          resources:
            limits:
              cpus: '0.5' # 0.5 코어 제한
              memory: 512M # 512MB 메모리 제한

    이는 Docker Swarm 모드에서 더 강력하게 작동하며, 단일 호스트에서도 어느 정도 자원 제한을 제공합니다.


5. 마무리하며

이제 여러분은 Docker Compose의 핵심 명령어들을 완벽하게 익히셨습니다! 🎉 docker-compose up부터 down, ps, logs, exec, run 등 다양한 명령어들을 통해 멀티 컨테이너 애플리케이션을 효율적으로 관리할 수 있게 되었을 겁니다.

Docker Compose는 복잡한 개발 환경을 단순화하고, 팀원 간의 협업을 원활하게 하며, “내 컴퓨터에서만 되는” 문제를 해결해 주는 강력한 도구입니다. 이 가이드를 통해 얻은 지식을 바탕으로 여러분의 개발 워크플로우가 훨씬 더 생산적이고 즐거워지기를 바랍니다! 😊

꾸준히 연습하고 다양한 프로젝트에 적용해 보면서 Docker Compose의 진정한 힘을 느껴보세요. 궁금한 점이나 더 알고 싶은 내용이 있다면 언제든지 댓글로 남겨주세요!

다음 글에서 또 만나요! 해피 코딩! 💻💖

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다