[Docker] E03.docker-compose
2021-04-11 # Docker

Docker Compose



이글은 위키북스의 시작하세요! 도커/쿠버네티스를 참고하여 쓴 글입니다.


Why docker-compse?


도커는 일반적으로 마이크로서비스를 지향하기 때문에 한개의 컨테이너에 한개의 서비스를 제공해야 합니다. 하지만, 이를 테스트하려면 각 컨테이너를 하나씩 생성해야 합니다. 예를 들어, 웹 애플리케이션을 테스트하려면 웹 서버, 데이터베이스 컨테이너를 생성해야합니다.


하지만, 각 컨테이너가 제대로 동작하는지 확인하는 테스트 단계에서는 번거로운 작업입니다. 따라서, 매번 run 명령어에 옵션을 설정해 CLI로 컨테이너를 생성하기보다는 여러 개의 컨테이너를 하나의 서비스로 `COMPOSE`하여 관리할 수 있다면 좋을 것입니다.

도커 컴포즈는 여러 개의 컨테이너의 옵션과 환경을 정의한 파일을 읽어 컨테이너를 순차적으로 생성하는 방식으로 동작합니다.


컨테이너의 수가 많아지고 정의해야할 옵션이 많아진다면 도커 컴포즈를 사용하는 것이 좋습니다.


Install docker-compse


리눅스에서는 다음 명령어로 도커 컴포즈를 설치할 수 있으며, 도커 컴포즈의 깃허브 저장소에서 직접 내려받아 설치할 수 있습니다.


1
2
3
4
5
root@DESKTOP-03N08DE:/home/csj7480# curl -L https://github.com/docker/compose/releases/download/1.11.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 633 0 633 0 0 2082 0 --:--:-- --:--:-- --:--:-- 2082
100 8052k 100 8052k 0 0 6022k 0 0:00:01 0:00:01 --:--:-- 14.8M

윈도우에서는 Docker for Windows를 설치하면 같이 설치됩니다.


Use docker-compose


Basic Usage of docker-compose


도커 컴포즈는 컨테이너의 설정이 정의된 YAML 파일을 읽어 도커 엔진을 통해 컨테이너를 생성합니다. 따라서, 가장 먼저 작성해야할 것은 YAML파일 입니다.

YAML(Yet Another Markup Language)이란?

  • XML, JSON과 같은 파일포맷형식으로 사람이 읽을 수 있는 데이터 직렬화 언어입니다. 밑의 예시에서도 살펴볼 수 있듯이 기존의 XML, JSON보다 읽기 쉬운 형식입니다.

출처 : SpesDevTech.log

우선, 다음과 같은 run 명령어를 docker-compose.yml 파일로 변환해 컨테이너를 생성하고 실행해보겠습니다.


  • 데이터베이스 컨테이너
1
2
3
csj7480@DESKTOP-03N08DE:~$ docker run -d --name mysql \
> alicek106/composetest:mysql \
> mysqld

- 웹 서버 컨테이너
1
2
3
4
csj7480@DESKTOP-03N08DE:~$ docker run -d -p 80:80 \
> --link mysql:db --name web \
> alicek106/composetest:web \
> apachectl -DFOREGROUND

- docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
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

이때 중요한 것은 YAML 파일에서 들여쓰기는 tab(4칸)이 아닌 **2개의 공백(space)**로 구분해야 합니다.


도커 컴포즈는 현재 디렉터리의 docker-compose.yml 파일을 읽어 로컬의 도커 엔진에게 컨테이너 생성을 요청합니다.
`docker-compose up -d`명령어로 컨테이너를 생성해보겠습니다.

docker-compose.yml 파일에 대한 설명은 다음과 같습니다.


1. `version` : YAML 파일 포맷의 버전을 의미합니다. 버전은 `1`,`2`,`2.1`,`3.0` 등이 있습니다. `도커 컴포즈 1.8`은 `버전 2`를 `도커 컴포즈 1.9`는 `버전 2.1`을, `도커 컴포즈 1.10`은 `버전 3.0`을 사용합니다. 2. `services`: 생성될 컨테이너를 묶어놓은 단위입니다. 3. `web`, `mysql` : 생성될 서비스의 이름입니다. `docker run`에서 사용하는 옵션과 동일하게 `image`, `ports`, `links`, `command` 등을 정의할 수 있습니다.
`docker ps`명령어로 확인하면 다음과 같습니다.

docker container

Docker desktop

