티스토리 뷰

728x90
반응형

도커 컴포즈



도커 컴포즈를 사용하는 이유

여러 개의 컨테이너가 하나의 애플리케이션으로 동작할 때 이를 테스트하려면 각 컨테이너를 하나씩 생성해야 한다. 매번 run 명령어에 옵션을 설정해 CLI로 컨테이너를 생성하기보다는 여러 개의 컨테이너를 하나의 서비스로 정의해 컨테이너 묶음으로 관리할 수 있다면 좀더 편리하다. 이를 위해 도커 컴포즈는 컨테이너를 이용한 서비스의 개발과 CI를 위해 여러 개의 컨테이너를 하나의 프로젝트로서 다룰 수 있는 작업 환경을 제공한다.



도커 컴포즈 설치

# ubuntu, 루트에서 해야함, 최신버전찾기 : https://github.com/docker/compose
$ curl -L https://github.com/docker/compose/releases/download/(최신버전)/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ docker-compose -v



도커 컴포즈 사용

도커 컴포즈 기본 사용법

컨테이너의 설정이 정의된 YAML 파일을 읽어 도커 엔진을 통해 컨테이너를 생성한다. 따라서 도커 컴포즈를 사용하려면 가장 먼저 YAML 파일을 작성해야 한다.



docker-compose.yml 작성과 활용

# vi docker-compose.yml
version: '3.0'
services:
  web:
    image: alicek106/composetest:web
    ports:
      - "80:80"
    links:
      - mysql:db
    command: apachectl -DFOREGROUND
  mysql:
    image: alicek106/composetest:mysql
    command: mysqld

현재 디렉터리의 docker-compose.yml 파일을 읽어 로컬의 도커 엔진에게 컨테이너 생성을 요청한다. 프로젝트의 이름을 명시하지 않으면 컨테이너들은 현재 디렉터리의 이름으로 시작하는 이름을 갖게 된다.

$ docker-compose up -d

docker ps말고 docker-compose ps로도 확인 가능하다.



도커 컴포즈의 프로젝트, 서비스, 컨테이너

도커 컴포즈는 컨테이너를 프로젝트 및 서비스 단위로 구분하므로 컨테이너의 이름은 일반적으로 다음과 같은 형식으로 정해진다.

[프로젝트 이름][서비스 이름][서비스 내에서 컨테이너 번호]

docker-compose scale 명령어로 컨테이너를 생성할 수 있다.

$ docker-compose scale mysql=2

docker-compose up 명령어의 끝에 서비스의 이름을 입력해 docker-compose.yml 파일에 명시된 특정 서비스의 컨테이너만 생성할 수 있다.

$ docker-compose up -d mysql

docker-compose run도 가능하다. 이때는 shell 사용 가능.

$ docker-compose run web /bin/bash

생성된 프로젝트들은 docker-compose down 명령어로 삭제 가능. 서비스 정지되고 삭제된다.

$ docker-compose down

도커 컴포즈는 기본적으로 현재 디렉터리의 이름으로 된 프로젝트를 제어한다. /home/ubuntu에 docker-compose.yml이 있으면 ubuntu라는 이름을 가진 프로젝트를 삭제한다. 근데 -p 옵션에 프로젝트의 이름을 사용해 제어할 프로젝트의 이름을 명시할 수 있다. 즉, -p 옵션을 사용하면 하나의 docker-compose.yml 파일로 서로 이름이 다른 여러 개의 프로젝트를 생성하고 제어할 수 있다.

$ docker-compose -p myproject up -d
$ docker-compose -p myproject ps
$ docker-compose -p myproject down



도커 컴포즈 활용

YAML 파일 작성

기존에 사용하던 run 명령어를 YAML 파일로 변환하는 것이 도커 컴포즈 사용법의 대부분이다.

YAML 파일은 크게 버전 정의, 서비스 정의, 볼륨 정의, 네트워크 정의의 4가지 항목으로 구성된다. 이 가운데 많이 사용하는 것은 서비스 정의이다. 각 항목의 하위 항목을 정의하려면 2개의 공백으로 들여쓰기해서 상위 항목과 구분한다.

-f 옵션으로 파일 지정이 가능하다.

$ docker-compose \
-f /home/uaena/my_compose_file.yml \
up -d

version

버전은 맨위에 정의하고 최신걸 쓰는것이 좋다.

services

도커 컴포즈로 생성할 컨테이너 옵션을 정의한다. 이 항목이 컨테이너로 구현된다. 서비스의 이름은 services의 하위 항목으로 정의하고, 서비스 이름의 하위 항목에 컨테이너 옵션을 정의한다.

services 즉, 서비스 이름의 하위 항목

  • images
  • links
services: 
  web:
    image: alicek106/composetest:web
    links:
      - db
      - db:database
      - redis
      ...
      ...
  • environment : docker run 명령어의 -e 옵션. 서비스의 컨테이너 내부에서 사용할 환경변수를 지정.
