튜토리얼

Docker Compose 활용 다중 서비스 로컬 개발 환경 구축 실전 가이드

강코의 코딩 일기 2026. 6. 9. 19:15
반응형

복잡한 다중 서비스 로컬 개발 환경, 이제 Docker Compose로 쉽고 효율적으로 구축하고 관리하세요. 컨테이너 기반 개발의 핵심 가이드를 제공합니다.

개발자라면 누구나 한 번쯤 복잡한 개발 환경 설정의 늪에 빠져본 경험이 있을 것입니다. 웹 애플리케이션 하나를 개발하려 해도 프론트엔드 서버, 백엔드 API 서버, 데이터베이스, 캐시 서버 등 여러 서비스가 유기적으로 연결되어야 합니다. 각 서비스마다 필요한 종속성과 버전이 다르고, 이를 로컬 머신에 일일이 설치하고 설정하는 과정은 그 자체로 거대한 산처럼 느껴지곤 합니다. “내 컴퓨터에서는 잘 되는데, 왜 다른 개발자 컴퓨터에서는 안 될까?”, “새로운 프로젝트를 시작할 때마다 이 모든 걸 다시 세팅해야 한다니…” 이런 고민을 해보셨다면, 이 글이 여러분의 개발 워크플로우를 혁신적으로 바꿔줄 해결책이 될 것입니다.

이번 글에서는 Docker Compose를 활용하여 다중 서비스 로컬 개발 환경을 효율적으로 구축하고 관리하는 실전 가이드를 제공합니다. 단일 파일 설정만으로 여러 개의 컨테이너를 한 번에 정의하고 실행하는 방법을 배우고, 실제 프로젝트에 적용할 수 있는 구체적인 예시를 통해 컨테이너 기반 개발의 강력함을 경험하게 될 것입니다.

📑 목차

Docker Compose를 활용한 다중 서비스 로컬 개발 환경 구축 실전 가이드 - computer, laptop, tech, blue computer, blue laptop, blue tech, computer, laptop, tech, tech, tech, tech, tech

Image by yeiferr on Pixabay

도입: 복잡한 개발 환경, 어떻게 해결하시겠습니까?

현대의 소프트웨어 개발은 대부분 여러 개의 독립적인 서비스들이 서로 통신하며 동작하는 마이크로서비스 아키텍처분산 시스템 형태로 이루어집니다. 예를 들어, 일반적인 웹 애플리케이션만 하더라도 다음과 같은 구성 요소들이 필요할 수 있습니다.

  • 프론트엔드 서비스: React, Vue, Angular 등으로 개발된 UI
  • 백엔드 서비스: Spring Boot, Node.js, Django 등으로 개발된 API 서버
  • 데이터베이스: PostgreSQL, MySQL, MongoDB 등
  • 캐시 서버: Redis, Memcached 등
  • 메시지 큐: RabbitMQ, Kafka 등

이 모든 서비스를 로컬 개발 환경에 직접 설치하고 버전을 맞추는 작업은 상당한 시간과 노력을 요구합니다. 특정 서비스의 버전을 변경해야 할 때는 다른 서비스에 영향을 미칠까 봐 조심해야 하고, 새로운 개발자가 팀에 합류하면 이 복잡한 환경 설정 과정을 처음부터 다시 반복해야 합니다. 이 과정에서 발생하는 버전 불일치, 환경 의존성 문제는 개발 생산성을 저해하는 주요 원인이 됩니다.

이러한 문제들을 해결하기 위해 등장한 것이 바로 컨테이너 기술, 그리고 여러 컨테이너를 쉽게 관리하기 위한 Docker Compose입니다. Docker Compose는 정의된 설정 파일을 기반으로 다중 컨테이너 애플리케이션을 한 번에 정의하고 실행할 수 있도록 돕는 도구입니다. 이제 더 이상 복잡한 환경 설정에 시간을 낭비하지 않고, 오직 코드 개발에만 집중할 수 있게 됩니다.

Docker Compose, 왜 필요한가?

단일 서비스라면 Docker만으로도 충분히 컨테이너를 관리할 수 있습니다. 하지만 두 개 이상의 서비스가 서로 연동되어야 하는 상황에서는 이야기가 달라집니다. 데이터베이스 컨테이너를 띄우고, 그 데이터베이스에 연결되는 백엔드 컨테이너를 띄우고, 다시 그 백엔드와 통신하는 프론트엔드 컨테이너를 띄우는 일련의 과정을 수동으로 진행하는 것은 비효율적이며 오류 발생 가능성이 높습니다.

