개발 & 기술/DevOps·인프라

Docker Compose 5분 입문, 컨테이너 여러 개 한 번에 띄우기

Lumin 2026. 6. 3. 18:59
반응형

Docker는 어찌어찌 써봤는데 컨테이너가 두세 개로 늘어나는 순간부터 머리가 복잡해집니다. 웹 서버 띄우고, DB 띄우고, 캐시 서버 띄우고… 매번 docker run 명령어를 길게 치다 보면 옵션 하나 빠뜨려서 디버깅에 한 시간을 버리는 일이 흔합니다. 이때 등장하는 게 Docker Compose입니다. 이 글은 Docker 기본 개념은 알지만 Compose는 처음 써보는 중급 입문자를 대상으로, 5분 안에 첫 멀티 컨테이너 환경을 띄울 수 있게 안내합니다. 명령어 외우기보다 왜 이렇게 동작하는지에 초점을 맞췄습니다.

Docker Compose가 뭐길래

Docker Compose는 여러 개의 컨테이너를 YAML 파일 하나로 정의하고 한 번에 실행·관리하는 공식 도구입니다. Docker 자체가 컨테이너 한 개를 띄우는 일에 집중한다면, Compose는 "여러 컨테이너의 묶음"을 다룹니다.

비유하자면 Docker는 식재료 하나하나를 다루는 칼이고, Compose는 그 식재료들로 한 상을 차리는 레시피입니다. 레시피에 "밥은 이렇게, 국은 이렇게, 반찬은 이렇게"를 써놓으면 매번 머리로 외울 필요가 없습니다.

실제로 백엔드 개발자가 마주하는 흔한 상황이 이런 식입니다.

상황 Docker만 쓸 때 Compose 쓸 때
웹 + DB + Redis 띄우기 docker run 3번, 옵션 길게 docker compose up 한 번
팀원에게 환경 공유 "이 명령어 순서대로 실행해줘" 메모 docker-compose.yml 파일 한 개 전송
전체 종료 컨테이너 ID 확인 후 stop 3번 docker compose down 한 번
환경 재현성 사람마다 옵션 빼먹어서 다름 파일이 곧 정답
💡 참고로 옛날엔 docker-compose(하이픈)라는 별도 명령어였는데, 글 작성 시점 기준 Docker 공식은 docker compose(띄어쓰기) 형태의 V2를 권장합니다. 기능은 같습니다.

첫 docker-compose.yml 뜯어보기

가장 자주 등장하는 구성, 웹 앱 + PostgreSQL DB 조합을 예로 들겠습니다. 프로젝트 폴더에 docker-compose.yml이라는 파일을 만들고 다음 내용을 넣습니다.

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: mysecret
      POSTGRES_DB: appdb
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:

이게 끝입니다. 한 줄씩 풀어볼게요.

  • services: 띄울 컨테이너들의 목록. 여기서는 webdb 두 개.
  • image: 사용할 Docker 이미지. nginx:alpine은 가벼운 웹 서버, postgres:16은 PostgreSQL 16 버전.
  • ports: "8080:80": 내 컴퓨터의 8080 포트를 컨테이너 안 80 포트로 연결. 브라우저에서 localhost:8080으로 접속 가능.
  • depends_on: web을 띄우기 전에 db부터 띄우라는 순서 지정.
  • environment: 컨테이너 안에 환경 변수 주입. DB 비밀번호 같은 것.
  • volumes: 컨테이너가 사라져도 데이터를 유지할 저장 공간. DB 데이터를 컨테이너 안에만 두면 재시작할 때마다 날아갑니다.

YAML(야믈, 사람이 읽기 쉬운 설정 파일 형식)은 들여쓰기로 구조를 표현하기 때문에 띄어쓰기에 민감합니다. 탭 대신 스페이스 2칸을 쓰는 게 안전합니다. 이 부분에서 처음에 한참 헤맸습니다.

자주 쓰는 명령어 5개

Compose의 묘미는 명령어가 단순하다는 점입니다. 사실상 다섯 개만 알면 일상 작업의 90%가 됩니다.

명령어 하는 일
docker compose up yml 파일대로 컨테이너 전부 띄우기
docker compose up -d 위와 같은데 백그라운드로 실행 (터미널 안 막음)
docker compose down 띄운 컨테이너 전부 정지 + 삭제
docker compose ps 지금 떠 있는 컨테이너 상태 확인
docker compose logs -f web 특정 서비스(web)의 로그 실시간 보기

처음엔 updown만 외우면 됩니다. 작업 시작할 때 up -d, 끝낼 때 down. 이게 전부입니다.

[작업 시작]
   ↓
docker compose up -d   ← 컨테이너 한 번에 기동
   ↓
docker compose ps      ← 잘 떴는지 확인
   ↓
[개발 작업]
   ↓
docker compose logs -f ← 문제 생기면 로그 추적
   ↓
docker compose down    ← 작업 끝나면 정리

컨테이너끼리 어떻게 통신하나