services:
  web:
    environment:
      - MYSQL_ROOT_PASSWORD=mypassword
    environment:
      - MYSQL_ROOT_PASSWORD: mypassword
  • command : 컨테이너가 실행될 때 수행할 명령어( /bin/bash )
  • depends_on : 특정 컨테이너에 대한 의존 관계를 나타내며, 이 항목에 명시된 컨테이너가 먼저 생성되고 실행된다. links도 depends_on과 같이 컨테이너의 생성 순서와 실행 순서를 정의하지만 depends_on은 서비스 이름으로만 접근할 수 있다는 점이 다르다.
services:
  web:
    image: alicek106/composetest:web
    depends_on: 
      - mysql
      ...
      ...

links, depends_on 모두 실행 순서만 설정할 뿐 컨테이너 내부의 애플리케이션이 준비된 상태인지에 대해서는 확인하지 않는다. 예를 들어, 데이터베이스 컨테이너와 웹 서버 컨테이너가 정해진 순서대로 실행됐더라도 데이터베이스가 초기화 중이라면 웹 서버 컨테이너가 정상적으로 동작하지 않을 수도 있다. 이를 해결하는 방법으로 컨테이너에 셸 스크립트를 entrypoint로 지정하는 방법이 있다.

services:
  web:
    ...
    entrypoint: ./sync_script.sh mysql:3306

until 구문의 조건 안에 다른 컨테이너의 애플리케이션이 준비됐는지 확인하는 명령어를 입력한다.

# vi sync_script.sh
until (상태를 확인할 수 있는 명령어); do
  echo "depend container is not available yet"
  sleep 1
done
echo "depends_on container is ready"
  • ports : docker run 에서 -p 옵션. 단일 호스트 환경에서 80:80과 같이 호스트의 특정 포트를 서비스의 컨테이너에 연결하면 docker-compose scale 명령어로 서비스의 컨테이너의 수를 늘릴 수 없다.
services: 
  web:
    image: ali~~
      ports:
        - "8080"
        - "8081-8085"
        - "80:80"
        .....
  • build : build 항목에 정의된 도커파일에서 이미지를 빌드해 서비스의 컨테이너를 생성하도록 설정한다. 다음 예제는 ./composetest 디렉터리에 저장된 도커파일로 이미지를 빌드해 컨테이너를 생성한다.
services:
  web: 
    build: ./composetest
    image: alicek106/composetest:web

build 항목에서 도커파일에 사용될 컨텍스트나 도커파일의 이름, 도커파일에서 사용될 인자 값을 설정할 수 있다.

services: 
  web: 
    build: ./composetest
    context: ./composettest
    dockerfile: myDockerfile
    args: 
      HOST_NAME: web
      HOST_CONFIG: self_config 

build 항목을 YAML 파일에 정의해 프로젝트를 생성하고 난 뒤 도커파일을 변경하고 다시 프로젝트를 생성해도 이미지를 새로 빌드하지 않는다. docker-compose up -d에 --build 옵션을 추가하거나 docker-composer build 명령어를 사용해 컨테이너를 생성할 때마다 빌드하도록 설정할 수 있다.

$ docker-compose up -d --build
$ docker-compose build [yml 파일에서 빌드할 서비스 이름]
  • extends : 다른 YAML 파일이나 현재 YAML 파일에서 서비스 속성을 상속받게 설정한다. 다음과 같이 2개의 YAML 파일이 있다고 가정해보자. docker-composer.yml의 web 서비스는 extend_compose.yml의 extend_web 서비스의 옵션을 그대로 갖게 된다.
# docker-compose.yml
version: '3.0'
  services: 
    web: 
      extends: 
        file: extend_compose.yml
        service: extend_web
# extend-compose.yml
version: '3.0'
  services: 
    extend_web: 
      image: ubuntu:14.04
      ports:
        - "80:80"

extends는 version 3.0에서 안될수도 있어서 그럴때는 version 2.x를 써야한다.

networks

  • driver : 도커 컴포즈는 생성된 컨테이너를 위해 기본적으로 브리지 타입의 네트워크를 생성한다. 그러나 YAML 파일에서 dirver 항목을 정의해 서비스의 컨테이너가 브리지 네트워크가 아닌 다른 네트워크를 사용하도록 설정할 수 있다. 드라이버에 필요한 옵션은 하위 항목인 dirver_ops로 전달한다.

다음 예제는 docker-compose up -d 명령어로 컨테이너를 생성할 때 mynetwork라는 overlay 타입의 네트워크도 함께 생성하고, myservice 서비스의 네트워크가 mynetwork 네트워크를 사용하도록 설정한다.

version: '3.0'
services:
  myservice:
    image: nginx
    networks:
      - mynetwork
networks:
  mynetwork:
    driver: overlay
    driver_opts:
      subnet: "255.255.255.0"
      IPAdress: "10.0.0.2"
  • ipam(IP Address Manager) : subnet, ip 범위 등을 설정한다.
