[Docker Mastery] - 8

Docker-Compose를 이용한 다중 컨테이너 오케스트레이션

시작

기존 도커만으로 불편한점

이전까진 각 컨테이너 실행때마다 이미지를 빌드하고 컨테이너를 실행하면서 옵션을 매번 설정해주었죠. 이후에도 컨테이너에 적용한 옵션을 이용하려면 어딘가에 계속 기록해두어야 할 것 입니다. 또한 하나 하나씩 실행해야 합니다.
이 문제를 해결하기 위해 Docker-Compsoe가 대안입니다.

Docker Compose

즉, 도커 컴포즈는 여러 컨테이너 실행에 필요한 docker build, docker run과정을 한 설정파일에서 기록하여 관리하고 실행 또한 설정파일을 기준으로 실행합니다. 이런 설정파일을 오케스트레이션 명령 셋이라고 부릅니다.
단, 그렇다고해서 Dockerfile, 이미지나 컨테이너, 다수 호스트에서 다중 컨테이너 관리를 완전히 대체하지는 않습니다. 도커 컴포즈는 한 호스트에서 여러 컨테이너를 실행하기에 적합합니다.

Service

다중 컨테이너 애플리케이션을 구성하는 컨테이너라고 이해하면 됩니다. 실제로 컨테이너이기도 합니다. 컴포즈안에서는 여러 서비스(컨테이너) 환경설정을 입력합니다. 포트, 환경변수, 볼륨, 네트워크 등 도커 명령으로 수행가능한 모든 일을 대체할 수 있습니다.

Compose 파일 작성하기

프로젝트 컨텍스트 혹은 특정 경로에 yaml확장자 파일을 생성합니다. 다중 컨테이너 환경과 프로젝트 설정을 기재합니다. 익스텐션을 설치해 자동완성을 이용해보는것을 추천합니다.

yaml
# docker-compose.yaml

# 도커 컴포즈 사양의 버전(버전 별로 사용가능한 설정이 존재)
# https://docs.docker.com/compose/compose-file/ 
version: "3.8"

# 서비스의 설정을 명시합니다.
# 들여쓰기를 철저히 지켜야합니다. 들여쓰기는 종속됨을 표현합니다.
services: 
  # 각 컨테이너에 대해 구성 설정 
  mongodb:
    image: 'mongo'
    volumes:
      # 네임드 볼륨 설정
      - data:/data/db 
    # environment:
      # - MONGO_INITDB_ROOT_USERNAME=max와 동일
      # MONGO_INITDB_ROOT_USERNAME: max
      # MONGO_INITDB_ROOT_PASSWORD: secret
    # environment를 사용하는것이 아닌 별도 환경 변수 파일로 설정하는 경우
    env_file:
      - ./env/mongo.env
    # networks:
    #   - sample-net
  # backend:

  # foorntend:

# service에서 사용중인 명명 볼륨을 명시합니다.
# 다른 컨테이너에서 이 data 폴더를 사용할 수도 있습니다.
# 익명 볼륨, 바인드 마운트는 명시하지 않습니다.
volumes:
  data:

도커 컴포즈로 실행되는 서비스의 경우 기본으로 -d, --rm옵션을 가지고 있기 때문에 해당 옵션은 설정하지 않았습니다. 또한 네트워크를 지정하지 않더라도 컴포즈 내에서 작동하는 모든 컨테이너는 생성 당시 같은 네트워크 공간에 포함됩니다. 다만 다른곳에서 참조하고싶은 경우 이를 명시해도 괜찮습니다. networks설정을 추가해주어야 합니다.
network옵션을 설정하지 않은 경우 yaml 파일명에 _default가 붙은채 네트워크가 생성됩니다. volume의 경우는 프로젝트 폴더명+볼륨명 으로 생성됩니다. 프로젝트 이름이 접두사로 붙게됩니다.

Linux에 Docker Compose 설치

