프로그래밍/DevOps

[DevOps] Docker Compose — 여러 컨테이너를 한 번에 관리하기

이슬먹는 개발자 2026. 7. 9. 17:50
728x90
반응형

지난 글에서 Dockerfile로 내 앱을 이미지로 만들었다. 그런데 실무 앱은 혼자 안 돈다. 웹 서버 하나에 데이터베이스가 붙고, 캐시로 Redis가 붙는다. 그럼 컨테이너를 하나씩 이렇게 띄워야 한다.

docker run -d --name my-db -e POSTGRES_PASSWORD=... postgres:16
docker run -d --name my-redis redis:7
docker run -d --name my-app -p 3000:3000 --link my-db ... my-app

컨테이너 세 개인데 벌써 명령어가 길고 지저분하다. 순서도 신경 써야 하고, 네트워크로 서로 연결도 해줘야 한다. 컨테이너가 다섯 개, 열 개로 늘면? 손으로 못 한다.

이 문제를 해결하는 게 Docker Compose다.


Docker Compose = 여러 컨테이너를 파일 하나로 정의

Docker Compose는 여러 컨테이너의 구성을 YAML 파일 하나에 적어두고, 명령 한 줄로 전부 띄우는 도구다.

docker run을 여러 번 치는 대신, docker-compose.yml에 "웹은 이렇게, DB는 이렇게 띄워라"라고 적어두고 이렇게만 하면 된다.

docker compose up

끝이다. 정의된 컨테이너가 전부 뜨고, 서로 통신할 네트워크까지 자동으로 만들어진다.

정리하면 이렇다.

  • Dockerfile = 컨테이너 하나를 어떻게 만들지
  • docker-compose.yml = 컨테이너 여러 개를 어떻게 같이 띄울지

예제: 웹 앱 + PostgreSQL 띄우기

지난 글에서 만든 Node.js 앱에 DB를 붙여보자. 프로젝트 루트에 docker-compose.yml을 만든다.

services:
  app:
    build: .                 # 현재 폴더 Dockerfile로 빌드
    ports:
      - "3000:3000"
    environment:
      DB_HOST: db            # 서비스 이름으로 접근한다!
      DB_PASSWORD: secret
    depends_on:
      - db

  db:
    image: postgres:16       # 이미 있는 이미지 사용
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

이 한 파일에 아까 그 복잡한 docker run 세 줄이 다 담겼다. 이제 하나씩 뜯어보자.


핵심 항목 뜯어보기

services — 띄울 컨테이너들의 목록이다. 여기서는 appdb 두 개다. 이 이름이 곧 서비스 이름이 된다.

build: . — 현재 폴더의 Dockerfile로 이미지를 직접 빌드한다. 내가 만든 앱은 이렇게 쓴다.

image: postgres:16 — 반대로 남이 만든 기성 이미지를 그냥 가져다 쓸 땐 image를 쓴다. 빌드할 필요가 없으니까.

ports: - "3000:3000"docker run -p와 같다. 내 컴퓨터 3000 → 컨테이너 3000 연결.

environment — 컨테이너에 넘길 환경변수다. DB 비밀번호 같은 걸 여기 넣는다.

depends_on — 시작 순서를 정한다. db가 먼저 뜨고 나서 app이 뜬다.

volumes — 데이터를 컨테이너 밖에 저장한다. (아래에서 따로 설명)


서비스 이름이 곧 주소가 된다

Compose에서 가장 중요하고, 처음에 가장 신기한 부분이다. 위 설정에서 앱의 DB 접속 주소를 이렇게 줬다.

DB_HOST: db

localhost도 아니고 IP 주소도 아니고 그냥 db다. 어떻게 이게 되냐면, Compose가 자동으로 네트워크를 만들고, 서비스 이름을 호스트명으로 등록해주기 때문이다.

app 컨테이너 안에서 db라고 부르면 알아서 DB 컨테이너를 찾아간다. IP를 알 필요도 없고, 컨테이너가 재시작돼서 IP가 바뀌어도 상관없다. 서비스 이름만 알면 된다.

이것 하나 때문에 컨테이너 간 연결이 훨씬 쉬워진다.


볼륨(Volume): 컨테이너가 죽어도 데이터는 살아야지

컨테이너는 일회용이다. 지우면 그 안의 데이터도 같이 사라진다. 앱이야 상관없지만 DB는 큰일이다. 컨테이너 한 번 내렸다고 데이터가 다 날아가면 안 되니까.

그래서 볼륨을 쓴다. 볼륨은 데이터를 컨테이너 바깥(호스트)에 저장해두는 공간이다.

db:
  volumes:
    - db_data:/var/lib/postgresql/data

/var/lib/postgresql/data(Postgres가 데이터를 쌓는 경로)를 db_data라는 볼륨에 연결했다. 이러면 컨테이너를 지우고 다시 만들어도 데이터가 그대로 살아있다.


자주 쓰는 명령어

명령어 하는 일
docker compose up 전체 실행 (로그 보임)
docker compose up -d 백그라운드로 실행
docker compose up --build 이미지 다시 빌드하고 실행
docker compose down 전체 중지 + 컨테이너 삭제
docker compose ps 실행 중인 서비스 확인
docker compose logs -f app 특정 서비스 로그 실시간 보기

가장 많이 쓰는 건 up -d로 띄우고, logs -f로 로그 보고, down으로 내리는 흐름이다.

참고로 down은 컨테이너만 지우고 볼륨은 남긴다. 볼륨까지 싹 지우려면 docker compose down -v를 쓴다. (DB 데이터 날아가니 주의하자.)


정리

  • docker run을 여러 번 치는 지옥에서 벗어나려면 Docker Compose를 쓴다.
  • Dockerfile은 컨테이너 하나, docker-compose.yml은 여러 컨테이너의 구성이다.
  • services 아래에 컨테이너들을 정의하고, docker compose up 한 줄로 전부 띄운다.
  • 서비스 이름이 곧 호스트명이라, 컨테이너끼리 이름으로 통신한다. (DB_HOST: db)
  • DB처럼 데이터가 살아남아야 하는 건 볼륨으로 보존한다.

로컬 개발 환경 세팅할 때 특히 강력하다. 새 팀원이 와도 git clone 하고 docker compose up 한 줄이면 웹이든 DB든 똑같은 환경이 뜬다. "환경 세팅하는 데 하루 걸렸어요"가 사라지는 거다.

여기까지가 컨테이너를 내 컴퓨터에서 다루는 이야기였다. 다음부터는 한 단계 나아가서, 코드를 푸시하면 자동으로 테스트하고 빌드해서 배포까지 해주는 CI/CD 이야기로 넘어가보자.

728x90
반응형