Docker Compose의 핵심 장점

Docker Compose는 이러한 문제들을 해결하며 다음과 같은 핵심적인 장점들을 제공합니다.

  • 환경 일관성 및 재현성: docker-compose.yml 파일 하나로 전체 개발 환경을 정의하므로, 모든 팀원이 동일하고 일관된 환경에서 개발할 수 있습니다. "내 컴퓨터에서는 되는데..." 하는 문제는 과거의 이야기가 됩니다.
  • 간편한 서비스 오케스트레이션: 여러 컨테이너를 한 번의 명령으로 동시에 시작, 중지, 재시작할 수 있습니다. 서비스 간의 의존성(예: 데이터베이스가 먼저 시작되어야 백엔드가 시작될 수 있음)도 손쉽게 설정할 수 있습니다.
  • 격리된 개발 환경: 각 서비스가 독립적인 컨테이너에서 실행되므로, 로컬 시스템의 다른 애플리케이션이나 라이브러리와 충돌할 염려가 없습니다. 개발 환경이 깔끔하게 유지됩니다.
  • 개발 생산성 향상: 환경 설정에 드는 시간을 줄여주고, 문제 발생 시 원인을 파악하기 쉽게 만들어 개발 생산성을 크게 향상시킵니다.
  • 버전 관리 용이: docker-compose.yml 파일 자체를 Git과 같은 버전 관리 시스템으로 관리하므로, 환경 변경 이력을 추적하고 필요에 따라 롤백하는 것이 용이합니다.

Docker CLI vs Docker Compose

단순히 Docker CLI만으로도 여러 컨테이너를 실행할 수 있지만, Docker Compose는 복잡한 다중 서비스 환경에서 훨씬 강력한 이점을 제공합니다. 아래 표는 두 방식의 주요 차이점을 보여줍니다.

특징 Docker CLI (docker run) Docker Compose
서비스 정의 방식 각 서비스를 개별 명령어로 정의 및 실행 docker-compose.yml 파일에 YAML 형식으로 모든 서비스 정의
다중 서비스 관리 여러 docker run 명령어를 수동으로 실행해야 함 단일 명령 (docker compose up)으로 모든 서비스 시작/중지/재시작 가능
환경 재현성 스크립트화하지 않으면 재현성 낮음 docker-compose.yml 파일 덕분에 높은 재현성 보장
네트워킹 수동으로 네트워크 생성 및 연결 필요 자동으로 기본 네트워크 생성, 서비스 간 이름으로 통신 가능
볼륨 관리 각 컨테이너마다 볼륨 마운트 설정 필요 docker-compose.yml에 볼륨 정의 및 공유 가능
복잡도 단일 서비스에 적합, 다중 서비스 시 복잡도 증가 복잡한 다중 서비스 환경에 최적화

결론적으로, 다중 서비스 환경을 구축하고 관리한다면 Docker Compose는 선택이 아닌 필수 도구입니다. 이제 Docker Compose를 활용하여 실제 개발 환경을 구축하는 방법을 알아보겠습니다.

Docker Compose 설치 및 기본 설정

Docker Compose를 사용하기 위해서는 먼저 Docker가 설치되어 있어야 합니다. 대부분의 경우, Docker Desktop을 설치하면 Docker 엔진과 함께 Docker Compose가 자동으로 설치됩니다.

Docker Desktop 설치 확인

운영체제에 맞는 Docker Desktop을 설치했다면, 터미널(또는 명령 프롬프트)을 열어 다음 명령어로 Docker와 Docker Compose의 설치 여부를 확인할 수 있습니다.

docker --version
docker compose version

위 명령어를 실행했을 때 버전 정보가 정상적으로 출력된다면 Docker Compose를 사용할 준비가 된 것입니다. 만약 docker compose 명령이 인식되지 않는다면, 구 버전의 Docker Compose (docker-compose)가 설치되어 있거나, Docker Desktop 설치가 제대로 완료되지 않은 경우일 수 있습니다. 최신 Docker Desktop을 설치하고 시스템을 재시작해 보세요.

프로젝트 디렉토리 구조 설정