기본적으로 Docker Compose는 Docker설치시 같이 설치됩니다. Linux의 경우 별도로 설치해야 합니다.

Docker Compose Up&Down

도커 컴포즈 실행시 up명령을 이용합니다.

bash
docker-compose up

위 명령은 attached로 실행하며 터미널에서 나오는 경우 --rm옵션이 적용됩니다.

-d옵션을 이용해 detached모드로 실행합니다.

bash
docker-compose up -d

중지는 down명령을 이용합니다.

bash
docker-compose down

볼륨도 같이 삭제할 경우 -v옵션을 이용합니다.

bash
docker-compose down -v

다중 컨테이너로 작업하기

이어서 백엔드 부분의 설정도 진행해봅시다.

환경변수는 별도 파일로 정리합니다.

json
// ./env/backend.env

MONGODB_USERNAME=max
MONGODB_PASSWORD=secret

yaml 파일을 작성해봅시다.

yaml
# docker-compose.yaml

version: "3.8"

services: 
  # 각 컨테이너에 대해 구성 설정 
  # ...
  backend:
    # image: 'backend-server'

    # 빌드 컨텍스트 및 도커 파일명 명시
    # build:
    #   context: ./backend
    #   dockerfile: Dockerfile
    #   arge:
    #     some-arg:1
    
    # Dockerfile을 찾아 이미지를 빌드합니다.
    build: ./backend

    ports:
      - '80:80'
    volumes:
      - logs:/app/logs
      # 바인드 마운트 현재 경로에서 ./backend 폴더를 컨테이너내 app에 마운트
      - ./backend:/app
      - /app/node_modules
    env_file:
      - ./env/backend.env
    # 도커 컴포즈에만 존재 
    # 동시에 여러 컨테이너가 생성되는데, 의존할 컨테이너를 명시할 수 있다.
    # backend의 경우 mongodb가 실행된 후 backend가 후에 실행되어야하고 의존함.
    depends_on:
      - mongodb

  # foorntend:
volumes:
  data:
  # 네임드 볼륨 명시
  logs:

이어서 frontend부분도 완성해봅시다. 프론트엔드의 경우 인터렉티브 옵션 -it 옵션이 필요했습니다.

yaml
# docker-compose.yaml

version: "3.8"

services: 
  # 각 컨테이너에 대해 구성 설정 
  # ...

  frontend:
    build: ./frontend
    ports:
      - '3000:3000'
    volumes:
      - ./frontend/src:/app/src
    # -i
    stdin_open: true
    # -t
    tty: true
    depends_on:
      - backend
volumes:
  data:
  logs:

이제 완성되었습니다. 그대로 실행하면 됩니다.

bash
docker-compose up -d

이렇듯 더 복잡한 프로젝트의 경우 docker-compose를 이용하는것이 유용합니다. 물론 명령을 기록할 수 있기 때문에 단일 컨테이너를 실행하는 경우에도 유용합니다.

한번 빌드가 완료되면 캐시에 남아 더 이상 빌드를 하지 않게 됩니다. 코드 변경 사항이 일어난 경우에는 build 명령으로 다시 빌드가 가능합니다.

bash
docker-compose build

이후 up명령 실행시 빌드된 이미지가 있으므로 위 build명령으로 수행된 이미지를 가지고 컨테이너를 실행하게 됩나다.

컨테이너 명을 명시하지 않고 컨테이너를 실행하면 네임은 프로젝트 폴더명_서비스 컨테이너명_증가숫자 와 같이 정해집니다. 컨테이너 명이 겹칠일은 없겠네요.

컨테이너명을 명시하려면 container_name: mongodb와 같이 컨테이너명을 명시해주어야 합니다.

yaml
# docker-compose.yaml

version: "3.8"

services: 
  # 각 컨테이너에 대해 구성 설정 
  # ...

  frontend:
    container_name: frontend
volumes:
  data:
  logs: