관리 메뉴

근묵자흑

Docker Compose 본문

k8s

Docker Compose

Luuuuu 2025. 3. 30. 17:58

Docker Compose 로고

Docker Compose란?

Docker Compose는 단일 서버에서 여러 개의 컨테이너를 하나의 서비스로 정의하고 컨테이너 묶음으로 관리할 수 있는 도구입니다. 복잡한 애플리케이션을 구성하는 여러 컨테이너를 함께 정의하고 실행할 수 있게 해줍니다.

Docker Compose를 사용하는 이유

여러 컨테이너가 하나의 애플리케이션으로 동작할 때 Docker Compose를 사용하지 않으면 각 컨테이너를 하나씩 생성해야 합니다. 예를 들어, WordPress와 MySQL로 구성된 웹 애플리케이션을 실행하려면 다음과 같이 두 개의 run 명령어를 입력해야 합니다:

$ docker run --name wordpress_db -d mysql:8

$ docker run -d -p 8080:80 \
--link wordpress_db:mysql --name my_wordpress \
wordpress:latest

이렇게 여러 컨테이너로 구성된 애플리케이션을 실행하기 위해 매번 여러 개의 명령어를 입력하는 것은 번거롭습니다. Docker Compose를 사용하면 여러 컨테이너의 설정을 하나의 파일에 정의하고, 단일 명령어로 모든 컨테이너를 생성 및 실행할 수 있습니다.

Docker Compose는 여러 컨테이너의 옵션과 환경을 정의한 파일을 읽어 컨테이너를 순차적으로 생성하는 방식으로 동작합니다. 컨테이너 간의 의존성, 네트워크, 볼륨 등을 함께 정의할 수 있으며, 서비스의 컨테이너 수를 유동적으로 조절할 수도 있습니다.

Docker Compose 설치

Linux에서 설치

Linux에서는 다음 명령어로 Docker Compose를 설치할 수 있습니다:

$ curl -SL https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

설치가 완료되었는지 확인하려면 다음 명령어로 Docker Compose의 버전을 확인합니다:

$ docker-compose -v

 

다른 OS에서의 설치 방법은 Docker Compose 공식 문서에서 확인할 수 있습니다.

docker-compose.yml 작성 및 활용

Docker Compose를 사용하려면 docker-compose.yml 파일을 작성해야 합니다. 이 파일에는 애플리케이션을 구성하는 서비스, 네트워크, 볼륨 등의 설정이 포함됩니다.

아래 예시는 WordPress와 MySQL을 사용하는 웹 애플리케이션의 docker-compose.yml 파일입니다:

version: '3.9'

services:
  db:
    image: mysql:8
    volumes:
    - db:/var/lib/mysql
    restart: unless-stopped
    environment:
    - MYSQL_ROOT_PASSWORD=mypassword
    - MYSQL_DATABASE=wordpress
    - MYSQL_USER=wordpress
    - MYSQL_PASSWORD=wordpress
    networks:
    - wordpress

  wordpress:
    depends_on:
    - db
    image: wordpress:latest
    ports:
    - "8000:80"
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    networks:
    - wordpress

volumes:
  db: {}

networks:
  wordpress: {}

주의: YAML 파일에서 들여쓰기를 할 때는 탭(Tab)이 아닌 공백(Space)을 사용해야 합니다. Docker Compose는 탭을 인식하지 못합니다.

 

이 파일을 저장한 후 다음 명령어로 Docker Compose 프로젝트를 실행할 수 있습니다:

$ docker-compose up -d

Docker Compose YAML 파일의 주요 옵션

아래에서는 Docker Compose YAML 파일에서 사용할 수 있는 다양한 옵션들을 살펴보겠습니다. 이러한 옵션들을 조합하여 복잡한 애플리케이션 구조를 정의할 수 있습니다.

서비스 정의

서비스는 Docker Compose로 생성할 컨테이너 옵션을 정의합니다. 우리가 정의하는 컨테이너 각각에 대한 명세는 service라는 단위로 정의됩니다.

services:
  container_1:
    image: myapp/container1
  container_2:
    image: myapp/container2