Docker Compose를 사용하는 프로젝트는 일반적으로 다음과 같은 디렉토리 구조를 가집니다.

my-multi-service-app/
├── web/
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt
├── api/
│   ├── Dockerfile
│   ├── server.js
│   └── package.json
└── docker-compose.yml

루트 디렉토리에는 docker-compose.yml 파일이 위치하며, 각 서비스별 코드는 별도의 서브 디렉토리에 분리되어 관리됩니다. 이 구조는 가독성을 높이고 각 서비스의 독립성을 유지하는 데 도움이 됩니다.

Docker Compose를 활용한 다중 서비스 로컬 개발 환경 구축 실전 가이드 - man, computer, screen, desktop, imac, apple products, desktop computer, workspace, workplace, working, technology, indoors, desk, office, information, display, monitor, programmer, developer, computer, computer, desktop, information, monitor, programmer, programmer, programmer, developer, developer, developer, developer, developer

Image by Pexels on Pixabay

다중 서비스 환경 설계 및 `docker-compose.yml` 작성

Docker Compose의 핵심docker-compose.yml 파일입니다. 이 YAML 파일에 우리가 구축하려는 다중 서비스 환경의 모든 정보가 담겨 있습니다. 어떤 서비스가 필요하고, 각 서비스는 어떤 이미지로 실행되며, 어떤 포트를 사용할지, 어떤 볼륨을 마운트할지 등을 정의합니다.

`docker-compose.yml` 파일의 기본 구조

docker-compose.yml 파일은 크게 다음과 같은 최상위 키를 가집니다.

  • version: Compose 파일 형식의 버전입니다. 일반적으로 최신 버전을 사용합니다.
  • services: 이 섹션에 우리가 실행할 각 서비스(컨테이너)들을 정의합니다.
  • networks: 서비스 간 통신을 위한 네트워크를 정의합니다.
  • volumes: 컨테이너의 데이터를 영구적으로 저장하기 위한 볼륨을 정의합니다.

가장 중요한 services 섹션 아래에는 각 서비스의 이름을 지정하고, 해당 서비스에 대한 상세 설정을 추가합니다. 각 서비스에 설정할 수 있는 주요 옵션은 다음과 같습니다.

  • image: 컨테이너를 생성할 Docker 이미지 이름을 지정합니다 (예: nginx:latest, postgres:13).
  • build: Dockerfile을 사용하여 이미지를 직접 빌드할 경우, Dockerfile이 있는 경로를 지정합니다.
  • ports: 호스트 머신과 컨테이너 간의 포트 매핑을 정의합니다 (예: "80:80").
  • volumes: 호스트 머신의 디렉토리나 명명된 볼륨을 컨테이너 내부에 마운트합니다 (예: ./app:/app).
  • environment: 컨테이너 내부에서 사용할 환경 변수를 설정합니다.
  • depends_on: 서비스 간의 의존성을 정의합니다 (예: 백엔드가 데이터베이스보다 먼저 시작되어야 함).
  • networks: 컨테이너가 연결될 네트워크를 지정합니다.
  • restart: 컨테이너 종료 시 재시작 정책을 정의합니다 (예: always, on-failure).

간단한 `docker-compose.yml` 예제: 웹 서버와 데이터베이스

간단한 웹 서버 (Nginx)와 데이터베이스 (PostgreSQL)를 포함하는 docker-compose.yml 파일을 살펴보겠습니다.

# docker-compose.yml
version: '3.8'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/html:/usr/share/nginx/html
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:13
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network
    restart: always

volumes:
  db_data:

networks:
  app-network:
    driver: bridge

이 파일은 두 개의 서비스 webdb를 정의합니다. web 서비스는 Nginx 이미지를 사용하고, db 서비스는 PostgreSQL 이미지를 사용합니다. 주목할 점은 다음과 같습니다.

  • depends_on: - db: web 서비스가 db 서비스보다 나중에 시작되도록 의존성을 설정합니다.
  • networks: - app-network: 두 서비스 모두 app-network라는 사용자 정의 네트워크에 연결되어 서로 이름으로 통신할 수 있습니다 (예: web 서비스에서 db라는 호스트 이름으로 PostgreSQL에 접근 가능).
  • volumes: - db_data:/var/lib/postgresql/data: db_data라는 명명된 볼륨을 사용하여 데이터베이스의 데이터를 영구적으로 저장합니다. 이렇게 하면 컨테이너가 삭제되어도 데이터는 유지됩니다.

