[Docker Compose] Compose Specification

whatSup CheatSheet·2022년 10월 21일
0

Container

목록 보기
7/9
post-thumbnail
post-custom-banner

본 글은 Compose file format 3.8+ 버전을 보고 작성하였습니다.

Docker Compose

Docker Compose는 다중 컨테이너로 구성된 애플리케이션을 관리하기 위한 오케스트레이션(Orchestration) 도구이다.

  • Compose에서는 YAML파일을 사용하여 애플리케이션 서비스를 구성(명세)함
  • Compose는 다음과 같이 3단계 프로세스로 진행됨
    1. Dockerfile에 애플리케이션을 작성. 이를 통해 어디에서나 재현가능한 환경을 제공함
    2. 애플리케이션 서비스들을 compose.yml에 정의하여 함꼐 실행될 수 있도록 함.
    3. docker compose up을 통해 전체 앱을 실행

Compose Specification

Compose를 사용하기 전에 Compose 파일에 대해 먼저 알아보자.

Compose 파일은 Docker 애플리케이션의 서비스, 네트워크, 볼륨 등을 정의(명세) 하는 YAML 파일이다. 이를 통해 플랫폼에 구애받지 않는, 재현가능한 컨테이너 기반 애플리케이션을 정의할 수 있다.

  • Compose 파일의 기본 양식은 compose.yaml 혹은 compose.yml 이다.
    • 이전 버전에서 사용하던 docker-compose.yaml도 호환되지만, 두 파일이 같이 있는 경우 기본양식이 선호

Compose 파일의 최상위 Level에는 다음과 같은 구조를 포함할 수 있다.

  • Version (Deprecated): 지원 버전을 확인.
  • Service : 독립된 컨테이너에서 돌아가는 애플리케이션의 구성요소
    • 쉽게 이야기해서 Compose에서 돌아갈 Container에 대한 설정을 의미.
    • 메인 애플리케이션부터 기반 시스템까지 모두 이 Service에 포함됨
  • Network : Service는 Network를 통해 서로 통신함
    • 기본적으로 Compose는 Default 네트워크에 모든 컨테이너 서비스들을 연결함
  • Volume : 서비스는 영구적으로 유지해야 할 데이터를 Volume에 저장하고 공유함.
    • 마치 Docker의 volume과 같음
  • Config : 애플리케이션 서비스에서 필요한 설정 값 등을 명시하기 위해 config가 사용됨.
  • Secret : 애플리케이션에서 사용할 민감한 정보를 저장 시 사용됨

이들이 동작되는 예시를 살펴보자. 다음과 같은 구조를 가진 서비스가 있다고 해보자.

(External user) --> 443 [frontend network]
                            |
                  +--------------------+
                  |  frontend service  |...ro...<HTTP configuration>
                  |      "webapp"      |...ro...<server certificate> #secured
                  +--------------------+
                            |
                        [backend network]
                            |
                  +--------------------+
                  |  backend service   |  r+w   ___________________
                  |     "database"     |=======( persistent volume )
                  +--------------------+        \_________________/

이들의 구성은 다음과 같다.

  • service : webapp, database
  • secret : frontend 서비스에서 사용할 HTTPS 인증서
  • config : frontend 서비스에서 사용할 HTTP config
  • volume : backend와 연결된 volume
  • networks : 2개의 network들

이들을 위한 Compose file은 다음과 같이 구성될 것임.

services:
  frontend:
    image: awesome/webapp
    ports:
      - "443:8043"
    networks:
      - front-tier
      - back-tier
    configs:
      - httpd-config
    secrets:
      - server-certificate

  backend:
    image: awesome/database
    volumes:
      - db-data:/etc/data
    networks:
      - back-tier

volumes:
  db-data:
    driver: flocker
    driver_opts:
      size: "10GiB"

configs:
  httpd-config:
    external: true

secrets:
  server-certificate:
    external: true

networks:
  # The presence of these objects is sufficient to define them
  front-tier: {}
  back-tier: {}

이제 Compose의 top-Level component들 중에서 가장 자주사용하는 services, volumess, networks 대해서 자세히 알아보자.

service

본 글에서는 자주 사용할 것 같은 명령어만 정리한다. 나머지는 공식 문서를 참고하자.

profiles

Profiles은 선택적으로 서비스를 활성화할 수 있도록 도와주는 속성이다.

  • 각 서비스를 프로필에 매핑하면, 해당 프로필이 활성화 된 경우에만 서비스가 시작된다.
  • 서비스를 프로필에 매핑시키지 않았다면, 해당 서비스는 항상 활성화된다.

예를 들어보자.

services:
  foo:
    image: foo
  bar:
    image: bar
    profiles:
      - test
  baz:
    image: baz
    depends_on:
      - bar
    profiles:
      - test
  zot:
    image: zot
    depends_on:
      - bar
    profiles:
      - debug
  • 위 서비스를 그냥 실행시키면 profiles 속성이 없는 foo는 항상 활성화됨
  • 만약 test 프로필만 활성화된다면, 해당하는 프로필에 속해있는 barbaz도 실행됨(foo는 고정적으로 실행되는 중..)
  • 만약 debug 프로필만 활성화되면, zot이 실행되어야 하지만, bar에 종속되어있으므로 실행되지 않음
  • debugtest가 모두 활성화되면, 위에 있는 모든 서비스가 활성화됨.
  • 만약 Compose가 그냥 bar명시적으로 실행하면, profiles을 활성화하지 않아도 해당 서비스(bar)와 해당 프로필(test)이 활성화됨
  • 만약 Compose가 그냥 baz명시적으로 실행하면, 해당 서비스와 해당 프로필이 활성화되며, depends_on이므로 bar도 실행됩니다.
  • 만약 Compose가 그냥 zot명시적으로 실행하면, 해당 서비스와 해당 프로필이 활성화됩니다. 하지만 depends_on에 의해 bar를 실행하려 할 때 해당 profile(test)이 zot의 profile(debug)다르므로, 실행될 수 없습니다. 따라서 결국 zot은 실행되지 않습니다.
    • 이러한 경우, bar의 profiles에 test를 추가로 포함시켜 해결할 수 있습니다.

image

image는 컨테이너를 시작할 이미지를 지정한다.

  • docker에서 build할 때와 마찬가지로, 로컬 환경에 없다면 hub에서 다운로드하여 사용한다.
services:
	# 이미지 지정은 다음과 같은 양식(도커 빌드할 때와 같음)으로 할 수 있다.
  image: redis
  image: redis:5
  image: redis@sha256:0ed5d5928d4737458944eb604cc8509e245c3e19d02ad83935398bc4b991aac7
  image: library/redis
  image: docker.io/library/redis
  image: my_private.registry:5000/redis

build

(image가 없다면) build는 컨테이너 이미지를 생성하기 위한 명령어이다. 해당 명령어를 통해 dockerfile을 자동으로 빌드하여 컨테이너를 생성하고, 이를 사용할 수 있다.

services:
  frontend:
    image: awesome/webapp
    build: ./webapp

  backend:
    image: awesome/database
    build:
      context: ../backend
      dockerfile: Dockerfile
			args:
				<abc>:123
  • awesome/webapp도커 이미지는 ./webapp이라는 하위폴더로부터 이미지를 생성한다. 해당 폴더에는 반드시 dockerfile이 있어야 한다.
    • 위와 같이 build에 경로를 바로 지정하여 사용할 수 있다.
  • awesome/database도커 이미지는backend라는 상위폴더로부터 이미지를 생성한다.
    • context에 있는 폴더(또는 git리포지토리 URL)에서 검색을 함(상대 혹은 절대경로)
    • dockerfile: (이름이 다를경우) 도커파일의 이름을 명시해줄 수 있음
    • args : 도커 이미지를 빌드할 때 사용할 args를 명시할 수 있음
  • build된 이미지는 이미지 레지스트리에 push된다.

depends_on

depends_on은 서비스 간 종속성을 나타냅니다.

services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres
  • Compose는 종속성 순서대로 서비스를 생성합니다.
    • 위 예시에서는 redis&dbweb
  • Compose는 종속성 순서대로 서비스를 제거합니다.
    • 위 예시에서는 webredis&db

containier_name

container_name은 컨테이너 이름을 지정해줄 수 있다. (지정하지 않는다면 default이름으로 지정됨)

container_name: my-web-container

cgroup_parent

cgroup_parent는 컨테이너에 대해 상위 cgroup을 지정해줄 수 있음

  • cgroup_parent: m-executor-abcd

deploy (배포 & 리소스 관리)

depoly는 서비스에 대한 런타임 요구사항들을 정의할 수 있다.

(간략하게 설명하고 넘어가는 component들은 docs를 참고)

  • endpoint_mode : 서비스에 연결하려는 (외부) 클라이언트에 대한 검색 방법(Virtual IP, DNS)을 지정한다.
