[ADVANCED #1] 여러 컨테이너 한 번에 관리하기: Docker Compose

2025. 6. 1. 11:44·Docker

0. 들어가며

지금까지 우리는 도커의 기본적인 개념부터 네트워크까지 모두 배웠다. 이제 여러분은 다음과 같은 작업을 할 수 있다.

# 1. 네트워크 생성
docker network create myapp-network

# 2. 볼륨 생성
docker volume create mysql-data

# 3. MySQL 컨테이너 실행
docker run -d \\
  --name mysql-db \\
  --network myapp-network \\
  -v mysql-data:/var/lib/mysql \\
  -e MYSQL_ROOT_PASSWORD=root \\
  mysql:8.0

# 4. Spring Boot 앱 컨테이너 실행
docker run -d \\
  --name spring-app \\
  --network myapp-network \\
  -p 8080:8080 \\
  -e SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/mydb \\
  myapp:latest

# 5. Nginx 컨테이너 실행
docker run -d \\
  --name nginx \\
  --network myapp-network \\
  -p 80:80 \\
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro \\
  nginx

매번 이렇게 길고 복잡한 명령어를 입력하는 것은 매우 번거롭고 실수하기 쉽다. 게다가 이 모든 과정을 문서로 남기지 않으면, 다른 개발자가 같은 환경을 구성하려면 또 다시 같은 작업을 반복해야 한다.

이런 문제를 해결하기 위해 등장한 것이 Docker Compose다.

 


1. Docker Compose란?

1.1. 정의

Docker Compose는 여러 컨테이너로 구성된 애플리케이션을 정의하고 실행하기 위한 도구다.

  • YAML 파일 (docker-compose.yml)에 컨테이너들의 설정을 작성한다.
  • 단 하나의 명령어(docker-compose up)로 모든 컨테이너를 한 번에 실행할 수 있다.
  • 네트워크, 볼륨, 의존 관계 등을 자동으로 관리해준다.

1.2. 실생활 비유: 공장 자동화

  • 기존 방식: 공장 기계(컨테이너) 하나하나를 수동으로 켜고, 재료를 넣고, 연결하는 것
  • Docker Compose: 모든 기계의 설정이 담긴 자동화 레시피를 만들고, 버튼 하나만 누르면 전체 공장이 가동되는 것

 

2. Docker Compose 설치

2.1. 확인

최신 Docker Desktop (Windows/Mac)에는 Docker Compose가 기본 포함되어 있다.

# 버전 확인
docker-compose --version
# 또는
docker compose version

2.2. Linux에서 별도 설치

# 최신 버전 다운로드
sudo curl -L "<https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$>(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 실행 권한 부여
sudo chmod +x /usr/local/bin/docker-compose

# 설치 확인
docker-compose --version

3. docker-compose.yml 파일 구조

3.1. 기본 구조

version: '3.8'  # Compose 파일 버전

services:       # 실행할 컨테이너들
  service-name:
    image: 이미지명
    container_name: 컨테이너명
    ports:
      - "호스트포트:컨테이너포트"
    environment:
      - ENV_VAR=value
    volumes:
      - 호스트경로:컨테이너경로
    networks:
      - 네트워크명
    depends_on:
      - 다른-서비스

networks:       # 사용할 네트워크 정의
  network-name:
    driver: bridge

volumes:        # 사용할 볼륨 정의
  volume-name:

3.2. 버전 정보

버전  Docker 엔진  주요 특징
3.8 19.03.0+ 최신 기능, 대부분의 프로젝트에 권장
3.0 1.13.0+ Swarm 모드 지원
2.4 17.12.0+ 다양한 개선 사항
2.0 1.10.0+ 기본적인 Compose 기능

4. 주요 옵션 설명

4.1. image

사용할 이미지를 지정한다.

services:
  web:
    image: nginx:latest
  db:
    image: mysql:8.0

4.2. build

Dockerfile로 직접 빌드하여 사용한다.

services:
  app:
    build: .  # 현재 디렉토리의 Dockerfile 사용
    # 또는
    build:
      context: ./app  # 빌드 컨텍스트 경로
      dockerfile: Dockerfile.dev  # Dockerfile 파일명 지정
      args:
        - VERSION=1.0  # 빌드 인자

4.3. ports

포트 매핑을 설정한다.

services:
  web:
    ports:
      - "8080:80"           # 호스트:컨테이너
      - "443:443"
      - "3000"              # 호스트 포트 랜덤 할당

4.4. environment

환경 변수를 설정한다.

services:
  db:
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: mydb
      MYSQL_USER: user
      MYSQL_PASSWORD: pass

    # 또는 배열 형태
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=mydb

4.5. volumes

볼륨을 마운트한다.

services:
  db:
    volumes:
      - mysql-data:/var/lib/mysql  # 볼륨 마운트
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # 바인드 마운트

volumes:
  mysql-data:  # 볼륨 정의

4.6. networks

네트워크를 설정한다.

services:
  web:
    networks:
      - frontend
  app:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

4.7. depends_on

서비스 간 의존 관계를 설정한다.

services:
  db:
    image: mysql:8.0

  app:
    build: .
    depends_on:
      - db  # db가 먼저 실행된 후 app 실행

주의: depends_on은 시작 순서만 보장할 뿐, DB가 완전히 준비될 때까지 기다리지는 않는다. (healthcheck 필요)

4.8. healthcheck

컨테이너의 상태를 확인한다.

services:
  db:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

5. 실습 1: WordPress + MySQL

가장 대표적인 예제인 WordPress와 MySQL을 Compose로 구성해보자.

5.1. docker-compose.yml 작성

version: '3.8'

services:
  # MySQL 데이터베이스
  db:
    image: mysql:8.0
    container_name: wordpress-db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - wordpress-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # WordPress 애플리케이션
  wordpress:
    image: wordpress:latest
    container_name: wordpress-app
    restart: always
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp-data:/var/www/html
    networks:
      - wordpress-network
    depends_on:
      db:
        condition: service_healthy  # db가 healthy 상태일 때 시작

  # phpMyAdmin (선택사항)
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: wordpress-phpmyadmin
    restart: always
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      PMA_USER: wordpress
      PMA_PASSWORD: wordpress
    networks:
      - wordpress-network
    depends_on:
      - db

networks:
  wordpress-network:
    driver: bridge

volumes:
  db-data:
  wp-data:

5.2. 실행

# 백그라운드에서 모든 서비스 실행
docker-compose up -d

# 실행 상태 확인
docker-compose ps

# 로그 확인
docker-compose logs -f

# 특정 서비스 로그만 확인
docker-compose logs -f wordpress

5.3. 확인

  • WordPress: http://localhost:8080
  • phpMyAdmin: http://localhost:8081

5.4. 종료 및 정리

# 컨테이너 중지 및 삭제
docker-compose down

# 볼륨까지 함께 삭제 (데이터 완전 삭제)
docker-compose down -v

6. 실습 2: Spring Boot + MySQL

6.1. 프로젝트 구조

my-spring-app/
├── docker-compose.yml
├── backend/
│   ├── Dockerfile
│   ├── pom.xml
│   └── src/
└── init.sql

6.2. Spring Boot Dockerfile

# backend/Dockerfile
FROM openjdk:17-jdk-slim AS builder
WORKDIR /build
COPY pom.xml .
RUN apt-get update && apt-get install -y maven
RUN mvn dependency:go-offline

COPY src ./src
RUN mvn package -DskipTests

FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

6.3. 초기화 SQL

-- init.sql
CREATE DATABASE IF NOT EXISTS myapp;
USE myapp;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL
);