이처럼 docker-compose.yml 파일 하나로 여러 서비스의 관계와 설정을 명확하게 정의할 수 있습니다. 이제 실제 개발 시나리오를 통해 더 복잡한 환경을 구축해 보겠습니다.

실전 예제: 웹 애플리케이션 + 데이터베이스 + 캐시 서버

이제 실제 개발에서 많이 사용되는 구성인 웹 애플리케이션(Node.js), 데이터베이스(PostgreSQL), 캐시 서버(Redis)를 Docker Compose로 구축하는 과정을 상세히 살펴보겠습니다. 이 예제는 백엔드 서버가 데이터베이스와 캐시 서버를 활용하는 일반적인 시나리오를 가정합니다.

프로젝트 구조 설정

먼저 프로젝트 디렉토리를 생성하고 다음과 같은 구조를 만듭니다.

my-fullstack-app/
├── backend/
│   ├── Dockerfile
│   ├── package.json
│   ├── package-lock.json
│   └── src/
│       └── app.js
└── docker-compose.yml

여기서 backend/src/app.js는 Node.js 기반의 백엔드 애플리케이션 코드가 들어갈 위치이며, backend/Dockerfile은 해당 애플리케이션을 컨테이너화하기 위한 파일입니다.

백엔드 서비스 `Dockerfile` 및 코드 작성

1. backend/package.json 작성

{
  "name": "my-backend",
  "version": "1.0.0",
  "description": "Node.js backend service",
  "main": "src/app.js",
  "scripts": {
    "start": "node src/app.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "pg": "^8.11.3",
    "redis": "^4.6.10"
  }
}

2. backend/Dockerfile 작성

# backend/Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY src ./src

EXPOSE 3000

CMD ["npm", "start"]

이 Dockerfile은 Node.js 18 버전 기반의 이미지를 사용하고, 의존성을 설치한 후 src 디렉토리의 애플리케이션 코드를 복사하여 3000번 포트로 서비스를 노출합니다.

3. backend/src/app.js (간단한 예제 코드)

// backend/src/app.js
const express = require('express');
const { Client } = require('pg');
const redis = require('redis');

const app = express();
const port = 3000;

// PostgreSQL 클라이언트 설정 (docker-compose.yml에서 정의된 서비스 이름 사용)
const pgClient = new Client({
  user: process.env.POSTGRES_USER || 'myuser',
  host: process.env.POSTGRES_HOST || 'db', // 서비스 이름 'db'로 접근
  database: process.env.POSTGRES_DB || 'mydatabase',
  password: process.env.POSTGRES_PASSWORD || 'mypassword',
  port: 5432,
});

// Redis 클라이언트 설정 (docker-compose.yml에서 정의된 서비스 이름 사용)
const redisClient = redis.createClient({
  url: `redis://${process.env.REDIS_HOST || 'redis'}:6379` // 서비스 이름 'redis'로 접근
});

pgClient.connect().then(() => {
  console.log('PostgreSQL connected!');
}).catch(err => {
  console.error('PostgreSQL connection error:', err.stack);
});

redisClient.connect().then(() => {
  console.log('Redis connected!');
}).catch(err => {
  console.error('Redis connection error:', err.stack);
});

app.get('/', (req, res) => {
  res.send('Hello from Backend Service!');
});

app.get('/data', async (req, res) => {
  try {
    const result = await pgClient.query('SELECT NOW()');
    const dbTime = result.rows[0].now;
    await redisClient.set('last_access', new Date().toISOString());
    const lastAccess = await redisClient.get('last_access');

    res.json({
      message: 'Data fetched successfully!',
      databaseTime: dbTime,
      redisLastAccess: lastAccess
    });
  } catch (error) {
    console.error('Error fetching data:', error);
    res.status(500).send('Error fetching data');
  }
});

app.listen(port, () => {
  console.log(`Backend service listening at http://localhost:${port}`);
});

이 코드는 db라는 호스트 이름으로 PostgreSQL에, redis라는 호스트 이름으로 Redis에 연결을 시도합니다. 이는 Docker Compose의 서비스 디스커버리 기능 덕분입니다.

`docker-compose.yml` 파일 작성 (전체 환경)