Compose의 진짜 강력한 점은 서비스 이름이 곧 호스트 이름이 된다는 것입니다.

예를 들어 위 yml에서 web 컨테이너가 db 컨테이너에 접속하려면, 주소로 localhost나 IP가 아니라 그냥 db를 쓰면 됩니다. 마치 회사 내선 전화처럼, 같은 Compose 안에 있는 서비스끼리는 이름만 부르면 통하는 구조입니다.

web 컨테이너 ──── (내부 네트워크) ────> db 컨테이너
   "db:5432로 접속해줘"

이게 가능한 이유는 Compose가 자동으로 가상 네트워크를 만들어서 같은 묶음의 컨테이너들을 연결하기 때문입니다. 별도 설정이 필요 없습니다.

이 차이가 큰 이유는 실제 앱 코드에서 DB 접속 주소를 다음과 같이 쓸 수 있기 때문입니다.

DATABASE_URL=postgres://postgres:mysecret@db:5432/appdb

db:5432 부분이 핵심입니다. IP가 바뀌든 컨테이너가 재시작되든 이 주소는 그대로 유효합니다.

자주 막히는 부분과 해결법

직접 부딪쳐본 경험을 토대로, 입문자가 첫 주에 거의 무조건 한 번씩 만나는 함정을 모았습니다.

1. 포트 충돌

docker compose up을 했는데 "port is already allocated" 같은 에러가 뜹니다. 8080 포트를 이미 다른 프로그램이 쓰고 있다는 뜻입니다. yml 파일에서 "8080:80""8081:80"처럼 다른 숫자로 바꾸면 해결됩니다. 콜론 왼쪽이 내 컴퓨터, 오른쪽이 컨테이너 안이라는 점만 기억하면 됩니다.

2. 코드를 고쳤는데 반영이 안 됨

이미지를 새로 빌드하지 않으면 옛날 코드가 그대로 돕니다. 코드를 수정한 뒤엔 다음을 써야 합니다.

docker compose up -d --build

--build 옵션이 핵심입니다.

3. DB 데이터가 자꾸 사라진다

volumes 설정을 빼먹은 경우입니다. 컨테이너는 휘발성이라, down 한 번에 안의 데이터가 다 날아갑니다. 위 예시처럼 db-data:/var/lib/postgresql/data 식으로 영구 저장 공간을 붙여줘야 합니다.

4. depends_on은 "기동 순서"일 뿐 "준비 완료"가 아님

depends_on: db라고 써도 db가 시작됐을 뿐, 접속 가능 상태라는 뜻은 아닙니다. PostgreSQL은 켜진 뒤 몇 초 동안 초기화를 합니다. 이 시간 동안 web이 접속을 시도하면 에러가 납니다. 실무에서는 healthcheck를 추가하거나, 앱 코드에 재시도 로직을 넣는 식으로 해결합니다.

⚠️ 공식 문서 기준으로도 "depends_on은 시작 순서만 보장하지 서비스 준비 상태를 보장하지 않는다"고 명시돼 있습니다. 입문자가 가장 자주 놓치는 부분입니다.

언제 Compose를 쓰고, 언제 다른 걸 써야 하나

Compose는 만능이 아닙니다. 적합한 자리가 따로 있습니다.

용도 Compose Kubernetes
로컬 개발 환경 ⭕ 최적 ❌ 과함
1대 서버에 소규모 서비스 ⭕ 충분 ⚠️ 가능하지만 복잡
팀원 간 환경 통일 ⭕ 최적 ❌ 학습 비용 큼
수십~수백 컨테이너 운영 ❌ 한계 ⭕ 적합
자동 스케일링·무중단 배포 ❌ 부족 ⭕ 적합

요약하면 로컬 개발과 작은 서비스의 운영에는 Compose가 가성비 최고입니다. 트래픽이 늘어나서 여러 서버에 분산해야 하는 시점이 오면 그때 Kubernetes 같은 오케스트레이션 도구를 학습하면 됩니다. 처음부터 K8s를 붙들고 있는 건 개인 블로그 글 쓰려고 신문사 인쇄기를 사는 격입니다.

마무리

Compose의 본질은 단순합니다. YAML 한 장에 컨테이너 묶음을 정의하고, up 한 번에 띄운다. 처음 yml 파일을 쓸 때는 들여쓰기 때문에 답답할 수 있는데, 한두 번 만들어보면 손에 익습니다.

오늘 바로 해보고 싶다면, 평소 자주 쓰는 백엔드 스택(예: Node.js + MongoDB, Python + PostgreSQL 등)을 yml로 옮겨보세요. 기존 README에 적혀 있던 "이 명령어들 순서대로 실행하세요" 내용을 그대로 services 항목으로 번역하면 됩니다. 다음 단계로는 Dockerfile을 직접 작성해서 image 대신 build로 자기 앱을 컨테이너화하는 작업이 자연스럽게 따라옵니다. 그 얘기는 다음 글에서 이어가겠습니다.

반응형