주요 서비스 옵션

  • image: 서비스의 컨테이너를 생성할 때 사용할 이미지 이름을 지정합니다. 다양한 방식으로 원하는 이미지를 가져올 수 있습니다.
services:
web:
    # 이미지 명
    image: nginx

redis:
    # 이미지 명: 태그명
    image: redis:5

db:
    # 이미지 명@sha256: IMAGE ID
    image: mysql@sha256:0ed5d5928d4737458944eb604cc8509e245c3e19d02ad83935398bc4b991aac7

cache:
    # 저장소명/이미지명
    image: library/redis

api:
    # 레지스트리명/저장소명/이미지명
    image: docker.io/library/redis

private:
    # 개인 레지스트리 주소:포트/이미지명
    image: my_private.registry:5000/redis
  • build: 도커파일로 이미지를 빌드해 서비스의 컨테이너를 생성하도록 설정합니다. Dockerfile을 통해 컨테이너를 생성하고자 할 때 사용합니다.
services:
frontend:
    image: awesome/webapp
    build: ./webapp # 하위 단계를 명세하지 않는다면 context 역할

backend:
    image: awesome/database
    build:
    context: backend # Dockerfile을 탐색할 경로
    dockerfile: ../backend.Dockerfile # 파일 이름이 Dockerfile이 아닌 경우 파일명을 명시

custom:
    build: ~/custom # 홈 디렉토리 표시 "~"를 사용할 수도 있음

imagebuild가 동시에 있는 경우, 먼저 image에 정의한 이미지를 가져온 다음 레지스트리에서 이미지를 찾을 수 없는 경우 Dockerfile에서 가져온 이미지를 빌드합니다.

  • links: 다른 서비스에 서비스명으로 접근할 수 있도록 설정합니다.
services:
web:
    links:
    - db
    - db:database
    - redis
  • environment: 컨테이너 내부에서 사용할 환경변수를 지정합니다. 두 가지 방식으로 사용할 수 있습니다:
# Map 방식
services:
web:
    environment:
    RACK_ENV: development
    SHOW: "true"
    USER_INPUT: "hello"

# Array 방식
services:
web:
    environment:
    - RACK_ENV=development
    - SHOW=true
    - USER_INPUT=hello
  • env_file: 환경변수를 직접 정의하는 것이 아닌 파일로 정의할 경우 해당 옵션을 사용합니다.
services:
web:
    env_file: some_env.env
# some_env.env
RACK_ENV=development
VAR="quoted"

이 방식을 사용하면 환경 변수를 파일 형태로 관리할 수 있어 더 용이합니다.

  • command: 컨테이너가 실행될 때 수행할 명령어를 설정합니다. DockerfileCMD와 유사한 역할을 합니다.
services:
web:
    image: nginx
    command: nginx -g 'daemon off;'

DockerfileCMD는 주로 pip install, gradle build와 같이 서버를 구성하는 기본 요소를 설치하는 명령에 사용되며, docker-compose.ymlcommand는 주로 서버를 배포하는 명령어(예: ... run serve)와 같이 서비스를 구동시키는 명령에 사용됩니다.

  • entrypoint: 컨테이너가 실행될 때 초기 명령어를 정의합니다. DockerfileENTRYPOINT와 동일한 역할을 수행합니다.
services:
web:
    entrypoint: /code/entrypoint.sh

해당 명령어는 단 한번만 선언이 가능하기 때문에 build 옵션을 통해 Dockerfile에서도 ENTRYPOINT를 명시하고 있는 경우 둘 중 하나(혹은 둘 다)를 지워야 합니다.

  • depends_on: 특정 컨테이너에 대한 의존 관계를 나타냅니다. 이 항목에 명시된 컨테이너가 먼저 생성되고 실행됩니다.
services:
web:
    depends_on:
    - db
db:
    image: mysql:8
  • labels: 컨테이너에 메타데이터를 추가할 수 있는 항목입니다.
services:
web:
    labels:
    - "com.example.description=Accounting webapp"
    - "com.example.department=Finance"
  • ports: 컨테이너를 개방할 포트를 설정합니다.