이제 백엔드, PostgreSQL, Redis를 포함하는 전체 docker-compose.yml 파일을 작성합니다.

# docker-compose.yml
version: '3.8'

services:
  backend:
    build: ./backend # backend 디렉토리의 Dockerfile을 사용하여 이미지 빌드
    ports:
      - "3000:3000" # 호스트의 3000번 포트를 컨테이너의 3000번 포트에 연결
    volumes:
      - ./backend:/app # 호스트의 ./backend 디렉토리를 컨테이너의 /app에 마운트 (코드 변경 시 즉시 반영)
      - /app/node_modules # node_modules는 볼륨 마운트에서 제외하여 컨테이너 내부에서 관리
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydatabase
      POSTGRES_HOST: db # PostgreSQL 서비스 이름
      REDIS_HOST: redis # Redis 서비스 이름
    depends_on:
      - db # db 서비스가 먼저 시작되어야 함
      - redis # redis 서비스가 먼저 시작되어야 함
    networks:
      - app-network
    restart: on-failure # 컨테이너 실패 시 재시작

  db:
    image: postgres:13 # PostgreSQL 13 이미지 사용
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
    volumes:
      - pgdata:/var/lib/postgresql/data # 데이터 영구 저장을 위한 명명된 볼륨
    networks:
      - app-network
    restart: always

  redis:
    image: redis:6-alpine # Redis 6 이미지 사용
    ports:
      - "6379:6379" # Redis CLI 등 외부 접근을 위해 포트 노출 (선택 사항)
    volumes:
      - redisdata:/data # 데이터 영구 저장을 위한 명명된 볼륨 (선택 사항)
    networks:
      - app-network
    restart: always

volumes:
  pgdata: # PostgreSQL 데이터 볼륨
  redisdata: # Redis 데이터 볼륨

networks:
  app-network:
    driver: bridge # 사용자 정의 브릿지 네트워크

docker-compose.yml 파일의 주요 특징은 다음과 같습니다.

  • backend 서비스: build: ./backend를 통해 로컬 backend 디렉토리의 Dockerfile을 사용하여 이미지를 직접 빌드합니다. volumes: - ./backend:/app는 개발 중 코드 변경 사항이 즉시 컨테이너에 반영되도록 합니다. depends_on을 통해 dbredis 서비스가 먼저 시작되도록 보장합니다.
  • db 서비스: postgres:13 이미지를 사용하고, pgdata라는 명명된 볼륨을 통해 데이터베이스 데이터를 영구적으로 저장합니다.
  • redis 서비스: redis:6-alpine 이미지를 사용합니다. redisdata 볼륨은 Redis의 데이터도 영구적으로 보존할 수 있게 합니다.
  • networks: app-network라는 단일 네트워크에 모든 서비스가 연결되어 서로의 서비스 이름을 호스트 이름처럼 사용하여 통신할 수 있습니다 (예: backend에서 db로 PostgreSQL에 접근).
  • environment: 각 서비스에 필요한 환경 변수를 설정하여 애플리케이션이 올바르게 동작하도록 합니다.

환경 실행 및 확인

프로젝트 루트 디렉토리(docker-compose.yml 파일이 있는 곳)에서 다음 명령어를 실행하여 모든 서비스를 시작합니다.

docker compose up -d
  • up: docker-compose.yml 파일에 정의된 모든 서비스를 생성하고 시작합니다.
  • -d (detached mode): 컨테이너를 백그라운드에서 실행하여 터미널을 계속 사용할 수 있게 합니다.

서비스가 정상적으로 시작되었는지 확인하려면 다음 명령어를 사용합니다.

docker compose ps

모든 서비스가 Up 상태여야 합니다. 이제 웹 브라우저에서 http://localhost:3000에 접속하여 "Hello from Backend Service!" 메시지를 확인할 수 있습니다. http://localhost:3000/data에 접속하면 백엔드가 데이터베이스와 Redis에서 데이터를 가져와 응답하는 것을 볼 수 있습니다.

로그를 확인하려면:

docker compose logs -f backend # 백엔드 서비스 로그 실시간 확인
docker compose logs # 모든 서비스 로그 한 번에 확인

서비스를 중지하고 컨테이너를 제거하려면:

docker compose down

만약 볼륨까지 완전히 삭제하려면 (주의: 데이터 손실):

docker compose down --volumes