INSERT INTO users (name, email) VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com');

6.4. docker-compose.yml

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: spring-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: myapp
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppassword
    ports:
      - "3307:3306"  # 호스트 3307, 컨테이너 3306 (충돌 방지)
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # 초기화 스크립트
    networks:
      - spring-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  spring-app:
    build: ./backend
    container_name: spring-app
    restart: always
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/myapp?useSSL=false&serverTimezone=UTC
      SPRING_DATASOURCE_USERNAME: appuser
      SPRING_DATASOURCE_PASSWORD: apppassword
    networks:
      - spring-network
    depends_on:
      mysql:
        condition: service_healthy

networks:
  spring-network:
    driver: bridge

volumes:
  mysql-data:

6.5. 실행

# 빌드 및 실행
docker-compose up -d

# 로그 확인
docker-compose logs -f spring-app

# 애플리케이션 상태 확인
curl <http://localhost:8080/actuator/health>

7. 실습 3: 개발 환경을 위한 Compose

개발 환경에서는 소스 코드 변경 시 컨테이너도 자동으로 반영되어야 한다.

7.1. Node.js 개발 환경

version: '3.8'

services:
  node-app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: node-dev
    ports:
      - "3000:3000"
      - "9229:9229"  # 디버그 포트
    volumes:
      - .:/app          # 소스 코드 마운트
      - /app/node_modules  # node_modules는 컨테이너 내부 유지
    environment:
      - NODE_ENV=development
      - DEBUG=true
    command: npm run dev  # nodemon 등으로 자동 리로드