services:
  frontend:
    image: awesome/webapp
    ports:
      - "8080:80"
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip
  • mode : 서비스를 실행하는 데 사용되는 복제 모델을 정의함
    • replicated(default) : 복제 모델을 정의함. 이를 통해 동일한 코드를 실행하는 여러 컨테이너를 가질 수 있음.
      • replicas로 복제할 개수를 설정함
    • global : 단 하나의 모델만 정의함
services:
  frontend:
    image: awesome/webapp
    deploy:
      mode: replicated
      replicas: 6
  • resources : 컨테이너들에 대한 리소스를 관리할 수 있음
    • limits : 여기에 해당하는 만큼 리소스를 제한할 수 있음
    • reservations : 여기에 해당하는 만큼의 리소스 이상을 할당한다는 것을 보장함.
services:
  frontend:
    image: awesome/webapp
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
          pids: 1
        reservations:
          cpus: '0.25'
          memory: 20M
  • resources 관련 컴포턴트들
    • cpus : 컨테이너가 사용할 수 있는 CPU 코어
      • 퍼센트로 표시
    • memory : 컨테이너가 할당할 수 있는 메모리 양
      • byte values 형식을 사용
        • 2b, 1024kb, 2048k, 30m, 1gb
    • pids : pid 제한을 조정
      • 정수로 표시
    • device : 컨테이너가 사용할 수 있는 장치를 구성함
      • capabilities 에는 사용할 기능을 문자열로 입력 ([gpu] 혹은 [tpu], …) → 필수로 입력해야 하는 필드임(이것만 입력하면 모든 gpu 사용함)
      • count 에는 사용할 장치 개수(int) 혹은 all 입력
      • device_ids 에는 호스트의 장치 id를 입력]
        • ex. 호스트에서 nvidia-smi를 출력하고, 장치 ID를 찾은 후 입력할 수 있음
      • driver 에는 문자열로 지정된 값을 넣음
        • ex. ‘nvidia’
  • device 예시
# 1
services:
  test:
    image: nvidia/cuda:10.2-base
    command: nvidia-smi
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
# 2
services:
  test:
    image: tensorflow/tensorflow:latest-gpu
    command: python -c "import tensorflow as tf;tf.test.gpu_device_name()"
    deploy:
      resources:
        reservations:
          devices:
          - driver: nvidia
            device_ids: ['0', '3']
            capabilities: [gpu]
  • restart_policy : 컨테이너가 종료될 때 다시 시작할지 여부와 방법을 작성
    • condition : none, on-failure, any(default)
    • delay : 재시작을 시도들 사이에 대기할 시간(default : 0)
    • max_attempts : 재시작 시도 횟수(int) (defult : 무한)
    • windows : 재시작 성공 여부를 결정하기 전 기다리는 시간
deploy:
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
    window: 120s
  • 그 외
    • roliback_config
    • update_config

command

comman는 Dockerfile에서의 CMD 명령을 재정의(overrides)함.

  • command: bundle exec thin -p 3000
  • command: [ "bundle", "exec", "thin", "-p", "3000" ]

entrypoint

entrypoint는 Dockerfile에서의 ENTRYPOINT 명령을 재정의(override)함.

  • Docker image의 ENTRYPOINT와 CMD는 모두 지움
  • entrypoint: /code/entrypoint.sh

environment

environment는 컨테이너에 설정된 환경변수를 정의함. 작성 형식은 다음과 같이 두 가지가 있음

# 1
environment:
  RACK_ENV: development
  SHOW: "true"
  USER_INPUT:

# 2
environment:
  - RACK_ENV=development
  - SHOW=true
  - USER_INPUT

env_file

env_file은 파일 내용을 기반으로 환경 변수를 추가함(만약 environment와 함께 있다면, environment가 우선순위를 가짐).

  • env_file: .env

ports

ports는 컨테이너 포트를 노출한다.. (network_mode: host와 함께 사용하면 안 됨)

ports:
  - "3000"
  - "3000-3005"
  - "8000:8000"
  - "9090-9091:8080-8081"
  - "49100:22"
  - "127.0.0.1:8001:8001"
  - "127.0.0.1:5000-5010:5000-5010"
  - "6060:6060/udp"

expose

expose는 호스트 머신에 대한 포트는 공개하지 않고, 포트를 노출하고 싶은 경우(ex. links 기능 사용)에 사용한다.

expose:
  - "3000"
  - "8000"

links는 다른 서비스의 컨테이너에 접근할 수 있도록 별명을 설정할 수 있다.

(사용하지 않더라도 한 네트워크 안에 있는 서비스끼리는 해당 서비스 이름으로 통신이 가능함)

web:
  links:
    - db
    - db:database  # [service:alias]를 통해 별칭으로도 접근할 수 있음
    - redis