이처럼 Docker Compose를 활용하면 복잡한 다중 서비스 환경도 단 몇 줄의 설정과 하나의 명령어로 손쉽게 구축하고 관리할 수 있습니다.

Docker Compose를 활용한 다중 서비스 로컬 개발 환경 구축 실전 가이드 - library, setup, books, read, stately, interior design, reside, furniture, nostalgia, room, space, victorian, library, library, library, library, library, room

Image by wal_172619 on Pixabay

Docker Compose 고급 활용 팁

Docker Compose는 단순한 다중 서비스 실행을 넘어, 개발 워크플로우를 더욱 효율적으로 만들 수 있는 다양한 고급 기능을 제공합니다.

환경 변수 관리: `.env` 파일 활용

docker-compose.yml 파일 내부에 직접 환경 변수를 명시하는 대신, .env 파일을 사용하여 환경 변수를 관리할 수 있습니다. 이는 특히 민감한 정보(예: 비밀번호)나 환경별로 달라지는 값들을 관리할 때 유용합니다. Docker Compose는 docker-compose.yml 파일과 동일한 디렉토리에 있는 .env 파일을 자동으로 로드합니다.

1. .env 파일 생성

# .env
POSTGRES_USER=myuser_dev
POSTGRES_PASSWORD=mypassword_dev
POSTGRES_DB=mydatabase_dev
REDIS_HOST=redis
POSTGRES_HOST=db

2. docker-compose.yml 수정

environment 섹션에서 변수 이름을 직접 명시하는 대신, ${환경변수명} 형태로 사용합니다. docker-compose.yml 파일에 직접 값을 넣어도 되지만, .env 파일에서 값을 가져오도록 설정할 수도 있습니다.

# docker-compose.yml (일부 발췌)
services:
  backend:
    # ...
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_HOST: ${POSTGRES_HOST}
      REDIS_HOST: ${REDIS_HOST}
    # ...

  db:
    # ...
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    # ...

이렇게 하면 .env 파일만 수정하여 환경 변수를 쉽게 변경할 수 있습니다. .env 파일은 일반적으로 Git 저장소에서 제외(.gitignore에 추가)하여 보안을 강화합니다.

다중 Compose 파일로 환경 분리

개발, 테스트, 프로덕션 등 여러 환경에 따라 서비스 구성이 달라져야 할 때가 있습니다. 이럴 때는 여러 개의 docker-compose.yml 파일을 사용하여 환경을 분리할 수 있습니다.

  • docker-compose.yml: 공통적으로 사용되는 기본 설정
  • docker-compose.dev.yml: 개발 환경에 특화된 설정 (예: 볼륨 마운트, 디버그 포트)
  • docker-compose.prod.yml: 프로덕션 환경에 특화된 설정 (예: 리소스 제한, 복제본 수)

예를 들어, 개발 환경에서는 로컬 코드 변경을 즉시 반영하기 위해 볼륨 마운트를 사용하고 싶을 수 있습니다. 이 경우 docker-compose.dev.yml에 해당 설정을 추가합니다.

# docker-compose.dev.yml
version: '3.8'

services:
  backend:
    volumes:
      - ./backend:/app # 개발 중 코드 변경을 위한 볼륨 마운트
      - /app/node_modules # node_modules는 제외
    environment:
      NODE_ENV: development
      DEBUG: "true"

이후 docker compose up 명령 시 -f 옵션을 사용하여 여러 Compose 파일을 함께 지정합니다. 뒤에 오는 파일이 앞선 파일의 설정을 덮어씁니다.

docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

이렇게 하면 공통 설정 위에 개발 환경 특화 설정을 덮어씌워 적용할 수 있습니다.

헬스 체크(Health Check)

depends_on은 서비스의 시작 순서를 보장하지만, 서비스가 완전히 준비되었는지까지는 보장하지 않습니다. 예를 들어, 데이터베이스 컨테이너가 시작되었더라도 내부의 데이터베이스 서버가 연결을 받을 준비가 되기까지는 시간이 걸릴 수 있습니다. 이때 헬스 체크(Health Check)를 사용하면 서비스의 실제 준비 상태를 확인할 수 있습니다.

