
도커 컴포즈, 왜 명령어를 하나씩 입력하고 계신가요?
터미널 창에 docker run 명령어를 대여섯 개씩 복사해서 붙여넣고 계신가요? 네트워크 설정을 맞추느라 한참을 고민하고, 볼륨 연결을 깜빡해서 데이터가 날아간 경험이 있다면 이제는 도커 컴포즈로 갈아탈 때가 되었어요.
컨테이너 하나를 띄우는 건 쉽지만, 웹 서버와 데이터베이스, 그리고 캐시 서버까지 연결된 복잡한 환경을 수동으로 구성하는 건 정말 고된 일이에요. 명령어 하나만 잘못 입력해도 전체 서비스가 먹통이 되곤 하죠. 이런 번거로움을 해결해 주는 것이 바로 도커 컴포즈(Docker Compose)예요.
도커 컴포즈를 사용하면 여러 개의 컨테이너 설정을 하나의 파일로 관리할 수 있어요. 마치 요리 레시피처럼, 파일 하나만 실행하면 복잡한 인프라 환경이 마법처럼 한 번에 구축돼요. 이 글을 읽고 나면 단순한 설치를 넘어, 실무에서 바로 쓸 수 있는 수준의 설정 파일 작성 능력을 갖추게 될 거예요.
- 도커 컴포즈를 시작하기 위한 기본 개념과 준비물
- 가장 쉬운 최소 구성 예제부터 실무형 확장 예제까지
- 설정 값이 틀렸을 때 나타나는 증상과 해결법
- 명령어 하나로 설정 파일의 오류를 찾아내는 검증 방법
실행 전 반드시 확인해야 할 준비 사항
도커 컴포즈를 제대로 활용하려면 무작정 파일을 쓰기 전에 몇 가지 기본 도구와 지식이 필요해요. 준비 없이 시작했다가는 YAML 문법 오류 때문에 몇 시간을 허비할 수 있거든요.
필수 전제 조건
가장 먼저 컴퓨터에 도커 엔진(Docker Engine)이 설치되어 있어야 해요. 최신 버전의 도커 데스크톱(Docker Desktop)을 사용 중이라면 도커 컴포즈는 이미 포함되어 있어요. 리눅스 서버 환경이라면 도커와 별개로 컴포즈 플러그인을 추가로 설치해야 할 수도 있으니 확인이 필요해요.
또한, YAML(YAML Ain’t Markup Language)
형식에 익숙해져야 해요. YAML은 들여쓰기(Indentation)에 매우 민감해요. 탭(Tab) 키를 쓰느냐, 스페이스(Space)를 쓰느냐에 따라 설정 파일이 완전히 망가질 수 있으니 주의해야 해요. 반드시 스페이스 2칸 또는 4칸으로 들여쓰기 규칙을 통일하는 습관을 들여보세요.
도커 CLI vs 도커 컴포즈 비교
내가 지금 어떤 방식을 써야 할지 고민된다면 아래 표를 참고해 보세요.
| 비교 항목 | 도커 CLI (docker run) | 도커 컴포즈 (docker compose) | ||
|---|---|---|---|---|
| 관리 방식 | 개별 컨테이너 단위 명령 실행 | YAML 파일 기반 일괄 관리 | ||
| 설정 재사용성 | 매번 긴 명령어를 입력해야 함 | 파일만 실행하면 즉시 동일 환경 구축 | ||
| 네트워크/볼륨 | 수동으로 네트워크 생성 및 연결 | 적합한 용도 | 단일 컨테이너 테스트 | 복합적인 애플리케이션 환경 운영 |
결론적으로, 혼자서 가벼운 테스트를 할 때는 명령어가 편할 수 있지만, 서비스의 구조를 유지하고 팀원들과 공유하려면 도커 컴포즈 설정 예제를 통해 표준화된 파일을 만드는 것이 훨씬 유리해요.
실무 적용을 위한 단계별 설정 가이드
이제 본격적으로 docker-compose.yml 파일을 작성해 볼게요. 아주 기초적인 수준부터 실제 업무에서 마주하게 될 복잡한 환경까지 순서대로 따라오시면 돼요.
STEP 1. 가장 기초적인 웹 서버 구성하기
먼저 가장 단순한 형태의 설정을 살펴볼게요. Nginx 웹 서버 하나만 띄우는 설정이에요. 이 예제는 도커 컴포즈의 기본 구조를 이해하는 데 아주 좋아요.
services: 아래에 우리가 띄울 컨테이너 목록이 들어갑니다. 각 서비스는 고유한 이름을 가져요.
services:
web-server:
image: nginx:latest
ports:
- "8080:80"
여기서 image는 사용할 컨테이너의 이미지를 지정해요. ports는 호스트 컴퓨터와 컨테이너 사이의 통로를 여는 아주 중요한 옵션이에요. “8080:80”이라고 적으면, 여러분의 브라우저에서 localhost:8080으로 접속했을 때 컨테이너 내부의 80번 포트로 연결된다는 뜻이에요. 왼쪽이 내 컴퓨터 포트, 오른쪽이 컨테이너 포트라는 것만 기억하세요.
STEP 2. 데이터베이스와 네트워크 연결하기
실제 앱은 혼자 돌아가지 않죠. 웹 서버와 데이터를 저장할 데이터베이스(DB)를 함께 띄워야 해요. 이때 두 컨테이너가 서로 대화할 수 있도록 네트워크를 구성하는 것이 핵심이에요.
services:
web-app:
image: my-app:1.0
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password123
여기서 depends_on 옵션을 눈여겨봐야 해요. 웹 앱이 실행되기 전에 데이터베이스가 먼저 준비되어야 에러가 나지 않겠죠? 이 옵션은 실행 순서를 제어해 줘요. 또한 environment는 컨테이너 내부 환경 변수를 설정하는 곳이에요. DB 비밀번호나 사용자 이름 같은 민감한 정보를 넘길 때 사용해요.
STEP 3. 데이터 보존을 위한 볼륨(Volume) 설정
도커 컨테이너는 삭제되면 그 안의 데이터도 모두 사라져요. DB에 저장한 소중한 데이터가 컨테이너를 껐다 켰다고 사라지면 안 되겠죠? 그래서 볼륨(Volume) 설정이 반드시 필요해요.
services:
db:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
위 코드처럼 volumes 섹션을 정의하면, 도커가 관리하는 안전한 저장 공간을 만들 수 있어요. 컨테이너가 삭제되어도 db_data라는 이름의 저장 공간은 그대로 남아 있어 다음에 다시 연결할 수 있어요. 데이터 영속성을 확보하는 가장 표준적인 방법이에요.
STEP 4. .env 파일을 활용한 보안 및 환경 관리
실무에서는 비밀번호를 yaml 파일에 직접 적지 않아요. 보안상 위험할 뿐만 아니라, 개발 환경과 운영 환경의 설정값이 다르기 때문이죠. 이때 사용하는 것이 바로 .env 파일이에요.
먼저 같은 폴더에 .env 파일을 만들고 내용을 적습니다.DB_PASSWORD=super_secret_password
APP_PORT=3000
그다음 yaml 파일에서는 변수 형태로 불러와요.services:
db:
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
이렇게 하면 소스 코드를 공유할 때 비밀번호가 노출되는 것을 방지할 수 있고, 서버 환경에 따라 .env 파일의 내용만 바꿔주면 되니 아주 효율적이에요.
STEP 5. 종합 실무 시나리오: 3계층 아키텍처 구성하기
마지막으로 지금까지 배운 내용을 모두 합친 종합 예제를 볼게요. 프론트엔드, 백엔드, 데이터베이스, 그리고 Redis 캐시 서버가 모두 연결된 형태예요. 이 정도면 웬만한 중소규모 서비스는 거뜬히 운영할 수 있는 구조예요.
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- backend
backend:
build: ./backend
environment:
DB_HOST: db
REDIS_HOST: cache
depends_on:
- db
- cache
db:
image: postgres:15
volumes:
- db_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
db_data:
이 예제에서 주목할 점은 build 옵션이에요. 이미 완성된 이미지를 가져오는 대신, 현재 폴더에 있는 코드를 가지고 직접 이미지를 만들 때 사용해요. 또한 백엔드 컨테이너는 DB와 Redis의 이름을 호스트명으로 사용하여 네트워크를 통해 서로를 찾아가요. 이것이 도커 컴포즈가 제공하는 강력한 자동 네트워크 기능이에요.
자주 하는 실수와 해결법
도커 컴포즈를 처음 쓸 때 누구나 한 번쯤 겪는 당황스러운 순간들이 있어요. 시행착오를 줄이기 위해 대표적인 사례들을 정리해 두었으니 꼭 읽어보세요.
- ❌ YAML 들여쓰기 오류 → Why: 스페이스와 탭을 혼용하거나 칸 수를 맞추지 못함 → ✅ Fix: VS Code 같은 에디터에서 ‘Render Whitespace’ 기능을 켜고, 반드시 스페이스 2칸으로 통일하세요.
- ❌ 포트 충돌 오류 → Why: 이미 내 컴퓨터에서 사용 중인 포트를 할당함 → ✅ Fix: “80:80” 대신 “8080:80″처럼 왼쪽 숫자를 바꿔보세요.
- ❌ 컨테이너 간 연결 실패 → Why: 서비스 이름이 틀렸거나 네트워크 설정이 누락됨 → ✅ Fix: 서비스 이름이 정확한지 확인하고, 호스트명을 IP가 아닌 서비스 이름(예: db)으로 적었는지 체크하세요.
- ❌ 데이터 사라짐 현상 → Why: 볼륨(Volumes) 설정을 하지 않고 컨테이너만 실행함 → ✅ Fix: 데이터를 저장할 경로는 반드시 volumes 섹션에 명시해야 합니다.
- ❌ 설정 변경이 반영 안 됨 → Why: 이미 실행 중인 컨테이너는 파일을 수정해도 자동으로 다시 시작되지 않음 → ✅ Fix:
docker compose up -d를 다시 실행하여 컨테이너를 재생성하세요.
자주 묻는 질문
Q. 도커 컴포즈를 실행하면 로그를 어떻게 볼 수 있나요?
명령어 창에 docker compose logs -f를 입력하면 실시간으로 모든 컨테이너의 로그를 확인할 수 있어요. 특정 서비스의 로그만 보고 싶다면 docker compose logs -f [서비스이름]을 쓰면 돼요.
Q. 작성한 yaml 파일에 문법 오류가 없는지 미리 알 수 없나요?
네, 가능해요! docker compose config 명령어를 실행해 보세요. 이 명령은 파일을 실제로 실행하지 않고도 문법이 맞는지, 변수가 제대로 치환되었는지 검증해 줍니다. 만약 오류가 있다면 어느 줄이 문제인지 친절하게 알려줄 거예요.
Q. 여러 개의 yaml 파일을 하나로 묶어서 쓸 수 있나요?
그럼요. docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d처럼 -f 옵션을 여러 번 써서 파일을 겹쳐서 실행할 수 있어요. 기본 설정 위에 운영 환경용 설정을 덧씌우는 방식으로 활용하면 아주 유용해요.
Q. 컨테이너를 완전히 삭제하고 싶을 땐 어떻게 하나요?
docker compose down 명령어를 사용하세요. 이 명령은 중지된 컨테이너와 생성된 네트워크를 모두 깔끔하게 제거해 줍니다. 만약 볼륨까지 한꺼번에 지우고 싶다면 docker compose down -v를 입력하면 됩니다.
성공적인 컨테이너 운영을 위한 마무리
도커 컴포즈는 단순한 도구가 아니라, 개발 환경을 코드화(Infrastructure as Code)하는 첫걸음이에요. 설정 파일 하나로 인프라를 관리할 수 있다는 점은 협업과 배포 과정에서 엄청난 시간을 아껴줄 거예요.
- YAML 문법(들여쓰기)을 지키는 것이 최우선이에요.
- 포트 설정 시 호스트:컨테이너 순서를 잊지 마세요.
- 데이터 유지를 위해 반드시 볼륨(Volumes)을 설정하세요.
- 보안을 위해 민감한 정보는 .env 파일에 분리하세요.
- 실행 전 config 명령어로 설정 오류를 미리 검증하세요.
오늘 바로 프로젝트 폴더에 docker-compose.yml 파일을 하나 만들어 보세요. 처음에는 간단한 Nginx 예제부터 시작해서, 하나씩 기능을 붙여나가는 재미를 느껴보시길 바라요.
🚀 다음 단계로 나아가기
- 오늘 할 일: 제공된 예제 코드를 복사해서 내 컴퓨터에서 직접 실행해 보기
- 이번 주 할 일: 나만의 .env 파일을 만들어 환경 변수 관리해 보기
- 실행 직전 할 일: 서비스 간의 네트워크 구조를 그림으로 그려보며 설계해 보기
예제 파일을 내려받아 프로젝트 구조에 맞게 값만 바꿔 사용해 보세요. 훨씬 편안한 데브옵스 생활이 시작될 거예요.
관련해서 더 깊이 있는 내용이 궁금하다면 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드 글도 함께 읽어보시길 추천해요.