도커 컴포즈는 컨테이너를 프로젝트 및 서비스 단위로 구분하므로 컨테이너의 이름은 일반적으로 다음과 같은 형식으로 정해집니다.
`[프로젝트 이름]_[서비스 이름]_[서비스 내에서 컨테이너의 번호]`
위 예제에서 생성한 프로젝트의 이름은 csj7480,서비스 이름은 mywql, web입니다. 프로젝트의 이름을 별도로 입력하지는 않았지만 `docker-compose.yml` 파일이 위치한 디렉터리의 이름을 프로젝트 이름으로 사용합니다. 프로젝트의 이름은 디렉터리의 이름에 따라 다를 것입니다.

하지만, -p옵션을 통해 프로젝트의 이름을 지정할 수도 있습니다. 또한, 기본적으로 현재 디렉토리의 docker-compose.yml파일을 사용하지만 -f옵션을 통해 파일의 위치도 지정할 수 있습니다.


또한, docker-compose scale명령어로 csj7480_mysql_2를 생성할 수 있습니다.


1
docker-compose scale mysql=2


단, docker-compose up -d mysql과 같이 docker-compose.yml파일에 명시된 특정 서비스의 컨테이너만 생성할 수 있습니다.


또한, 생성된 프로젝트는 docker-compose down명령어로 삭제할 수도 있습니다. 프로젝트를 삭제하면 서비스의 컨테이너 또한 전부 정지된 뒤 삭제됩니다.




Application of docker-compose


도커 컴포즈를 실제 개발환경에서 사용하려면 더 많은 옵션과 명령어가 필요합니다. 이번 챕터에서는 이에 대해서 알아보겠습니다.


YAML 파일 작성


YAML 파일은 크게 버전, **서비스**, 볼륨, 네트워크 정의의 4가지 항목으로 구성됩니다. 이 중 **서비스** 정의를 가장 많이 사용하며, 볼륨과 네트워크 정의는 서비스로 생성된 컨테이너에 선택적으로 사용됩니다.


  1. version 정의

도커 컴포즈 버전 1.10에서 사용할 수 있는 버전 3를 기준으로 합니다. 버전 항목은 일반적으로 YAML파일의 맨 윗부분에 명시합니다.

1
version: '3.0'



  1. services 정의

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


1
2
3
4
5
services:
my_container_1:
image: -
my_container_2:
image: -

서비스 항목이 가질 수 있는 주요 컨테이너 옵션만 설명하겠습니다.
  • image: 이미지의 이름을 설정합니다. 이미지 이름 포맷은 docker run과 같습니다.

1
2
3
services:
my_container_1:
image: csj7480/composetest:mysql

  • links: docker run --link와 같으며, 다른 서비스에 서비스명만으로 접근할 수 있도록 설정합니다. [SERVICE:ALIAS]형식으로 별칭을 지정할 수 있습니다.

1
2
3
4
5
6
7
services:
web:
image: csj7480/composetest:web
links:
- db
- db:database
- redis

  • environment: docker run --env, -e 와 같습니다. 딕셔너리나 배열 형태로 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
web:
image: csj7480/composetest:web
links:
- db
- db:database
- redis
environment:
- MYSQL_ROOT_PASSWORD=0000
- MYSQL_DATABASE_NAME=mydb
또는
MYSQL_ROOT_PASSWORD:0000
MYSQL_DATABASE_NAME:mydb

  • command: 컨테이너가 실행될 때 수행할 명령어를 설정하며, docker run의 마지막에 붙는 커맨드와 같습니다. Dockerfile의 RUN과 같은 배열 형태로도 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
web:
image: csj7480/composetest:web
links:
- db
- db:database
- redis
environment:
- MYSQL_ROOT_PASSWORD=0000
- MYSQL_DATABASE_NAME=mydb
command: apachectl -DFOREGROUND
또는
command: [apachectl, -DFOREGROUND]

  • depends_on : 특정 컨테이너에 대한 의존 관계를 나타내며, 이 항목에 명시된 컨테이너가 먼저 생성되고 실행됩니다. 다음 예제에서는 web 컨테이너보다 mysql 컨테이너가 먼저 생성됩니다. links와 달리 depends_on은 서비스 이름으로만 접근할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
services:
web:
image: csj7480/composetest:web
links:
- db
- db:database
- redis
environment:
- MYSQL_ROOT_PASSWORD=0000
- MYSQL_DATABASE_NAME=mydb
command: apachectl -DFOREGROUND
depends_on
- mysql
mysql:
image: csj7480/composetest:mysql