7.2. Python Flask 개발 환경

version: '3.8'

services:
  flask-app:
    build: .
    container_name: flask-dev
    ports:
      - "5000:5000"
    volumes:
      - .:/app
    environment:
      - FLASK_ENV=development
      - FLASK_APP=app.py
      - DEBUG=true
    command: flask run --host=0.0.0.0 --reload

8. 유용한 Compose 명령어

8.1. 기본 명령어

명령어  설명
docker-compose up -d 백그라운드에서 서비스 실행
docker-compose down 서비스 중지 및 컨테이너 삭제
docker-compose ps 실행 중인 서비스 목록
docker-compose logs -f 모든 서비스 로그 실시간 확인
docker-compose logs -f [서비스명] 특정 서비스 로그 확인
docker-compose exec [서비스명] [명령어] 실행 중인 서비스에 명령 실행
docker-compose run [서비스명] [명령어] 일회성 명령 실행
docker-compose build 이미지 빌드 (변경사항 반영)
docker-compose restart 모든 서비스 재시작
docker-compose stop 서비스 중지 (컨테이너 유지)
docker-compose start 중지된 서비스 시작

8.2. 고급 명령어

# 특정 서비스만 빌드/실행
docker-compose up -d db
docker-compose up -d --build spring-app

# 스케일 아웃 (같은 서비스 여러 개 실행)
docker-compose up -d --scale app=3

# 설정 확인
docker-compose config

# 환경 변수 파일 사용
docker-compose --env-file .env.prod up -d

9. 환경 변수 관리

9.1. .env 파일 사용

.env 파일

MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=apppass123
APP_VERSION=1.0.0

docker-compose.yml

version: '3.8'

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

  app:
    build: .
    environment:
      - DB_URL=jdbc:mysql://db:3306/${MYSQL_DATABASE}
      - DB_USER=${MYSQL_USER}
      - DB_PASS=${MYSQL_PASSWORD}

9.2. 여러 환경 분리

# 개발 환경
cp .env.example .env.dev
docker-compose --env-file .env.dev up -d

# 운영 환경
cp .env.example .env.prod
# .env.prod 수정
docker-compose --env-file .env.prod up -d

10. Docker Compose vs 수동 명령어 비교

10.1. 수동 명령어 방식

# 네트워크 생성
docker network create my-network

# 볼륨 생성
docker volume create db-data

