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_data
와wp_data
라는 두 개의 명명된 볼륨을 정의합니다.networks
(최상위):wordpress-network
라는 사용자 정의 네트워크를 생성하여db
와wordpress
서비스가 이 네트워크를 통해 안전하게 통신하도록 합니다.
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: always
나restart: 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를 사용하다 보면 몇 가지 흔한 문제에 직면할 수 있습니다. 당황하지 마세요! 대부분 쉽게 해결 가능합니다. 😊
- 포트 충돌 (Port Conflict)
- 문제: “port is already allocated” 또는 “bind: address already in use” 에러 메시지가 뜹니다. 호스트 머신의 특정 포트가 이미 다른 프로그램이나 다른 Docker 컨테이너에 의해 사용 중일 때 발생합니다.
- 해결:
docker-compose.yml
파일의ports
섹션에서 호스트 포트 번호를 변경하거나, 해당 포트를 사용 중인 프로그램을 종료합니다. (예:"8080:80"
으로 변경)
- 볼륨 권한 문제 (Volume Permissions)
- 문제: 컨테이너 내부에서 파일 쓰기/읽기 권한 오류가 발생합니다. 특히 Linux/macOS에서 호스트의 특정 폴더를 마운트할 때 컨테이너 내부의 사용자(보통 root가 아님)가 해당 폴더에 접근/쓰기 권한이 없을 때 발생합니다.
- 해결: 호스트 폴더의 권한을 컨테이너 내부 사용자가 접근할 수 있도록 변경하거나,
docker-compose.yml
에서 컨테이너 내부 사용자 ID/그룹 ID를 명시적으로 설정하는user
옵션을 고려합니다. (초보자는 명명된 볼륨 사용을 권장)
- 서비스 간 통신 실패
- 문제:
wordpress
서비스가db
서비스에 연결하지 못하는 등 서비스 간에 통신이 안 됩니다. “unknown host”, “connection refused” 같은 에러가 발생합니다. - 해결:
WORDPRESS_DB_HOST
와 같은 환경 변수에서 서비스 이름을 정확히 사용했는지 확인합니다. (예:db
가 아닌localhost
를 사용하지 않았는지)- 모든 서비스가 동일한 네트워크에 연결되어 있는지 확인합니다.
depends_on
으로 순서가 보장되었는지 확인하고, 그래도 안되면healthcheck
를 사용하여 서비스가 완전히 준비될 때까지 기다리도록 설정할 수 있습니다. (고급)
- 문제:
- 환경 변수 미적용
- 문제: 설정한 환경 변수가 컨테이너 내부에 적용되지 않는 것 같습니다.
- 해결:
docker-compose.yml
파일에서 환경 변수 오타를 확인합니다.- 서비스를 재시작해야 환경 변수가 새로 적용됩니다.
docker-compose up -d
나docker-compose restart [서비스명]
을 사용합니다. docker-compose exec [서비스명] printenv
명령어로 컨테이너 내부의 환경 변수를 직접 확인해봅니다.
문제 해결의 핵심은 로그 확인입니다! docker-compose logs [서비스명]
명령어로 에러 메시지를 자세히 살펴보세요. 대부분의 단서는 로그에 있습니다. 🕵️♂️
마무리하며: 이제 당신도 Docker Compose 전문가! 🎓
축하합니다! 🎉 이 가이드를 통해 Docker Compose의 기본 개념부터 실전 예제, 그리고 유용한 팁과 문제 해결 방법까지 모두 마스터하셨습니다. Docker Compose는 다중 컨테이너 애플리케이션을 효율적으로 개발하고 배포하는 데 필수적인 도구입니다. 이제 복잡한 설정에 얽매이지 않고, 원하는 서비스를 원하는 대로 구성하고 실행할 수 있는 자유를 만끽하세요! 🚀
오늘 배운 내용을 바탕으로 자신만의 Docker Compose 프로젝트를 시작해보세요. 공식 문서를 참고하거나 더 복잡한 스택을 구성해보는 것도 좋습니다. 꾸준히 연습하면 더욱 강력한 개발자가 될 수 있을 거예요! 궁금한 점이 있다면 언제든지 찾아보고 질문하며 성장해나가시길 바랍니다. Happy Dockering! 🐳