이 때 주의해야할 점은 실행 순서만 정의할 뿐 컨테이너 내부의 애플리케이션이 준비된 상태인지에 대해서는 확인하지 않습니다. 따라서, 컨테이너에 셸 스크립트를 entrypoint로 지정하는 방법이 있습니다.

1
2
3
4
services:
web:
...
entrypoint: ./sync_scripts.sh mysql:3306

entrypoint에 지정된 sync_scripts.sh은 다음과 같습니다.

1
2
3
4
5
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명령어로 서비스의 컨테이너의 수를 늘릴 수 없습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
web:
image: csj7480/composetest:web
ports:
- "8080"
- "8081-8085"
- ...
links:
- db
- db:database
- redis
environment:
- MYSQL_ROOT_PASSWORD=0000
- MYSQL_DATABASE_NAME=mydb
command: apachectl -DFOREGROUND
depends_on
- mysql

mysql:
image: csj7480/composetest:mysql

  • build: build 항목에 정의된 도커파일에서 이미지를 빌드해 서비스의 컨테이너를 생성하도록 설정합니다. 또한 도커파일에 사용될 컨텍스트나 도커파일의 이름, 도커파일에서 사용될 인자 값을 설정할 수 있습니다.

1
2
3
4
5
6
7
8
9
services:
web:
build: ./composetest
context: ./composetest
dockerfile : myDockerFile
args:
HOST_NAME:web
HOST_CONFIG: self_config
image: csj7480/composetest:web

  • extends: 현재 혹은 다른 YAML파일에서 서비스 속성을 상속받게 설정합니다. 다음과 같은 예시를 들어보겠습니다.

1
2
3
4
5
6
version:'3.0'
services:
web:
extends:
file: extend_compose.yml
service: extend_web
docker-compose.yml

1
2
3
4
5
6
version:'3.0'
services:
extend_web:
image: ubuntu:14.04
ports:
- "80:80"
extend-compose.yml

1
2
3
4
5
6
7
8
9
version:'3.0'
services:
web:
extends:
service: extend-web
extend_web:
image: ubuntu:14.04
ports:
- "80:80"
상속받은 결과물

단, depends_on, links,volumes_from과 같은 항목들은 컨테이너 사이의 의존성을 내포하므로 extends로 상속받을 수 없습니다.




  1. network 정의

  • driver: 기본적으로 브리지타입의 네트워크를 생성하는데 다른 네트워크를 사용할 수 있도록 설정할 수 있습니다. 드라이버에 필요한 옵션은 하위 항목인 driver_ops로 전달합니다.

  • ipam: IPAM(IP Address Manager)를 위해 사용할 수 있는 옵션으로 subnet, ip 범위 등을 설정할 수 있습니다. 이 때 driver항목에는 IPAM을 지원하는 드라이버의 이름을 입력합니다.

  • external: YAML파일을 통해 프로젝트를 생성할 때마다 네트워크를 생성하는 것이 아니라 기존의 네트워크를 사용하도록 설정합니다. 사용하려는 외부 네트워크의 이름을 하위 항목으로 입력한 뒤 external의 값을 true로 설정합니다. 이 때, external은 다른 네트워크의 옵션을 사용하므로 driver,driver_ops,ipams 옵션과 함께 사용할 수 없습니다.



  1. volume 정의

  • driver: 볼륨을 생성할 때 사용될 드라이버를 설정합니다. default값으로는 local로 설정되며 사용하는 드라이버에 따라 변경해야 합니다. 추가 옵션은 하위 항목인 driver_opts를 통해 인자를 넘겨줍니다.

1
2
3
4
5
6
7
8
9
version:'3.0'
services:
...

volumes:
driver: flocker
driver_opts:
opt: "1"
opt2: 2

  • external: volume,volumes-from 옵션 등을 사용하면 프로젝트마다 볼륨을 생성합니다. 이 때 external옵션을 설정하면 볼륨을 프로젝트를 생성할 때마다 매번 생성하지 않고 기존 볼륨을 사용하도록 설정합니다.

1
2
3
4
5
6
7
8
9
version:'3.0'
services:
web:
image: csj7480/composetest:web
volumes:
- myvolume:/var/www/html
volumes:
myvolume:
external: true

위와 같은 예제는 `myvolume`이라는 이름의 외부 볼륨을 web 서비스의 컨테이너에 마운트합니다.



Reference


시작하세요! 도커/쿠버네티스: 친절한 설명으로 쉽게 이해하는 컨테이너 관리 - 용찬호