tty

TTY와 함께 실행되도록 서비스 컨테이너를 구성한다.

service:
  service_name:
    tty: true

logging

컨테이너와 서비스의 로깅에 관한 설정을 한다.

  • drive에는 드라이버 종류를 명시하고, options에서는 옵션을 키-값 쌍으로 설정합니다.
logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"

restart

restart는 컨테이너가 종료될 시 재시작 여부와 방법에 대해 지정한다.

restart: "no"  # 재시작하지 않음
restart: always  # 항상 재시작
restart: on-failure  # exit code가 error를 나타내는 경우만 재시작
restart: unless-stopped  # 서비스가 중지되거나 제거되기 전까지 항상 재시작

working_dir

working_dir은 Dockerfile의 WORKDIR로 지정된 컨테이너의 작업 디렉토리를 재정의(override)한다.

service:
  service_name:
    working_dir: /home/user/workspace

Network

네트워크는 서비스가 서로 통신할 수 있도록 하는 layer이다.

  • 네트워크는 top-level 섹션에서 (이름을 지정하여) 생성되며, Service의 하위 섹션에서 네트워크 이름을 명시함으로써 네트워크에 연결할 수 있다.
# 예를 들어 다음과 같이 fromt-tier와 back-tier를 생성했다면
# service 하위 섹션에 이 이름을 명시하여 연결할 수 있음
services:
  frontend:
    image: awesome/webapp
    networks:
      - front-tier
      - back-tier

networks:
  front-tier:
  back-tier:
  • 기본적으로 Compose에서는 애플리케이션에 대한 default 단일 네트워크를 생성한다. 서비스의 각 컨테이너는 기본 네트워크에 연결되며, 이를 통해 서로 통신할 수 있다.
    • default 네트워크는 애플리케이션이 생성될 때 만들어졌다가, 애플리케이션이 내려갈 때 삭제됨.
    • default 네트워크의 이름은 compose.yaml파일이 있는 디렉토리의 이름을 기반으로 생성됨.
    • ex) .yml파일이 my_app에 있다면, 네트워크 이름은 my_app_default가 됨
  • 각 컨테이너는 호스트명으로 네트워크를 검색할 수 있다.
    • 호스트명으로 접근하면, 적절한 컨테이너 IP 주소를 얻어서 접근하게 됨
    • 이때, 주의해야 할 점은 ports(<host_port>:<container_port>)이다.
      • 만약 같은 네트워크에서 접근한다면 container_port를 사용해야 하며, 호스트에서 접속할 때에는 host_port를 사용해야 한다. host_port를 사용할 경우 스웜 밖에서도 접근이 가능하다.

driver

driver는 새로 생성한 네트워크에서 사용할 드라이버를 지정함

  • 네트워크 driver 종류는 이전에 작성한 을 참고
networks:
  mynet1:  # 네트워크 별칭
    driver: overlay

  mynet2:
    driver: bridge

attachable

만약 attachable이 true라면, 다른 독립 실행된 컨테이너에서도 이 네트워크에 접근할 수 있다. 독립 실행된 컨테이너가 이 네트워크에 연결되면, 네트워크에 연결된 서비스와 통신할 수 있다.

networks:
  mynet1:
    driver: overlay
    attachable: true

internal

internal이 True면, 외부로부터 격리된 네트워크를 생성할 수 있다.

external

external이 True이면, 외부에서 생성된 network를 사용한다는 의미이다. 만약, 해당하는 network가 없다면 오류를 뱉는다.

services:
  frontend:
    image: awesome/webapp
    networks:
      - outside_network  # 외부에 있는 outside_network라는 이름의 네트워크 사용

networks:
  outside_network:
    external: true

Volume

volume은 영구적으로 데이터를 저장하기 위한 layer이다.

  • 네트워크와 마찬가지로 top-level 섹션에서 (이름을 지정하여) 생성되며, Service의 하위 섹션에서 이를 사용할 수 있다.
services:
  backend:
    image: awesome/database
    volumes:
      - db-data:/etc/data

  backup:
    image: backup-service
    volumes:
      - db-data:/var/lib/backup/data

volumes:
  db-data:

external

external이 True이면, 외부에서 생성된 volume를 사용한다는 의미이다. 만약, 해당하는 volume가 없다면 오류를 뱉는다.

services:
  frontend:
    image: awesome/webapp
    networks:
      - outside_volume  # 외부에 있는 outside_network라는 이름의 volume 사용

volumes:
  outside_volume:
    external: true
profile
AI Engineer : Lv 0
post-custom-banner

0개의 댓글