# MySQL 실행
docker run -d \\
  --name mysql \\
  --network my-network \\
  -v db-data:/var/lib/mysql \\
  -e MYSQL_ROOT_PASSWORD=root \\
  mysql:8.0

# 앱 실행
docker run -d \\
  --name app \\
  --network my-network \\
  -p 8080:8080 \\
  -e DB_HOST=mysql \\
  myapp:latest

10.2. Docker Compose 방식

# docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
    networks:
      - my-network

  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      DB_HOST: mysql
    networks:
      - my-network
    depends_on:
      - mysql

networks:
  my-network:

volumes:
  db-data:

 

# 단 한 줄로 모든 것 실행!
docker-compose up -d

11. 마치며

이번 포스팅에서는 여러 컨테이너를 효율적으로 관리하는 Docker Compose에 대해 알아보았다.

  • Compose는 여러 컨테이너로 구성된 애플리케이션을 YAML 파일로 정의하고 관리한다.
  • docker-compose up 한 줄이면 수동으로 입력하던 긴 명령어들을 대체할 수 있다.
  • 네트워크, 볼륨, 의존 관계 등을 자동으로 관리해준다.
  • 개발 환경에서는 볼륨 마운트로 실시간 코드 반영이 가능하다.
  • .env 파일을 사용하여 환경별 설정을 분리할 수 있다.

이제 여러분은 단일 컨테이너부터 여러 컨테이너로 구성된 복잡한 애플리케이션까지 도커로 자유롭게 다룰 수 있다.

'Docker' 카테고리의 다른 글

[PROJECT #1] N-Tier 애플리케이션 도커로 구성하기 (Web + App + DB)  (0) 2025.06.01
[ADVANCED #2] 도커 이미지 배포와 공유: Docker Hub 활용법  (0) 2025.06.01
[BASIC #6] 컨테이너 간 통신: Docker Network 이해하기  (0) 2025.06.01
[BASIC #5] 데이터를 영구적으로 저장하는 법: Docker Volume  (0) 2025.05.31
[BASIC #4] 나만의 이미지 만들기: Dockerfile 완전 정복  (0) 2025.05.31
'Docker' 카테고리의 다른 글
  • [PROJECT #1] N-Tier 애플리케이션 도커로 구성하기 (Web + App + DB)
  • [ADVANCED #2] 도커 이미지 배포와 공유: Docker Hub 활용법
  • [BASIC #6] 컨테이너 간 통신: Docker Network 이해하기
  • [BASIC #5] 데이터를 영구적으로 저장하는 법: Docker Volume
h6bro
h6bro
백엔드 개발자의 기술 블로그
  • h6bro
    Jun's Tech Blog
    h6bro
  • 전체
    오늘
    어제
    • 분류 전체보기 (241) N
      • Java (18)
        • Core (9)
        • Design Pattern (9)
      • Spring (80)
        • Core (24)
        • MVC (6)
        • DB (10)
        • JPA (26)
        • Monitoring (3)
        • Security (11)
        • WebSocket (0)
      • Database (33)
        • Redis (15)
        • MySQL (18)
      • MSA (16)
        • MSA 기본 (11)
        • MSA 아키텍처 (5)
      • Kafka (30) N
        • Core (18) N
        • Connect (12)
      • ElasticSearch (11)
        • Search (11)
        • Logging (0)
      • Test (4)
        • k6 (4)
      • Docker (9)
      • CI&CD (10)
        • GitHub Actions (6)
        • ArgoCD (4)
      • Kubernetes (18)
        • Core (12)
        • Ops (6)
      • Cloud Engineering (4)
        • AWS Infrastructure (3)
        • AWS EKS (1)
        • Terraform (0)
      • Project (8)
        • LinkFolio (1)
        • Secondhand Market (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Cloud Engineering 포스팅 정리
  • 인기 글

  • 태그

    ㅈ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
h6bro
[ADVANCED #1] 여러 컨테이너 한 번에 관리하기: Docker Compose
상단으로

티스토리툴바