Developer.

[멋사 백엔드 19기] TIL 62일차 Docker(3)

작성중

📂 목차


📚 본문

Docker Compose

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

핵심 특징

  • YAML 파일 기반: docker-compose.yml 파일 하나로 전체 애플리케이션 스택을 정의
  • 선언적 방식: “어떻게” 실행할지가 아닌 “무엇을” 실행할지 정의
  • 단일 명령어: docker-compose up 하나로 모든 서비스 실행
  • 환경 일관성: 개발/테스트/프로덕션 환경 간 일관된 구성 유지

웹 애플리케이션(프론트엔드 + 백엔드 + DB + Redis)을 배포한다고 가정해보자.

docker run 만 사용할 경우:

docker network create app-network

mysql 서버

docker run -d \
  --name mysql \
  --network app-network \
  -e MYSQL_ROOT_PASSWORD=root123 \
  -e MYSQL_DATABASE=myapp \
  -v mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  mysql:8.0

Redis 서버

docker run -d \
  --name redis \
  --network app-network \
  -v redis-data:/data \
  -p 6379:6379 \
  redis:7-alpine

백서버

docker run -d \
  --name backend \
  --network app-network \
  -e DB_HOST=mysql \
  -e DB_PASSWORD=root123 \
  -e REDIS_HOST=redis \
  -p 8080:8080 \
  myapp-backend:latest

프론트서버

docker run -d \
  --name frontend \
  --network app-network \
  -e BACKEND_URL=http://backend:8080 \
  -p 3000:3000 \
  myapp-frontend:latest

위와 같이 명령어가 길고 복잡하며, 다른 팀원들에게서는 다르게 실행될 수도 있어 재현성이 부족하다는 단점이 있고, 순서 관리가 힘들며, 환경 변수 관리에 혼란(여러 곳에 흩어짐)이 있게 된다. bash script 로 이를 커버 할 수 있지만 bash script 의 코드를 해석해야한다는 불편함과 코드 로직을 직접 전부 짜야하는 단점이 있다.

이를 해결하고자 Docker Compose 가 나왔다.

Docker Compose 기본 구조

version: '3.8'

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
    
  database:
    image: postgres:14
    environment:
      POSTGRES_PASSWORD: secret

버전은 굳이 명시 안해도 알아서 자동으로 찾아온다.

  • services: 실행시킬 컨테이너들을 넣을 수 있는 실행 동작을 추상화한 블럭인 듯하며, 실행 단위라고 봐도 무방하다. 실행 단위마다 최소 하나의 이미지가 들어가야 한다.
  • image: 이미지 명과 태그가 들어가는 자리이다. 해당 이미지로 컨테이너를 실행하게 된다.
  • ports: 서비스가 어떤 포트로 포워딩이 될지를 정하는 곳이다.
  • environment: 환경변수를 설정할 수 있는 블록이고, key: value 로도 되고, - key:value 로도 된다.

container_name 도 있는데 이는 잘 쓰이지 않는다. scaling 할 때 불편함 때문

Docker Network 설정

서비스끼리의 네트워크를 설정해보자.

services:
  web:
    image: nginx
    networks:
      - frontend
      - backend
  
  api:
    image: myapi
    networks:
      - backend
  
  db:
    image: postgres
    networks:
      - backend

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

기본적으로 networks 라는 블록이 없으면 docker-compose 내부의 서비스들은 한 네트워크에 배치가 되어 서로 소통을 할 수 있게 된다. 만약 네트워크를 따로 설정해주고 싶다면 위처럼 networks 블록을 사용하여 network 를 생성할 수 있다.

Docker Volume 설정

데이터를 영구적으로 저장하기 위한 볼륨을 지정해보자.

services:
  db:
    image: postgres:14
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
  
  web:
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - static_content:/usr/share/nginx/html

volumes:
  db_data:
    driver: local
  static_content:

volumes 를 통해 Named Volume 을 지정하고 있음을 볼 수 있고, 이를 위 services 에서 쓰고 있음을 볼 수 있다. 또한 마지막 : 의 구분자로 read-only 를 주고 있는것도 볼 수 있을 것이다.

Docker Compose Build 블럭

서비스에 build 블럭을 쓸 수도 있다.

services:
  web:
    build:
      context: ./app
      dockerfile: Dockerfile.dev
      args:
        - NODE_VERSION=18
        - APP_ENV=development
      cache_from:
        - myapp:latest
    image: myapp:dev
    ports:
      - "3000:3000"
Docker Compose 환경변수 연동
services:
  db:
    image: postgres:14
    env_file:
      - .env
      - .env.local
    environment:
      POSTGRES_USER: ${DB_USER:-postgres}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DBNAME:-myapp}

위처럼 bash script 의 문법을 가져가면 된다. 민감한 정보는 env 파일로 다루고, .env 파일은 일반적인 설정이며 .gitignore 에 추가하도록 한다.

Docker 실습: Multi-container 구성하기