도커(Docker) 컨테이너의 편리함에 눈을 뜨고 나면, 곧바로 새로운 장벽에 부딪히게 됩니다. 실제 서비스는 웹 서버(Nginx) 하나로만 굴러가지 않기 때문입니다. 데이터를 저장할 데이터베이스(MySQL), 동적 처리를 위한 백엔드(Spring, Node.js) 등 여러 개의 컨테이너가 톱니바퀴처럼 맞물려 돌아가야 합니다.
이 여러 개의 컨테이너를 매번 긴 docker run 명령어를 쳐서 하나씩 실행하고, 서로 통신할 수 있게 네트워크를 묶어주는 작업은 매우 고통스럽고 휴먼 에러(실수)를 유발하기 쉽습니다.
이러한 복잡한 다중 서버 환경을 단 하나의 파일과 명령어 한 줄로 통제할 수 있게 해주는 마법 같은 도구가 바로 **도커 컴포즈(Docker Compose)**입니다. 오늘은 백엔드 개발자와 시스템 엔지니어의 필수 스킬인 도커 컴포즈의 개념과, 웹 서버(Nginx)와 데이터베이스(MySQL)를 한 번에 띄우는 실전 구축 방법을 상세히 알아보겠습니다.
1. 도커 컴포즈(Docker Compose)란 무엇인가요?
도커가 개별 ‘컨테이너(화물)’를 만드는 기술이라면, **도커 컴포즈는 이 여러 개의 컨테이너를 지휘하는 ‘오케스트라 지휘자’**입니다.
복잡한 컨테이너 실행 조건(포트 매핑, 환경 변수, 볼륨, 네트워크 등)을 터미널에 매번 타이핑하는 대신, **docker-compose.yml**이라는 텍스트 파일(설계도)에 미리 깔끔하게 정리해 둡니다. 그리고 지휘자에게 “이 설계도대로 연주해 줘!”라고 명령(docker-compose up) 한 번만 내리면, 수십 개의 서버가 정해진 순서와 규칙에 맞게 동시에 실행되는 혁신적인 도구입니다.
2. 왜 도커 컴포즈를 써야 할까? (핵심 장점 3가지)
- 인프라의 코드화 (IaC, Infrastructure as Code): 서버 세팅 명세서가
.yml파일 하나로 정리되므로, 이 파일만 깃허브(GitHub)에 올려두면 새로운 팀원이 와도 1분 만에 완벽히 똑같은 개발 환경을 구축할 수 있습니다. - 자동화된 네트워크 격리 (내부 통신망 생성): 컴포즈로 실행된 컨테이너들은 자동으로 같은 ‘가상 네트워크 망’ 안에 묶입니다. 따라서 웹 서버에서 DB에 접속할 때 복잡한 IP 주소를 외울 필요 없이, 단순히 서비스 이름(예:
db)만 입력해도 서로 완벽하게 통신이 가능합니다. - 실행 및 종료의 간편함: 명령어 한 줄로 전체 시스템을 켜고, 또 명령어 한 줄로 전체 시스템을 깔끔하게 종료하고 삭제할 수 있습니다.
3. 실전! Web(Nginx) + DB(MySQL) 다중 서버 환경 구축하기
이제 실제로 가장 널리 쓰이는 조합인 Nginx 웹 서버와 MySQL 데이터베이스를 도커 컴포즈로 한 번에 실행해 보겠습니다.
[Step 1] 작업용 폴더 및 파일 생성
먼저 원하는 위치에 폴더를 하나 만들고, 그 안에 docker-compose.yml 파일을 생성합니다.
Bash
mkdir my-web-server
cd my-web-server
nano docker-compose.yml
[Step 2] docker-compose.yml 설계도 작성
에디터가 열리면 아래의 코드를 작성합니다. YAML 파일은 ‘들여쓰기(띄어쓰기)’가 문법이므로 간격에 매우 주의해야 합니다. (보통 스페이스바 2칸 단위로 들여쓰기합니다.)
YAML
version: '3.8' # 컴포즈 파일의 버전 (최신 규격)
services: # 실행할 컨테이너들의 목록을 정의합니다.
# 1. 웹 서버 (Nginx)
web:
image: nginx:latest # 도커 허브에서 최신 Nginx 이미지를 다운로드합니다.
ports:
- "80:80" # 외부의 80번 포트로 들어오면, 컨테이너의 80번 포트로 연결합니다.
depends_on:
- db # db 컨테이너가 먼저 실행된 후에 web 컨테이너를 실행하라는 옵션입니다.
# 2. 데이터베이스 (MySQL)
db:
image: mysql:8.0
environment: # MySQL 초기 세팅을 위한 환경 변수입니다.
MYSQL_ROOT_PASSWORD: my_root_password # (주의) 실무에서는 복잡하게 설정하세요.
MYSQL_DATABASE: my_database # 컨테이너 생성 시 자동으로 만들어질 DB 이름
volumes:
- db_data:/var/lib/mysql # DB 데이터가 날아가지 않도록 외부 볼륨에 영구 저장합니다.
volumes:
db_data: # db 서비스에서 사용할 볼륨을 선언합니다.
[Step 3] 마법의 명령어, 실행하기!
파일을 저장하고 빠져나온 뒤, 해당 폴더 안에서 아래 명령어를 입력합니다.
Bash
docker-compose up -d
-d(detach) 옵션은 백그라운드에서 실행하라는 뜻입니다. 이 옵션을 빼면 터미널 창에 로그가 계속 출력되어 다른 작업을 할 수 없습니다.
명령어를 치면 도커가 알아서 Nginx와 MySQL 이미지를 다운로드하고, 네트워크를 묶고, 볼륨을 생성한 뒤 두 개의 서버를 동시에 구동시킵니다. 웹 브라우저를 열고 http://localhost (또는 서버의 공인 IP)로 접속하면 Nginx의 ‘Welcome to nginx!’ 화면이 나타납니다.
4. 알아두면 평생 쓰는 도커 컴포즈 필수 명령어 3대장
컴포즈를 구동했다면 관리를 위한 명령어도 세트(Set)로 알아두어야 합니다. (docker-compose.yml 파일이 있는 폴더에서 실행해야 합니다.)
- 상태 확인 (
docker-compose ps): 현재 컴포즈 명세서에 의해 실행된 컨테이너들의 목록과 상태(Up, Exit 등), 그리고 열려있는 포트 정보를 한눈에 보여줍니다. - 로그 확인 (
docker-compose logs -f): 웹 서버나 DB에서 에러가 났을 때 원인을 파악하기 위해 씁니다. 두 컨테이너에서 발생하는 실시간 로그를 섞어서 한 화면에 출력해 주어 트러블슈팅에 매우 유리합니다. - 깔끔한 종료 및 삭제 (
docker-compose down): 실행 중인 모든 컨테이너를 중지하고, 묶어두었던 가상 네트워크 망까지 완벽하게 철거합니다. (단, 볼륨에 저장된 데이터는 삭제되지 않으므로 안전합니다.)
결론: 아키텍처 확장의 시작점, 도커 컴포즈
웹 서버와 DB를 띄우는 이 기본적인 템플릿에, 나중에는 Redis(캐시 서버), Spring Boot(백엔드 서버), Prometheus(모니터링 서버) 등을 services 아래에 계속 추가해 나가기만 하면 아무리 거대한 시스템이라도 명령어 한 줄로 통제할 수 있게 됩니다.
이 강력한 무기를 손에 쥐셨다면, 이제 더 이상 서버 환경 세팅에 두려움을 가질 필요가 없습니다. 이번에 구축하신 Nginx와 MySQL 환경을 바탕으로, 혹시 워드프레스나 특정 백엔드 프레임워크를 추가로 연동해 보고 싶으신 계획이 있으신가요?