# docker-compose.yml (일부 발췌)
services:
  backend:
    # ...
    depends_on:
      db:
        condition: service_healthy # db 서비스가 healthy 상태일 때까지 기다림
      redis:
        condition: service_healthy # redis 서비스가 healthy 상태일 때까지 기다림
    # ...

  db:
    image: postgres:13
    # ...
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d mydatabase"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 10s # 시작 후 10초 동안은 실패해도 재시도

db 서비스에 healthcheck를 정의하여 PostgreSQL이 pg_isready 명령어를 통해 연결 준비가 되었는지 주기적으로 확인합니다. backend 서비스는 depends_on에서 condition: service_healthy를 사용하여 db 서비스가 건강한 상태가 될 때까지 기다립니다. 이는 애플리케이션 시작 시 발생하는 연결 오류를 줄이는 데 매우 효과적입니다.

스케일링 (Scaling)

Docker Compose는 로컬 환경에서 서비스의 인스턴스를 여러 개 실행하여 스케일링을 테스트할 수 있도록 지원합니다. 이는 부하 분산이나 다중 인스턴스 환경에서의 애플리케이션 동작을 확인하는 데 유용합니다.

docker compose up -d --scale backend=3

위 명령은 backend 서비스를 3개의 인스턴스로 실행합니다. docker compose ps 명령으로 확인해 보면 backend-1, backend-2, backend-3과 같은 이름으로 여러 컨테이너가 실행되고 있음을 알 수 있습니다. 로드 밸런싱이 필요하다면 Nginx와 같은 프록시 서비스를 추가하여 설정할 수 있습니다.

마무리: 더 효율적인 개발을 위한 첫걸음

지금까지 Docker Compose를 활용하여 다중 서비스 로컬 개발 환경을 구축하는 실전 가이드를 상세히 살펴보았습니다. 복잡한 의존성 관리, 환경 불일치, 수동 설정의 어려움 등 개발자가 직면하는 다양한 문제들을 Docker Compose가 어떻게 해결해 줄 수 있는지 이해하셨기를 바랍니다.

Docker Compose는 다음과 같은 강력한 이점을 제공합니다.

  • 일관된 개발 환경: 모든 팀원이 동일한 환경에서 작업하여 "내 컴퓨터에서는 되는데..." 문제를 해결합니다.
  • 향상된 생산성: 환경 설정에 드는 시간을 최소화하고, 코드 개발에 집중할 수 있도록 돕습니다.
  • 쉬운 환경 관리: 단일 docker-compose.yml 파일로 여러 서비스를 정의하고, 한 번의 명령으로 전체 환경을 제어할 수 있습니다.
  • 유연한 확장성: .env 파일, 다중 Compose 파일, 헬스 체크, 스케일링 등 고급 기능을 통해 다양한 개발 시나리오에 대응할 수 있습니다.

이 가이드를 통해 Docker Compose의 기본적인 사용법부터 실전 예제, 그리고 고급 활용 팁까지 익히셨다면, 이제 여러분의 개발 워크플로우를 한 단계 더 발전시킬 준비가 된 것입니다. 컨테이너 기반의 효율적인 개발 환경은 더 빠르고 안정적인 소프트웨어 개발을 위한 필수적인 도구입니다.

이 글에서 제시된 예제를 직접 따라 해보면서 Docker Compose의 강력함을 경험해 보시길 강력히 추천합니다. 처음에는 다소 복잡하게 느껴질 수 있지만, 익숙해지면 여러분의 개발 생활에 없어서는 안 될 소중한 도구가 될 것입니다. 더 나아가 Docker Swarm이나 Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼으로 확장하는 기반 지식이 될 수도 있습니다.

Docker Compose를 사용하면서 겪었던 경험이나 궁금한 점이 있다면 언제든지 댓글로 공유해주세요. 함께 성장하는 개발 커뮤니티를 만들어가는 데 기여해주셔서 감사합니다!

📌 함께 읽으면 좋은 글

  • [튜토리얼] Playwright 활용 웹 애플리케이션 E2E 테스트: 효율적인 환경 구축 및 실전 가이드
  • [튜토리얼] Shadcn UI와 Tailwind CSS: 반응형 웹 컴포넌트 개발 환경 구축 가이드
  • [튜토리얼] AWS Lambda API Gateway 활용 서버리스 REST API 구축 실전 가이드

이 글이 도움이 되셨다면 공감(♥)댓글로 응원해 주세요!
궁금한 점이나 다루었으면 하는 주제가 있다면 댓글로 남겨주세요.

반응형