화. 8월 12th, 2025

G: “`html

여러 개의 컨테이너를 한 번에 관리하는 것이 어렵게 느껴지셨나요? 🤯 복잡한 마이크로서비스 아키텍처나 다중 컨테이너 애플리케이션을 단 한 줄의 명령어로 손쉽게 배포하고 관리하고 싶으신가요? 그렇다면 Docker Compose가 바로 당신을 위한 해답입니다! 이 가이드에서는 Docker Compose가 무엇인지부터 시작하여, 초보자도 쉽게 따라 할 수 있는 실전 예제를 통해 완벽하게 작성하고 활용하는 방법을 알려드릴게요. 이제 컨테이너 오케스트레이션의 첫걸음을 함께 내딛어 봅시다! 🚀

🚀 Docker Compose, 도대체 무엇인가요?

Docker Compose는 여러 개의 Docker 컨테이너를 정의하고 실행하는 도구입니다. 간단히 말해, 복수의 컨테이너로 이루어진 애플리케이션을 YAML 파일 하나로 한 번에 정의하고 관리할 수 있게 해주는 마법 같은 도구죠! ✨

왜 Docker Compose를 사용해야 할까요?

  • 단순성: 복잡한 docker run 명령어를 여러 번 입력할 필요 없이, 하나의 docker-compose.yml 파일로 모든 설정을 정의할 수 있습니다.
  • 일관성: 개발, 테스트, 배포 환경에 걸쳐 애플리케이션 스택을 일관되게 유지할 수 있습니다. “내 컴퓨터에서는 됐는데…” 라는 말이 사라지는 거죠! 🥳
  • 생산성 향상: 개발 환경을 빠르게 구축하고, 필요한 서비스를 손쉽게 띄우고 내릴 수 있어 개발 생산성이 크게 향상됩니다.
  • 로컬 개발 용이성: 실제 운영 환경과 유사한 다중 서비스 환경을 로컬에서 쉽게 구성하여 테스트할 수 있습니다.

🧱 Docker Compose의 기본 구조 이해하기: docker-compose.yml

Docker Compose는 docker-compose.yml 이라는 YAML 파일을 사용하여 애플리케이션의 서비스들을 정의합니다. 이 파일은 Docker Compose에게 “어떤 컨테이너를 만들고, 어떻게 연결하며, 어떤 설정을 가질 것인지”를 알려주는 설계도와 같습니다. 📝

주요 구성 요소


version: '3.8' # Docker Compose 파일 형식 버전 (필수)
services: # 정의할 서비스(컨테이너) 목록
  web: # 서비스 이름 (임의 지정 가능)
    image: nginx:latest # 사용할 Docker 이미지
    ports: # 포트 매핑 (호스트 포트:컨테이너 포트)
      - "80:80"
    volumes: # 볼륨 마운트 (호스트 경로:컨테이너 경로)
      - ./nginx/conf.d:/etc/nginx/conf.d
    environment: # 환경 변수 설정
      - NGINX_PORT=80
    depends_on: # 서비스 간 의존성 (web 서비스는 db 서비스가 먼저 시작되어야 함)
      - db
    networks: # 사용할 네트워크 지정
      - app-network
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network

volumes: # 명명된 볼륨 정의
  db_data:

networks: # 사용자 정의 네트워크 정의
  app-network:
    driver: bridge # 네트워크 드라이버 (기본값)

각 구성 요소에 대한 자세한 설명은 다음과 같습니다:

  • version: Docker Compose 파일의 버전을 명시합니다. 최신 버전을 사용하는 것이 좋습니다. (예: ‘3.8’)
  • services: 애플리케이션을 구성하는 모든 컨테이너 서비스를 정의하는 부분입니다. 각 서비스는 별도의 컨테이너로 실행됩니다.
  • image: 해당 서비스에 사용할 Docker 이미지를 지정합니다. (예: nginx:latest, mysql:8.0)
  • ports: 호스트 머신의 포트와 컨테이너 내부의 포트를 연결합니다. (예: "80:80"은 호스트의 80번 포트를 컨테이너의 80번 포트에 연결합니다.)
  • volumes: 데이터를 영구적으로 저장하거나, 호스트 머신의 파일을 컨테이너 내부에 마운트할 때 사용합니다. (예: ./data:/app/data)
  • environment: 컨테이너 내부에서 사용할 환경 변수를 설정합니다. 데이터베이스 연결 정보나 API 키 등을 여기에 설정할 수 있습니다.
  • depends_on: 서비스 간의 의존성을 정의합니다. 예를 들어, 웹 서비스가 데이터베이스 서비스보다 먼저 시작되어야 할 때 사용합니다. (컨테이너 시작 순서만 보장하며, 서비스가 완전히 준비되었음을 보장하지는 않습니다.)
  • networks: 서비스들이 통신할 네트워크를 지정합니다. 기본적으로는 하나의 기본 네트워크가 생성되지만, 사용자 정의 네트워크를 사용할 수 있습니다.
  • volumes (최상위): 명명된 볼륨(Named Volumes)을 정의하여 데이터를 영구적으로 저장할 때 사용합니다.
  • networks (최상위): 사용자 정의 네트워크를 정의할 때 사용합니다.

🛠️ 실전 예제 1: 간단한 웹 애플리케이션 (Nginx + Static HTML)

가장 간단한 예제로, Nginx 웹 서버를 사용하여 정적 HTML 페이지를 서빙하는 애플리케이션을 만들어 봅시다.

1단계: 프로젝트 폴더 생성 및 파일 준비

먼저, 프로젝트를 위한 폴더를 만들고 그 안에 필요한 파일들을 생성합니다.


mkdir my-nginx-app
cd my-nginx-app
mkdir html

html 폴더 안에 index.html 파일을 생성하고 다음 내용을 입력합니다.


<!-- html/index.html -->



    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Hello Docker Compose!</title>

<style>
        body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; background-color: #f0f8ff; }
        h1 { color: #2e8b57; }
        p { color: #4682b4; }
    </style>



<h1>👋 Hello from Docker Compose!</h1>

<p>이 페이지는 Nginx와 Docker Compose로 서빙되고 있습니다.</p>

<p>정말 쉽죠? 🎉</p>


2단계: docker-compose.yml 파일 작성

my-nginx-app 폴더 안에 docker-compose.yml 파일을 생성하고 다음 내용을 입력합니다.


# docker-compose.yml
version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80" # 호스트의 80번 포트와 컨테이너의 80번 포트를 연결
    volumes:
      - ./html:/usr/share/nginx/html:ro # 현재 폴더의 html을 Nginx의 웹 루트에 마운트 (읽기 전용)
    restart: always # 컨테이너가 종료될 경우 항상 재시작

설명:

  • web: 우리가 만들 서비스의 이름입니다.
  • image: nginx:latest: 최신 Nginx 이미지를 사용합니다.
  • ports: - "80:80": 호스트 머신의 80번 포트를 컨테이너의 80번 포트(Nginx 기본 포트)에 연결합니다. 이제 웹 브라우저에서 http://localhost로 접속할 수 있습니다.
  • volumes: - ./html:/usr/share/nginx/html:ro: 현재 디렉토리의 html 폴더를 Nginx 컨테이너의 웹 서버 루트 디렉토리(/usr/share/nginx/html)에 마운트합니다. :ro는 읽기 전용(Read-Only)을 의미하여 컨테이너가 호스트의 파일을 변경하는 것을 방지합니다.
  • restart: always: 컨테이너가 어떤 이유로든 종료되면 항상 자동으로 다시 시작하도록 설정합니다.

3단계: Docker Compose 실행

이제 my-nginx-app 폴더에서 다음 명령어를 실행합니다.


docker-compose up -d
  • up: docker-compose.yml 파일에 정의된 서비스들을 시작합니다.
  • -d (--detach): 백그라운드에서 컨테이너를 실행합니다. 터미널을 점유하지 않아 다른 작업을 할 수 있습니다.

명령어 실행 후, 웹 브라우저를 열고 http://localhost에 접속해보세요. “Hello from Docker Compose!” 메시지가 보이면 성공입니다! 🎉

4단계: 서비스 중지 및 삭제

서비스 사용을 마쳤거나 변경 사항을 적용하고 싶다면 다음 명령어로 서비스를 중지하고 관련 리소스(컨테이너, 네트워크)를 삭제할 수 있습니다.


docker-compose down
  • down: up 명령어로 생성된 모든 컨테이너, 네트워크, 볼륨(명시적으로 제거하지 않으면 유지)을 중지하고 삭제합니다.

더 깔끔하게 삭제하고 싶다면, 볼륨까지 강제로 삭제하는 -v 옵션을 추가할 수 있습니다. 주의: 이 명령은 데이터 볼륨의 모든 데이터를 삭제합니다!


docker-compose down -v

⚙️ 실전 예제 2: 워드프레스 블로그 스택 (WordPress + MySQL)

이제 조금 더 복잡한 예제로, 실제 많이 사용되는 워드프레스(WordPress)와 MySQL 데이터베이스를 Docker Compose로 함께 배포하는 방법을 알아봅시다. 워드프레스는 PHP 기반의 웹 애플리케이션이고, MySQL은 데이터베이스입니다. 두 서비스가 서로 통신해야 합니다.

1단계: 프로젝트 폴더 생성 및 docker-compose.yml 작성

새로운 프로젝트 폴더를 만들고 docker-compose.yml 파일을 생성합니다.


mkdir my-wordpress-blog
cd my-wordpress-blog

my-wordpress-blog 폴더 안에 docker-compose.yml 파일을 생성하고 다음 내용을 입력합니다.


# docker-compose.yml
version: '3.8'
services:
  db:
    image: mysql:8.0 # MySQL 8.0 이미지 사용
    command: --default-authentication-plugin=mysql_native_password # 인증 플러그인 설정 (워드프레스 호환성)
    environment: # MySQL 환경 변수 설정 (중요!)
      MYSQL_ROOT_PASSWORD: your_root_password # 루트 비밀번호 (실제 사용 시 강력한 비밀번호로 변경하세요!)
      MYSQL_DATABASE: wordpress # 워드프레스가 사용할 데이터베이스 이름
      MYSQL_USER: wordpress # 워드프레스가 사용할 사용자 이름
      MYSQL_PASSWORD: wordpress_password # 워드프레스가 사용할 사용자 비밀번호
    volumes:
      - db_data:/var/lib/mysql # 데이터 영속성을 위한 볼륨 마운트
    networks:
      - wordpress-network # db 서비스가 사용할 네트워크
    restart: always

  wordpress:
    image: wordpress:latest # 최신 워드프레스 이미지 사용
    ports:
      - "80:80" # 호스트의 80번 포트와 컨테이너의 80번 포트를 연결
    environment: # 워드프레스 환경 변수 설정
      WORDPRESS_DB_HOST: db:3306 # 데이터베이스 호스트 (db 서비스 이름과 포트)
      WORDPRESS_DB_USER: wordpress # 위에서 설정한 MySQL 사용자 이름
      WORDPRESS_DB_PASSWORD: wordpress_password # 위에서 설정한 MySQL 사용자 비밀번호
      WORDPRESS_DB_NAME: wordpress # 위에서 설정한 MySQL 데이터베이스 이름
    volumes:
      - wp_data:/var/www/html # 워드프레스 파일 영속성을 위한 볼륨 마운트
    depends_on:
      - db # wordpress 서비스는 db 서비스가 먼저 시작되어야 함
    networks:
      - wordpress-network # wordpress 서비스가 사용할 네트워크
    restart: always

volumes: # 명명된 볼륨 정의
  db_data:
  wp_data:

networks: # 사용자 정의 네트워크 정의
  wordpress-network:
    driver: bridge

설명:

  • db 서비스:
    • image: mysql:8.0: MySQL 8.0 버전을 사용합니다.
    • command: --default-authentication-plugin=mysql_native_password: MySQL 8.0의 기본 인증 방식이 워드프레스와 호환되지 않을 수 있어, 호환 가능한 플러그인으로 설정해줍니다.
    • environment: MySQL 컨테이너의 초기 설정을 위한 환경 변수들입니다. 실제 운영 환경에서는 절대 위와 같이 간단한 비밀번호를 사용하면 안 됩니다! MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD가 중요합니다.
    • volumes: - db_data:/var/lib/mysql: db_data라는 명명된 볼륨을 사용하여 MySQL 데이터가 컨테이너가 삭제되어도 유지되도록 합니다.
  • wordpress 서비스:
    • image: wordpress:latest: 최신 워드프레스 이미지를 사용합니다.
    • ports: - "80:80": 호스트의 80번 포트를 워드프레스 컨테이너의 80번 포트에 연결합니다.
    • environment: 워드프레스가 데이터베이스에 연결하기 위한 환경 변수들입니다.
      • WORDPRESS_DB_HOST: db:3306: 여기서 db는 Docker Compose 파일에 정의된 MySQL 서비스의 이름입니다. 같은 네트워크 상에 있으므로 서비스 이름으로 통신이 가능합니다. :3306은 MySQL의 기본 포트입니다.
      • 나머지 변수들은 MySQL 서비스에서 설정한 값과 일치해야 합니다.
    • volumes: - wp_data:/var/www/html: wp_data라는 명명된 볼륨을 사용하여 워드프레스 설치 파일, 테마, 플러그인 등이 컨테이너 삭제 후에도 유지되도록 합니다.
    • depends_on: - db: 워드프레스 서비스는 db 서비스가 시작된 후에 시작되어야 함을 명시합니다.
  • volumes (최상위): db_datawp_data라는 두 개의 명명된 볼륨을 정의합니다.
  • networks (최상위): wordpress-network라는 사용자 정의 네트워크를 생성하여 dbwordpress 서비스가 이 네트워크를 통해 안전하게 통신하도록 합니다.

2단계: Docker Compose 실행

my-wordpress-blog 폴더에서 다음 명령어를 실행합니다.


docker-compose up -d

컨테이너 이미지를 다운로드하고 서비스들을 시작하는 데 시간이 조금 걸릴 수 있습니다. 모든 컨테이너가 정상적으로 시작되었는지 확인하려면 다음 명령어를 사용합니다.


docker-compose ps

두 서비스 모두 Up 상태여야 합니다. 이제 웹 브라우저를 열고 http://localhost에 접속하면 워드프레스 설치 화면이 나타날 것입니다. 🥳 설치 절차를 따라 워드프레스 블로그를 완성해 보세요!

3단계: 서비스 중지 및 삭제

마찬가지로, 서비스를 중지하고 싶다면:


docker-compose down

데이터를 포함하여 모든 것을 삭제하고 싶다면 (주의!):


docker-compose down -v

✨ 유용한 Docker Compose 명령어들

Docker Compose를 사용하면서 자주 쓰게 될 명령어들을 알아봅시다.

  • docker-compose up: 모든 서비스를 시작합니다. -d 옵션으로 백그라운드 실행.
  • docker-compose up --build: 서비스를 시작하고, Dockerfile 기반으로 이미지를 빌드해야 하는 경우 이미지를 다시 빌드합니다. 코드 변경 후 반영할 때 유용합니다.
  • docker-compose down: 모든 서비스를 중지하고 관련 리소스를 제거합니다. -v 옵션으로 볼륨도 제거.
  • docker-compose ps: 현재 실행 중인 서비스들의 상태를 보여줍니다.
  • docker-compose logs [서비스명]: 특정 서비스 또는 모든 서비스의 로그를 확인합니다. -f 옵션으로 실시간 로그를 볼 수 있습니다. (예: docker-compose logs -f wordpress)
  • docker-compose exec [서비스명] [명령]: 실행 중인 컨테이너 내부로 들어가 명령어를 실행합니다. (예: docker-compose exec wordpress bash)
  • docker-compose start [서비스명]: 중지된 서비스를 시작합니다.
  • docker-compose stop [서비스명]: 실행 중인 서비스를 중지합니다.
  • docker-compose restart [서비스명]: 실행 중인 서비스를 재시작합니다.

💡 Docker Compose 사용 팁 & 베스트 프랙티스

  • .env 파일 활용: 비밀번호나 API 키와 같은 민감한 정보는 docker-compose.yml 파일에 직접 노출하지 않고, .env 파일에 별도로 관리하는 것이 좋습니다. docker-compose.yml에서 ${변수명} 형식으로 참조할 수 있습니다. .env 파일은 Git에 커밋하지 않도록 .gitignore에 추가하세요.
  • 명명된 볼륨(Named Volumes) 사용: 데이터 영속성을 위해 호스트 경로 마운트보다 명명된 볼륨을 사용하는 것이 좋습니다. Docker가 볼륨을 관리하므로 파일 시스템 권한 문제 등에 덜 민감하고, 더 이식성이 좋습니다.
  • 네트워크 정의: 명시적으로 사용자 정의 네트워크를 정의하여 서비스 간의 통신을 더 명확하게 관리하세요. 기본 브릿지 네트워크보다 보안성이 높고 구조화하기 좋습니다.
  • restart 정책 설정: restart: alwaysrestart: unless-stopped와 같은 정책을 설정하여 컨테이너가 예상치 않게 종료될 경우 자동으로 재시작되도록 하세요.
  • 버전 관리: docker-compose.yml 파일을 Git과 같은 버전 관리 시스템에 추가하여 팀원들과 공유하고 변경 이력을 관리하세요.
  • 환경별 설정 관리: 개발, 테스트, 운영 등 환경에 따라 다른 설정을 사용해야 할 경우, 여러 개의 docker-compose.yml 파일을 조합하여 사용하는 방법을 고려해 보세요 (예: docker-compose.yml, docker-compose.prod.yml). docker-compose -f docker-compose.yml -f docker-compose.prod.yml up과 같이 사용할 수 있습니다.

⚠️ 흔히 겪는 문제와 해결 방법

Docker Compose를 사용하다 보면 몇 가지 흔한 문제에 직면할 수 있습니다. 당황하지 마세요! 대부분 쉽게 해결 가능합니다. 😊

  1. 포트 충돌 (Port Conflict)
    • 문제: “port is already allocated” 또는 “bind: address already in use” 에러 메시지가 뜹니다. 호스트 머신의 특정 포트가 이미 다른 프로그램이나 다른 Docker 컨테이너에 의해 사용 중일 때 발생합니다.
    • 해결: docker-compose.yml 파일의 ports 섹션에서 호스트 포트 번호를 변경하거나, 해당 포트를 사용 중인 프로그램을 종료합니다. (예: "8080:80"으로 변경)
  2. 볼륨 권한 문제 (Volume Permissions)
    • 문제: 컨테이너 내부에서 파일 쓰기/읽기 권한 오류가 발생합니다. 특히 Linux/macOS에서 호스트의 특정 폴더를 마운트할 때 컨테이너 내부의 사용자(보통 root가 아님)가 해당 폴더에 접근/쓰기 권한이 없을 때 발생합니다.
    • 해결: 호스트 폴더의 권한을 컨테이너 내부 사용자가 접근할 수 있도록 변경하거나, docker-compose.yml에서 컨테이너 내부 사용자 ID/그룹 ID를 명시적으로 설정하는 user 옵션을 고려합니다. (초보자는 명명된 볼륨 사용을 권장)
  3. 서비스 간 통신 실패
    • 문제: wordpress 서비스가 db 서비스에 연결하지 못하는 등 서비스 간에 통신이 안 됩니다. “unknown host”, “connection refused” 같은 에러가 발생합니다.
    • 해결:
      • WORDPRESS_DB_HOST와 같은 환경 변수에서 서비스 이름을 정확히 사용했는지 확인합니다. (예: db가 아닌 localhost를 사용하지 않았는지)
      • 모든 서비스가 동일한 네트워크에 연결되어 있는지 확인합니다.
      • depends_on으로 순서가 보장되었는지 확인하고, 그래도 안되면 healthcheck를 사용하여 서비스가 완전히 준비될 때까지 기다리도록 설정할 수 있습니다. (고급)
  4. 환경 변수 미적용
    • 문제: 설정한 환경 변수가 컨테이너 내부에 적용되지 않는 것 같습니다.
    • 해결:
      • docker-compose.yml 파일에서 환경 변수 오타를 확인합니다.
      • 서비스를 재시작해야 환경 변수가 새로 적용됩니다. docker-compose up -ddocker-compose restart [서비스명]을 사용합니다.
      • docker-compose exec [서비스명] printenv 명령어로 컨테이너 내부의 환경 변수를 직접 확인해봅니다.

문제 해결의 핵심은 로그 확인입니다! docker-compose logs [서비스명] 명령어로 에러 메시지를 자세히 살펴보세요. 대부분의 단서는 로그에 있습니다. 🕵️‍♂️

마무리하며: 이제 당신도 Docker Compose 전문가! 🎓

축하합니다! 🎉 이 가이드를 통해 Docker Compose의 기본 개념부터 실전 예제, 그리고 유용한 팁과 문제 해결 방법까지 모두 마스터하셨습니다. Docker Compose는 다중 컨테이너 애플리케이션을 효율적으로 개발하고 배포하는 데 필수적인 도구입니다. 이제 복잡한 설정에 얽매이지 않고, 원하는 서비스를 원하는 대로 구성하고 실행할 수 있는 자유를 만끽하세요! 🚀

오늘 배운 내용을 바탕으로 자신만의 Docker Compose 프로젝트를 시작해보세요. 공식 문서를 참고하거나 더 복잡한 스택을 구성해보는 것도 좋습니다. 꾸준히 연습하면 더욱 강력한 개발자가 될 수 있을 거예요! 궁금한 점이 있다면 언제든지 찾아보고 질문하며 성장해나가시길 바랍니다. Happy Dockering! 🐳

답글 남기기

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