services:
  ...


networks:
  ipam:
    driver: mydriver
    config: 
      subnet: 172.20.0.0/16
      ip_range: 172.20.5.0/24
      gateway: 172.20.5.1
  • external : YAML 파일을 통해 프로젝트를 생성할 때마다 네트워크를 생성하는 것이 아닌, 기존의 네트워크를 사용하도록 설정한다. 이를 설정하려면 사용하려는 외부 네트워크의 이름을 하위 항목으로 입력한 뒤 external의 값을 true로 설정한다.

다음 예제는 서비스의 컨테이너가 기존의 uaena라는 이름의 네트워크를 사용하도록 설정한다.

services: 
  web:
    image: ~
    networks:
      - uaena
networks:
  uaena:
    external: true 

volumes

  • driver : 볼륨을 생성할 때 사용될 드라이버를 설정한다. 추가 옵션은 하위 항목인 driver_opts를 통해 인자로 설정한다.

  • external : 도커 컴포즈는 YAML 파일에서 volume, volumes-from 옵션 등을 사용하면 프로젝트마다 볼륨을 생성한다. 이때 external 옵션을 설정하면 볼륨을 프로젝트를 생성할 때마다 매번 생성하지 않고 기존 볼륨을 사용하도록 설정한다.

다음 예제는 myvolum이라는 이름의 외부 볼륨을 web 서비스의 컨테이너에 마운트한다.

services:
  web:
    image: ~
    volumes: 
      - myvolume:/var/www/html
volumes:
  myvolume:
    external: true

YAML 파일 검증

$ docker-compose -f (hml파일경로) config



도커 컴포즈 네트워크

YAML 파일에 네트워크 항목을 정의하지 않으면 도커 컴포즈는 프로젝트별로 브리지 타입의 네트워크를 생성한다. docker-compose up 명령어로 생성되고 docker-compose down 명령어로 삭제된다. docker-compose scale 명령어로 생성되는 컨테이너 전부가 이 브리지 타입의 네트워크를 사용한다. 서비스 내의 컨테이너는 --net-alias가 서비스의 이름을 갖도록 자동으로 설정되므로 이 네트워크에 속한 컨테이너는 서비스의 이름으로 서비스 내의 컨테이너에 접근할 수 있다.

image

예를 들어, web 서비스와 mysql 서비스가 각기 존재할 때 web 서비스의 컨테이너가 mysql이라는 호스트 이름으로 접근하면 mysql 서비스의 컨테이너 중 하나의 IP로 변환되며, 컨테이너가 여러 개 존재할 경우 라운드 로빈으로 연결을 분산한다.

따라서 docker-compose scale 명령어로 컨테이너의 수를 늘려도 해당 서비스의 이름으로 서비스의 모든 컨테이너에 접근할 수 있다. 서비스 이름으로 컨테이너에 접근하는 방식은 스웜 모드의 서비스와 유사하지만 작동 원리는 다르다.



도커 학습을 마치며: 도커와 컨테이너 생태계

2016년 도커 사는 컨테이너 기술이 특정 벤더 또는 회사에 의존적으로 개발되지 않도록 중립적인 입장에서 컨테이너 표준을 정의하는 OCI(Open Container Initiative)를 발표했다. OCI에서는 컨테이너를 구성하기 위해 공통적으로 구현돼야 하는 런타임 및 이미지 스펙의 표준을 정의하고 있다. OCI가 발표된 이후 Moby라는 큰 프로젝트 안에서 도커 컨테이너 기술을 관리하기 시작했고, 도커는 runC, containerd, 그리고 도커 엔진으로 분리됐다.

image

도커의 핵심 프로세스라고 하면 보통 도커 데몬을 떠올리기 쉽지만 사실 도커 데몬은 컨테이너가 아니다. 실제로 컨테이너 프로세스라고 부를 수 있을 만한 것은 dockerd가 아닌 runC 이며, 컨테이너에 1:1로 매칭되는 런타임 역할을 runC가 담당한다. 그리고 여러 개의 runC 컨테이너 프로세스 및 이미지를 관리하는 주체가 바로 containerd이다. 우리가 알고 있는 도커 엔진(dockerd 프로세스)은 containerd와 통신해 runC를 사용할 수 있도록 하는 엔드 유저용 도구에 불과하다.

컨테이너를 생성하고 사용하기 위해 도커가 반드시 필요한 것은 아니며, runC와 containerd는 도커 엔진 없이도 독립적으로 사용할 수 있다. 따라서 우리가 흔히 도커 컨테이너라고 부르는 것은 정확히 말하자면 도커가 아니라는 점에 유의해야 한다.

참고 : 도커 컨테이너 까보기





출처
시작하세요! 도커/쿠버네티스(용찬호 저, 위키북스)
example

728x90
반응형
댓글
반응형
250x250
글 보관함
최근에 달린 댓글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Total
Today
Yesterday
링크