services:
web:
    ports:
    - "8080:80"
    - "8081-8100:8081-8100"
  • extends: 다른 YAML 파일이나 현재 YAML 파일에서 서비스 속성을 상속받도록 설정합니다. 이 옵션은 반복적인 구성을 줄이고 여러 환경에서 재사용 가능한 서비스 정의를 만들 때 유용합니다.
services:
web:
    extends:
    file: extend_compose.yml
    service: extend_web

 

실제 사용 예시:

docker-compose.yml:

version: '3.7'
services:
web:
    extends:
    file: extend-compose.yml
    service: testweb

extend-compose.yml:

version: '3.7'
services: 
testweb: 
    image: httpd 
    ports:
    - "80"

 

이렇게 구성하면 docker-compose.ymlweb 서비스는 extend-compose.yml에 정의된 testweb 서비스의 속성을 상속받습니다. 두 파일을 모두 사용하여 배포하려면 다음 명령어를 사용합니다:

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

 

확장된 서비스는 원본 서비스의 구성을 재사용하면서 필요에 따라 추가 설정을 덮어쓸 수 있습니다. 단, links와 같은 의존성이 있는 옵션들은 상속받을 수 없습니다.

네트워크 정의

  • driver: 서비스의 컨테이너가 사용할 네트워크 드라이버를 설정합니다.
networks:
mynetwork:
    driver: overlay
    driver_opts:
    subnet: "255.255.255.0"
    IPAddress: "10.0.0.2"
  • ipam: IP 주소 관리를 위한 옵션으로 서브넷, IP 범위 등을 설정할 수 있습니다.
networks:
mynetwork:
    ipam:
    driver: default
    config:
        - subnet: 172.20.0.0/16
        ip_range: 172.20.5.0/24
        gateway: 172.20.5.1
  • external: 기존의 네트워크를 사용하도록 설정합니다. external: true 옵션을 사용하면 새 네트워크가 만들어지지 않고, 기존 네트워크에 연결됩니다. 이 옵션은 다른 프로젝트나 수동으로 생성한 네트워크를 재사용하고 싶을 때 유용합니다.
networks:
mynetwork:
    external: true

실제 사용 예시:

services:
web:
    image: httpd
    ports:
    - "80"
    command: httpd -D FOREGROUND
    depends_on:
    - db
    links:
    - db:mysql
    networks:
    - test1net

db:
    image: mysql:5.7
    environment:
    - MYSQL_DATABASE=testdb
    - MYSQL_ROOT_PASSWORD=test123
    networks:
    - test1net
networks:
test1net:
    external: true

 

이렇게 구성하면 test1net이라는 기존 네트워크를 사용하여 컨테이너들이 통신할 수 있게 됩니다. 새로운 네트워크가 생성되지 않고, 기존에 존재하는 test1net 네트워크에 연결됩니다.

볼륨 정의 및 사용법

볼륨은 컨테이너의 데이터를 영구적으로 저장하기 위한 메커니즘입니다. Docker Compose에서는 다양한 방식으로 볼륨을 정의하고 사용할 수 있습니다.

볼륨 정의 옵션

  • driver: 볼륨을 생성할 때 사용될 드라이버를 설정합니다.
volumes:
myvolume:
    driver: local
    driver_opts:
    type: "nfs"
    o: "addr=10.0.0.1,nolock,soft,rw"
    device: ":/path/to/dir"
  • external: 프로젝트를 생성할 때마다 볼륨을 새로 생성하지 않고 기존 볼륨을 사용하도록 설정합니다. 볼륨을 지정하지 않으면 디렉터리 이름을 이용하여 신규 볼륨이 생성됩니다.
volumes:
myvolume:
    external: true

볼륨 사용 방식

Docker Compose에서는 다양한 방식으로 볼륨을 사용할 수 있습니다:

  1. Named Volumes: 이름이 있는 볼륨으로, Docker가 관리하는 위치에 저장됩니다.
services:
    web:
    volumes:
        - testvolume1:/var/www/html  # 이름이 있는 볼륨을 연결

volumes:
    testvolume1:  # 볼륨 정의
  1. 기존 볼륨 재사용: external: true 옵션을 사용하여 기존 볼륨을 재사용합니다.
