
왜 도커 컴포즈 문법이 우리를 괴롭힐까요
새로 맡게 된 서버, 참 막막하시죠? 분명히 도커(Docker)를 배우고 있는데, 명령어가 왜 이렇게 길고 복잡한지 모르겠어요. 컨테이너 하나 띄우는 데도 docker run 명령어를 사용하면 포트 설정부터 볼륨 연결까지 한 줄에 길게 써야 해요. 만약 데이터베이스(DB)와 웹 서버를 동시에 띄워야 한다면 어떨까요? 명령어가 두 배로 길어지는 것은 물론이고, 두 컨테이너를 어떻게 서로 연결해야 할지도 막막해집니다.
이런 상황에서 우리를 구해줄 구원투수가 바로 docker-compose.yml 파일이에요. 이 파일 하나만 잘 작성해두면, 복잡한 명령어 대신 docker compose up이라는 짧은 명령어 하나로 모든 서비스를 동시에 실행할 수 있어요. 하지만 처음 파일을 열어보면 알 수 있듯이, 들여쓰기 하나만 틀려도 에러가 나며 실행조차 되지 않아요. 낯선 용어와 규칙들이 초보 운영자를 겁나게 만들죠.
이 글은 바로 그런 분들을 위해 준비했어요. 비전공자 출신이라도, 서버 운영이 처음이라도 괜찮아요. 복잡한 기술 용어에 매몰되지 않고, 실제 서버를 운영할 때 꼭 필요한 핵심 문법 위주로 아주 쉽게 풀어낼게요. 이 글을 끝까지 읽고 나면, 여러분은 직접 작성한 설정 파일로 웹 서버와 데이터베이스를 한 번에 띄우는 마법을 경험하게 될 거예요.
- 도커 컴포즈를 시작하기 전 반드시 알아야 할 필수 용어 정리
- 실패 없는 설정을 위한 YAML 문법의 기초 규칙
- 실제 예제로 배우는 핵심 설정 키워드 사용법
- 실무에서 가장 자주 발생하는 실수와 해결 방법
시작하기 전에 꼭 알아야 할 기초 개념
도커 컴포즈 문법을 배우기 전에, 우리가 다루는 재료들이 무엇인지 알아야 해요. 무턱대고 파일을 작성하기 시작하면, 내가 지금 무엇을 설정하고 있는지 몰라 길을 잃기 쉽거든요. 컨테이너 운영의 핵심이 되는 네 가지 개념을 먼저 살펴볼게요.
반드시 이해해야 하는 4가지 용어
첫째, 이미지(Image)예요. 이미지는 소프트웨어를 실행하기 위한 모든 것이 담긴 ‘설계도’ 혹은 ‘압축 파일’이라고 생각하면 편해요. 둘째, 컨테이너(Container)는 이 설계도를 바탕으로 실제로 살아 움직이는 ‘실체’예요. 셋째, 서비스(Service)는 도커 컴포즈 안에서 하나의 컨테이너를 정의하는 단위예요. 마지막으로 볼륨(Volume)은 컨테이너가 사라져도 데이터가 남을 수 있게 연결해두는 ‘외장 하드’ 같은 존재예요.
이 용어들이 왜 중요한지, 그리고 우리가 왜 굳이 도커 컴포즈를 써야 하는지 비교해 드릴게요. 아래 표를 통해 기존 방식과 컴포즈 방식의 차이를 확인해 보세요.
| 비교 항목 | 도커 CLI (단일 명령어) | 도커 컴포즈 (YAML 활용) |
|---|---|---|
| 설정 관리 | 매번 긴 명령어를 직접 입력해야 해요. | 파일에 한 번 적어두면 재사용이 가능해요. |
| 다중 서비스 | 각 컨테이너를 따로 실행하고 연결해야 해요. | 파일 하나로 모든 서비스를 한꺼번에 관리해요. |
| 재현성 | 명령어를 잊어버리면 똑같이 만들기 어려워요. | 파일만 전달하면 어디서든 똑같이 실행돼요. |
| 난이도 | 명령어 옵션을 모두 외워야 해서 어려워요. | 문법 규칙만 알면 훨씬 직관적이에요. |
결론적으로, 서비스가 하나일 때는 명령어가 편할 수 있지만, 규모가 커질수록 도커 컴포즈는 선택이 아닌 필수가 됩니다. 이제 기초 용어를 익혔으니, 본격적으로 파일을 어떻게 작성하는지 단계별로 알아볼 준비가 끝났어요.
단계별로 따라 하는 docker-compose.yml 작성법
이제 직접 파일을 작성해 볼 시간이에요. 어렵게 생각하지 마세요. 마치 레시피를 적는 것처럼, 필요한 재료와 조리법을 순서대로 적는 과정일 뿐이에요. 실습을 위해 Nginx(웹 서버)와 Redis(데이터 저장소)를 함께 띄우는 시나리오를 따라가 볼게요.
STEP 1. YAML 문법의 절대 규칙: 들여쓰기
가장 먼저 알아야 할 규칙은 YAML이라는 파일 형식의 특성이에요. YAML은 들여쓰기(Indentation)로 계층 구조를 구분해요. 만약 들여쓰기가 잘못되면 컴퓨터는 어디가 어디에 속해 있는지 알 수 없어서 화를 내며 멈춰버려요.
절대로 탭(Tab) 키를 사용하지 마세요. 반드시 스페이스(Space) 키를 사용해야 해요. 보통 스페이스 2칸을 한 단계의 들여쓰기로 사용합니다. 탭과 스페이스를 혼용하면 눈에는 똑같아 보여도 에러가 발생해요.
모든 설정은 키(Key)와 값(Value)의 쌍으로 이루어져요. services:라는 키 뒤에 콜론(:)을 붙이고, 다음 줄부터 한 칸 들여써서 구체적인 내용을 적는 식이죠.
STEP 2. 서비스(Services)와 이미지(Image) 정의하기
컴포즈 파일의 심장은 services 항목이에요. 여기에 우리가 띄우고 싶은 컨테이너들을 하나씩 나열합니다. 각 서비스 안에는 어떤 이미지를 사용할지도 적어줘야 해요.
예를 들어, 웹 서버를 만들고 싶다면 이렇게 적어요. services:
web-server:
image: nginx
이것은 “서비스 목록 중에 web-server라는 이름을 가진 서비스가 있고, 이 서비스는 nginx 이미지를 사용한다”라는 뜻이에요. 이미지는 도커 허브라는 저장소에서 자동으로 가져오게 됩니다.
STEP 3. 포트(Ports)와 환경 변수(Environment) 설정
이미지만 가져온다고 끝이 아니에요. 외부에서 웹 사이트에 접속할 수 있도록 통로를 열어줘야 하는데, 이게 바로 ports 설정이에요. 또한, 데이터베이스 비밀번호 같은 중요한 정보는 environment를 통해 전달합니다.
포트 설정은 호스트포트:컨테이너포트 형식을 사용해요. 만약 내 컴퓨터의 8080번 포트로 접속했을 때 컨테이너의 80번 포트로 연결하고 싶다면 8080:80이라고 적으면 됩니다. 환경 변수는 서비스가 실행될 때 필요한 설정값들을 주입해주는 역할을 해요.
STEP 4. 데이터 보존을 위한 볼륨(Volumes) 연결
컨테이너는 기본적으로 일회용이에요. 컨테이너를 삭제하면 그 안에서 생성된 데이터도 모두 사라지죠. 이를 방지하기 위해 볼륨(Volumes) 설정이 꼭 필요해요. 볼륨은 내 컴퓨터의 특정 폴더와 컨테이너 내부의 폴더를 실시간으로 동기화해주는 연결 고리예요.
volumes:
./html:/usr/share/nginx/html
위와 같이 설정하면, 내 컴퓨터의 현재 폴더에 있는 html 폴더 내용이 컨테이너 내부의 웹 루트 디렉토리로 바로 전달돼요. 덕분에 컨테이너를 껐다 켜도 우리가 만든 웹 페이지는 그대로 남아 있게 됩니다.
STEP 5. 실전 예제: 웹 서버와 DB 한 번에 띄우기
이제 지금까지 배운 내용을 모두 합쳐서 하나의 완성된 파일을 만들어 볼게요. 아래 코드를 눈으로 따라 읽으며 구조를 파악해 보세요. 이 코드는 웹 서버(Nginx)와 데이터 저장소(Redis)를 연결하는 예제예요.
services:
web-app:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./web_content:/usr/share/nginx/html
depends_on:
- cache-db
cache-db:
image: redis:alpine
여기서 depends_on이라는 아주 유용한 키워드가 보이죠? 이것은 “web-app을 실행하기 전에 cache-db를 먼저 실행해라”라는 순서를 정해주는 명령이에요. 덕분에 데이터베이스가 준비되지 않아 웹 서버가 오류를 일으키는 일을 방지할 수 있어요. 이제 이 파일을 저장하고 docker compose up -d 명령어를 입력하면, 두 서비스가 마치 약속이라도 한 듯 순서대로 멋지게 실행될 거예요.
자주 하는 실수와 해결법
처음부터 완벽한 파일을 작성하는 사람은 없어요. 저도 수없이 에러 메시지를 마주하며 배웠거든요. 여러분이 겪을 가능성이 높은 실수들을 모아봤으니, 에러가 나면 당황하지 말고 여기서 찾아보세요.
- ❌ 실수: 탭(Tab) 키를 사용해 들여쓰기를 했다.
왜 발생하나요? YAML은 탭 문자를 해석하지 못해 문법 에러를 냅니다.
✅ 해결법: 에디터 설정에서 탭을 스페이스로 변환하거나, 직접 스페이스 키를 사용하세요. - ❌ 실수: 콜론(:) 뒤에 한 칸을 띄우지 않았다.
왜 발생하나요?key:value처럼 붙여 쓰면 YAML은 이를 하나의 단어로 인식합니다.
✅ 해결법: 반드시key: value처럼 콜론 뒤에 공백을 한 칸 넣으세요. - ❌ 실수: 포트 번호가 이미 사용 중이다.
왜 발생하나요? 이미 다른 프로그램이 8080번 포트를 쓰고 있기 때문이에요.
✅ 해결법:8081:80처럼 왼쪽의 호스트 포트 번호를 다른 숫자로 바꿔보세요. - ❌ 실수: 볼륨 경로를 잘못 지정했다.
왜 발생하나요? 파일 경로가 틀리면 컨테이너 내부에서 데이터를 찾을 수 없어요.
✅ 해결법: 현재 폴더를 뜻하는./를 경로 앞에 붙였는지 다시 확인하세요. - ❌ 실수: 이미지 이름을 오타 냈다.
왜 발생하나요? 존재하지 않는 이미지를 요청하면 다운로드에 실패합니다.
✅ 해결법: 도커 허브에서 정확한 이미지 이름과 태그를 확인하세요.
자주 묻는 질문
Q. 도커 컴포즈 파일 이름은 꼭 docker-compose.yml이어야 하나요?
꼭 그렇지는 않아요. 하지만 기본 이름을 사용해야 별도의 설정 없이 docker compose up 명령어를 바로 쓸 수 있어서 편리해요. 다른 이름을 쓴다면 -f 파일명 옵션을 붙여야 해요.
Q. 컨테이너를 멈추고 삭제하고 싶을 때는 어떻게 하나요?
docker compose down 명령어를 사용하면 됩니다. 이 명령어를 쓰면 실행 중인 컨테이너뿐만 아니라 생성된 네트워크까지 깔끔하게 정리해줘요.
Q. 버전(version) 항목은 꼭 써야 하나요?
최신 버전의 도커 컴포즈에서는 사실 버전 명시를 필수로 요구하지 않는 추세예요. 하지만 프로젝트의 안정성을 위해 version: '3.8'처럼 명시해주는 습관을 들이는 것이 좋습니다.
Q. 수정 사항을 적용했는데 왜 반영이 안 될까요?
이미 실행 중인 컨테이너는 설정 파일이 바뀌었다고 해서 자동으로 다시 시작되지 않아요. docker compose up -d를 다시 실행하면 변경된 부분을 감지해 컨테이너를 다시 만들어줍니다.
기초를 마치며: 다음 단계로 나아가기
지금까지 docker compose yml 기초 문법을 함께 살펴보았어요. 처음에는 들여쓰기 하나에 머리가 아플 수 있지만, 한두 번만 직접 파일을 만들고 실행해 보면 금방 익숙해질 거예요. 오늘 배운 내용을 바탕으로 여러분의 서버 운영 환경을 훨씬 더 체계적으로 관리해 보세요.
- YAML은 반드시 스페이스 2칸으로 들여쓰기를 합니다.
- 모든 설정은 키(Key): 값(Value)의 쌍으로 작성하며 콜론 뒤에 공백을 넣습니다.
services항목 아래에 컨테이너 설정을 정의합니다.ports로 통로를 열고,volumes로 데이터를 보호합니다.depends_on을 사용해 서비스 실행 순서를 제어할 수 있습니다.
이해가 안 되는 용어나 문법이 있다면 그냥 넘기지 마세요. 눈으로만 보는 것과 직접 에디터에 타이핑해서 에러를 마주하는 것은 완전히 다른 경험이니까요. 지금 바로 메모장을 열고 아주 간단한 nginx 설정부터 시작해 보세요.
🚀 다음 단계로 무엇을 하면 좋을까요?
- 오늘 할 일: 위 예제 코드를 복사해 자신의 컴퓨터에서 실행해 보기
- 이번 주 할 일: Nginx 대신 MySQL 같은 데이터베이스 서비스를 추가해 보기
- 실행 직전 할 일: 들여쓰기 에러를 잡기 위해 VS Code 같은 코드 에디터 설치하기
이 과정이 익숙해졌다면, 이제 더 복잡한 네트워크 설정이나 환경 변수 관리법을 공부할 차례예요. 실무에서 만나는 진짜 문제는 이 기초가 탄탄할 때 비로소 해결할 수 있습니다.
관련해서 더 깊이 있는 내용이 궁금하시다면 도커 컴포즈 기본 개념 완벽 정리 — 개념부터 실무 활용까지 한눈에 보는 가이드를 참고해 보세요.