여러 개의 컨테이너로 구성된 시스템을 실행시키는 상황을 생각해보자. 여러 인자와 옵션을 고려해야 하고, 볼륨과 네트워크 설정을 진행해야 하며, 컨테이너와 이미지 목록을 출력해 일일이 삭제해야 하는 수고스러움이 있을 것이다. 이와 같은 상황에서 도커 컴포즈 사용을 고려해볼 수 있다.
도커 컴포즈는 시스템 구축과 관련한 명령어를 하나의 텍스트 파일에 정의함으로써, 명령어 한번으로 시스템 전체를 실행/종료/폐기 할 수 있도록 도와주는 도구이다.
도커 컴포즈는 시스템 구축에 필요한 설정이 정의된 YAML 파일을 이용하여, 시스템을 일괄적으로 실행, 종료, 삭제한다. 사용되는 명령은 도커 명령어와 비슷하지만, 도커 명령어와는 다르다. 도커 컴포즈의 명령은 대표적으로 up 커맨드와 down 커맨드로 구분된다. 다른 커맨드도 있지만, 컨테이너를 종료하는 stop 커맨드 외에는 잘 사용되지 않는다.
① up 커맨드
② down 커맨드
③ stop 커맨드
도커 컴포즈는 텍스트 파일에 정의된 내용을 따라 실행된다는 점에서 이전 포스팅에서 배운 Dockerfile 스크립트와 비슷하다. 하지만, 도커 컴포즈와 Dockerfile 스크립트는 명백히 다른 것이다. 도커 컴포즈는 docker run 커맨드를 여러 개 모아놓은 것과 같은 것으로, 컨테이너 뿐 아니라 네트워크나 볼륨까지 만들어낼 수 있다. 반면, Dockerfile 스크립트는 이미지를 만들기 위한 것이므로, 네트워크나 볼륨을 만들어 낼 수는 없다.
※ 도커 컴포즈와 쿠버네티스
아직 쿠버네티스에 대해 배우지는 않았지만, 도커에 대해 어느 정도 아는 사람이라면 쿠버네티스가 무엇인지 대강 알고 있을 것이다. 쿠버네티스도 여러 개의 컨테이너를 다루기 위해 사용된다는 점에서 도커 컴포즈와 비슷하다고 생각할 수 있는데, 사실 이들의 역할은 명확하게 다르다.
쿠버네티스는 컨테이너 관리를 도와주는 도구인데 반해, 도커 컴포즈는 컨테이너의 생성 및 삭제 정도만 도와주는 도구로써, 컨테이너를 관리하는 기능은 수행하지 않는다.
원칙적으로는 도커 컴포즈는 도커 엔진과 별개의 소프트웨어이므로, 도커 엔진을 설치했다 하더라도 도커 컴포즈를 설치해야 한다. 그러나, 윈도우나 macOS에서 사용하는 도커 데스크톱에는 도커 컴포즈가 함께 포함되어 있기 때문에, 실제로 설치할 필요는 없다. 하지만, 리눅스에서 도커를 사용하는 경우에는 도커 컴포즈를 별도로 설치해주어야 한다. 실제 서버를 운영해야 할 때에는 리눅스 OS를 사용해야 하기 때문에, 설치 명령을 알아두는 게 좋다.
리눅스에서 도커 컴포즈를 다운로드 받으려면, 도커 컴포즈와 python3 런타임, python3-pip가 필요하다. 이는 도커 컴포즈가 파이썬으로 작성된 프로그램이기 때문이다. 설치하는 명령은 아래와 같다.
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose -version // 설치가 잘 되었는지 확인
도커 컴포즈는 설치와 함께 바로 실행이 가능하므로, 별도의 실행 명령은 존재하지 않는다.
Dockerfile 스크립트를 생성할 때와 비슷하게, 호스트 컴퓨터의 폴더에 YAML 파일을 배치한다. 이 때, 파일의 이름은 반드시 docker-compose.yml이어야 한다. docker-compose.yml의 명령을 실행하려면, 누군가 도커 엔진에 해당 명령을 전달해야 하는데, 이 역할을 도커 컴포즈가 수행한다.
만약 위와 같은 상황에서 도커 컴포즈를 사용하지 않는다면, 각각의 컨테이너에 대해 필요한 명령을 직접 입력했어야 할 것이다. 그러나, 도커 컴포즈를 사용하여 필요한 명령을 미리 정의해두면, 많은 컨테이너에 대해 반복적인 명령을 보다 간편하게 수행할 수 있게 된다.
이 때, 정의 파일은 반드시 한 폴더에 하나만 존재해야 한다. 만약, 여러 개의 정의 파일을 두어야 한다면, 필요한 정의 파일의 수만큼 개별 폴더로 관리하면 된다. 당연히 모든 폴더에서 파일명은 docker-compose.yml로 동일해야 한다.
도커 컴포즈는 실행할 정의 파일을 필요로 하기 때문에, 정의 파일 작성법을 알고 있어야 한다. 파일 작성법에 대해 알아보기에 앞서 먼저는, 아래의 예시를 통해 정의 파일의 구조를 살펴보기로 하자. 아래의 예시는 아파치 컨테이너를 생성하는 간단한 정의 파일을 나타낸 것이다. 참고로, yml 파일은 계층 구조로 구성되며, 일반적으로 두 칸의 공백을 이용해 계층을 구분한다. (계층 구분을 위해 tab을 사용하지 않도록 한다.)
version: "3"
services:
apa000ex1:
image:httpd
ports:
- 8080:80
restart: always
정의 파일로 나타내니 다소 복잡하고 낯설게 느껴지지만, 위 내용을 docker run 커맨드로 변경해보면 매우 익숙하게 느껴질 것이다. 아래는 위 정의 파일과 동일한 컨테이너를 생성하는 docker run 커맨드이다.
docker run --name apa000ex1 -d -p 8080:80 httpd
이번에는 조금 더 복잡한 예시를 살펴보기로 하자.
version: "3"
services:
wordpress000ex1:
depends_on:
- mysql000ex1
image: wordpress
networks:
- wordpress000net1
ports:
- 8080:80
restart: always
environment:
WORDPRESS_DB_HOST=mysql000ex1
WORDPRESS_DB_NAME=wordpress000db
WORDPRESS_DB_USER=wordpress000chrome
WORDPRESS_DB_PASSWORD=pwd
이와 동일한 docker run 커맨드는 아래와 같다.
docker run --name wordpress000ex1 -dit --net=wordpress000net1 -p 8080:80 -e WORDPRESS_DB_HOST=mysql000ex1 -e WORDPRESS_DB_NAME=wordpress000db -e WORDPRESS_DB_USER=wordpress000chrome -e WORDPRESS_DB_PASSWORD=pwd wordpress
정의 파일도 메모장으로 작성하면 된다. 정의 파일을 작성할 때에는 가장 먼저 정의 파일의 버전을 기입한 후, 상위 계층에서 하위 계층 순으로 작성하는 것이 좋다. 계층 구조는 대략 메인 항목 > 이름 > 설정 순으로 구성된다.
① 메인 항목
version: "3"
services:
# 컨테이너 관련 정보
networks:
# 네트워크 관련 정보
volumes:
# 볼륨 관련 정보
② 이름
version: "3"
services:
wordpress000ex1:
# 생략
networks:
wordpress000net1:
# 생략
volumes:
wordpress000vol1:
# 생략
③ 설정
version: "3"
services:
wordpress000ex1:
image: wordpress
networks:
- wordpress000net1
# 이하 생략
이제 실제로 정의 파일을 작성하는 실습을 해보기로 하자. 워드프레스 및 MySQL 컨테이너를 생성하는 정의 파일을 작성해보기로 한다. 다만, 이전 실습에서와는 달리 이번 실습에서는 5.7 버전의 MySQL을 사용할 것이며, 볼륨에 대한 정보도 추가할 것이다.
정의 파일을 작성하기 위해 필요한 정보는 아래와 같다.
① 폴더 생성하기
② docker-compose.yml 파일 생성
③ 메인 항목 작성
version: "3"
services:
networks:
volumes:
④ 이름 작성
version: "3"
services:
mysql000ex11:
wordpress000ex12:
networks:
wordpress000net1:
volumes:
mysql000vol11:
wordpress000vol12
⑤ 설정 작성
version: "3"
services:
mysql000ex11:
image: mysql:5.7
networks:
- wordpress000net1
volumes:
- mysql000vol11:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpwd
MYSQL_DATABASE: wordpress000db
MYSQL_USER: wordpress000chrome
MYSQL_PASSWORD: pwd
wordpress000ex12:
depends_on:
- mysql000ex11
image: wordpress
networks:
- wordpress000net1
volumes:
- wordpress000vol12:/var/www/html
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: mysql000ex11
WORDPRESS_DB_NAME: wordpress000db
WORDPRESS_DB_USER: wordpress000chrome
WORDPRESS_DB_PASSWORD: pwd
networks:
wordpress000net1:
volumes:
mysql000vol11:
wordpress000vol12:
파일을 저장하면, 정의 파일 작성이 모두 완료된다.
도커 엔진에서는 docker 명령을 사용하지만, 도커 컴포즈에서는 docker-compose 명령을 사용한다. up, down, stop 커맨드를 이용해 도커 컴포즈를 실행시켜보자.
① docker-compose up 커맨드
docker-compose -f /compose_folder/docker-compose.yml up -d
② 웹 브라우저를 통해 워드프레스에 접근
③ docker-compose down 커맨드
docker-compose -f /compose_folder/docker-compose.yml down
// 또는 docker-compose -f /compose_folder/docker-compose.yml down -v --rmi all
도커 컴포즈에는 한 가지 흥미로운 특징이 있다. 도커 컴포즈를 실행한 후 docker ps나 docker volume ls를 입력해보면, 컨테이너와 볼륨의 이름이 우리가 지정한 이름과 조금 달라진 것을 확인할 수 있다.
우리가 지정한 이름의 앞에는 폴더의 이름이 붙고(-f 옵션을 생략한 경우에는 폴더의 이름은 붙지 않는다), 뒤에는 번호가 붙는 형식이다. 이름이 변경되었긴 하지만, 정의 파일에 기재된 컨테이너나 볼륨의 이름은 그대로 사용할 수 있기 때문에, 정의 파일을 수정할 필요는 없다. 다만, 도커 엔진으로 컨테이너를 다뤄야 할 때에는 변경된 이름을 사용해야 한다. 즉, 도커 컴포즈는 자신은 예전 이름을 그대로 사용하면서, 도커 엔진에게는 변경된 이름을 사용할 것을 강요한다.