services:
    web:
    volumes:
        - testvolume1:/var/www/html  # 기존 볼륨을 연결

volumes:
    testvolume1:
    external: true  # 기존에 만들어 둔 볼륨을 사용

실제 사용 예시:

# 먼저 볼륨 생성
$ docker volume create mydata

# docker-compose.yml에서 외부 볼륨 사용
services:
    web:
    volumes:
        - mydata:/var/www/html

volumes:
    mydata:
    external: true
  1. 호스트 디렉터리 마운트(nfs): 호스트의 디렉터리를 컨테이너에 마운트합니다.
services:
    web:
    volumes:
        - /host/directory:/container/path  # 호스트 디렉터리를 마운트

실제 사용 예시:

# 호스트의 디렉터리에 파일 생성
$ mkdir -p /data/web
$ echo "Hello Docker" > /data/web/test.txt

# docker-compose.yml에서 해당 디렉터리 마운트
services:
    web:
    volumes:
        - /data/web:/usr/local/apache2/htdocs
  1. tmpfs: 디스크가 아닌 RAM에 데이터를 저장하는 방식으로, 영구 보관이 불가능합니다. 임시 데이터를 고속으로 처리해야 할 때 유용합니다.
services:
    web:
    volumes:
        - type: tmpfs
        target: /tmp
  1. iscsi: 스토리지에서 볼륨을 생성하고, 이를 컨테이너의 /dev/sda*와 같은 형태로 연결합니다.

Docker Compose에서 생성한 볼륨은 docker-compose down 명령어로 컨테이너를 삭제하면 함께 삭제됩니다. 하지만 external: true로 지정한 기존 볼륨과 네트워크는 컨테이너가 삭제되어도 유지됩니다. 볼륨을 포함하여 모든 리소스를 삭제하려면 docker-compose down -v 명령어를 사용합니다.

Docker Compose 네트워크

YAML 파일에 네트워크 항목을 정의하지 않으면 Docker Compose는 프로젝트별로 브리지 타입의 네트워크를 생성합니다. 생성된 네트워크의 이름은 [프로젝트 이름]_default로 설정됩니다.

서비스 내의 컨테이너는 --net-alias로 서비스 이름을 갖도록 자동 설정되므로, 이 네트워크에 속한 컨테이너는 서비스 이름으로 다른 서비스의 컨테이너에 접근할 수 있습니다.

 

예를 들어, web 서비스와 db 서비스가 있을 때 web 서비스의 컨테이너가 db라는 호스트 이름으로 접근하면, db 서비스의 컨테이너 중 하나의 IP로 연결됩니다. 컨테이너가 여러 개 존재할 경우 라운드 로빈 방식으로 연결이 분산됩니다.

Docker Compose 명령어

프로젝트 실행

# 포그라운드로 도커 컴포즈 프로젝트 실행
$ docker-compose up

# 백그라운드로 도커 컴포즈 프로젝트 실행
$ docker-compose up -d

# 프로젝트 이름 지정하여 도커 컴포즈 프로젝트 실행
$ docker-compose -p my-project up -d

# 서비스별 컨테이너 수 지정
$ docker-compose scale web=3 db=1

프로젝트 종료

# 프로젝트 내 컨테이너 및 네트워크 종료 및 제거
$ docker-compose down

# 프로젝트 내 컨테이너, 네트워크 및 볼륨 종료 및 제거
$ docker-compose down -v

프로젝트 목록 확인

# 도커 컴포즈 프로젝트 목록 확인
$ docker-compose ps

정리

Docker Compose는 여러 컨테이너로 구성된 애플리케이션을 쉽게 관리할 수 있게 해주는 도구입니다. 하나의 YAML 파일로 컨테이너, 네트워크, 볼륨 등을 정의하고, 단일 명령어로 전체 애플리케이션 스택을 실행할 수 있습니다. 네트워크와 볼륨을 효과적으로 관리하여 컨테이너 간 통신과 데이터 영속성을 확보할 수 있으며, extends 옵션을 통해 설정을 재사용할 수도 있습니다. 컨테이너의 수가 많아지거나 설정이 복잡해질수록 Docker Compose의 유용성이 더욱 커집니다.