실제로 프로젝트에 Docker를 적용하다보면, 하나의 컨테이너만을 사용하는 경우는 극히 드물다는 걸 알 수 있다. 하나의 프로젝트는 여러 개의 하위 시스템과 여러 서비스를 갖고 있고, 각 서비스별로 컨테이너가 필요할 때는 매우 많다. 예를 들어 nginx 기반의 웹 서비스가 있다면, DB는 별도의 프로세스에서 동작하며 웹 서비스로부터 요청을 받아들여 질의 결과를 반환하게 된다. 이 때 nginx와 DBMS(이를테면 mysql)는 별개의 컨테이너에서 구동되어야 할 것이다.
docker-compose는 YAML 파일 형태로 여러 서비스를 관리한다. 한 번 YAML로 파일을 작성해두면 이 파일로 도커 빌드/실행/종료를 모두 수행할 수 있다. 또한 일일이 명령어를 작성해서 컨테이너를 실행하는 것에 비해 휴먼 에러를 크게 줄일 수 있다는 것 또한 장점이다.
Docker Desktop을 설치해도 docker-compose를 사용하는 것이 가능하지만, docker-compose가 기업용으로는 유료화되며 사용상에 제약이 생겼다. 하지만 Linux를 사용할 경우 docker engine과 docker CLI가 설치되어 있는 환경에 docker-compose 플러그인만 따로 설치하는 것이 가능하다.
주의 사항
Linux 이외의 운영체제에서는 지원하지 않는 방법이다. MacOS 환경에서는 Docker Desktop 사용을 권장한다. Windows 환경에서는 마찬가지로 Docker Desktop을 사용하거나, WSL(Windows Subsystem for Linux)를 이용하면 된다.
apt/yum 을 이용하여 설치해도 되지만, docker-compose의 최신/특정 버전을 설치하고자 하는 경우 manual installation 방법을 사용하는 게 좋다.
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
리눅스 환경의 특정 사용자가 아닌 전체 사용자가 docker-compose를 사용할 수 있게 하고자 하는 경우 ~/.docker/cli-plugins 대신 /usr/local/lib/docker/cli-plugins 로 설치 경로를 변경한다.
curl 로 가져온 실행 파일이 정상적으로 executable 권한을 갖고 있는지 확인한다. 만약 실행 권한이 없는 경우 추가해준다.
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
설치가 완료되면 docker compose 명령어로 정상적으로 실행되는지 확인해본다.
docker compose version
docker compose로 서비스를 배포하려면 yaml 파일이 작성되어야 한다. docker-compose.yml 파일은 다음과 같이 작성한다.
version: "3.9"
services:
db:
image: "mariadb:10.9"
volumes:
- "./mysql:/var/lib/mysql"
environment:
MYSQL_USER: myuser
MYSQL_PASSWORD: password123!
docker-compose 작성에 사용 가능한 옵션 값들은 이 곳을 참조한다.
Docker Compose를 사용하면 여러 컨테이너를 동시에 제어하는 것이 가능하다. 하지만 실제 운영환경에서는 이걸로도 충분하지 않은 경우가 많다. 만약 서비스에 대한 수요가 늘어나서 더 많은 자원이 필요하다면? 더 많은 서버 기기가 필요할 것이다.
다행히도, 컨테이너를 통한 배포의 장점 중 하나는 여러 노드에 걸친 수평적 확장이 쉽다는 점이다. 그리고 여러 노드에 걸쳐 배포된 다수의 컨테이너를 제어하기 위한 컨테이너 오케스트레이터를 사용하면 깔끔하게 배포를 관리할 수도 있다. Docker의 기능 중 하나인 swarm mode를 사용하면 여러 서버로 이루어진 클러스터 환경에서 다수의 컨테이너를 동시에 실행해 관리하는 것이 가능하다.
Docker Swarm 클러스터는 서비스의 상태를 확인하고 스케줄링을 지원하는 manager 노드와, 실제 daemon을 통해 container 를 띄우고 실행하는 worker node들로 구성되어 있다. swarm 클러스터를 구성하고 서비스 시작을 요청하면 manager node는 가용한 worker node를 찾아 컨테이너 생성 요청을 내린다. 실제 서비스는 worker 노드에서 실행되며, swarm manager에 의해 제어된다.
swarm 모드를 사용하여 클러스터를 구성하려면 간단한 명령어 몇 줄로 시작 가능하다.
docker swarm init --advertise-addr <MANAGER-IP>
클러스터에 추가할 worker node에서는 다음과 같이 join 명령을 입력한다. token은 swarm init 시 출력되는 값을 그대로 사용한다.
docker swarm join \
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
<MANAGER-IP>:2377
이후 docker node ls
명령으로 모든 노드가 정상적으로 join 되고 ready 상태가 되었는지 확인해본다. 모든 노드가 준비가 되었다면 docker service create
명령어 혹은 아래에서 설명할 compose yaml 파일을 사용해 서비스를 시작할 수 있다.
docker swarm 모드에서도 명령줄 입력 대신 yaml 파일 형태로 서비스를 배포할 수 있다. 이 때 사용하는 서비스 정의 파일은 docker compose file 을 사용해 필요한 전체 서비스를 docker stack deploy
로 배포할 수 있다.
docker stack deploy --compose-file compose.yml stackname
Docker swarm은 클러스터 구성도 쉽고, docker-compose와 (일부) 호환이 되어 compose 파일로 전체 서비스 stack을 쉽게 배포할 수 있다. 그러나 막상 swarm을 사용해보면 여러 기능 상의 한계가 매우 뚜렷해서 아쉬운 점이 많았다. 다음은 내가 swarm을 사용하며 느낀 불편한 한계점들이다.
swarm mode에서는 docker compose file v3을 쓰기는 하지만, compose V1과 호환되는 레거시 버전을 쓰고 있다. 따라서 docker-compose에 새로운 기능이 나왔더라도 swarm mode에 반영되어 있지 않을 확률이 매우 높다.
GPU 서버 클러스터를 구축해서 사용하다보니, NVIDIA GPU 드라이버 혹은 Infiniband 드라이버 등, device 옵션값을 필요로 하는 경우가 매우 많았다. 그러나 devices 옵션은 swarm mode에서는 지원하지 않는 기능이었다. 실제로 이 기능을 추가해달라는 요청은 github에 무려 2016년에 올라왔으나 아직 Open 상태이다. 스레드의 글 중 I'm getting strong "the perfect is the enemy of the good" vibes from this issue. (완벽함은 좋은 것의 적이다. 즉, 완벽함에 대한 집착이 종종 개선의 여지를 완전히 차단할 수 있다는 뜻이다.) 라는 문구에 매우 공감할 수 밖에 없었다.
이 외에도 cgroup_parent, container_name, depends_on 등, docker-compose를 통해서는 사용할 수 있었던 여러가지 다양한 기능들 중 swarm 모드에서 지원하지 않는 것들은 매우 많다. 여러 디바이스에 안정적으로 배포되기 위해서 모든 기능을 다 제공할 수 없었을 것이라는 생각은 들지만, 사용하다 보면 '경고로도 충분하지 않나?'는 의구심을 지울 수가 없었다.
Swarm은 클러스터 구축이 매우 간단하고 러닝커브도 낮은 편이다. 그 말인 즉슨, 정작 운영 단계의 컨테이너 오케스트레이션에 쓰기엔 기능이 빈약하다는 이야기다.
서비스 탐색, 자가 복구, 유연한 배포, Role-Based Access Control 등, 서비스 운영에는 많은 부가 기능이 필요하다. Kubernetes의 경우 이런 기능을 갖추었을 뿐 아니라 수많은 빅테크 기업에서 실제로 산업현장에 적용하고 있는 만큼 많은 검증이 되었고, CSP 회사들도 완전관리형 솔루션을 출시하여 활발하게 쓰이고 있는 상태이다. 또한 Open Source 커뮤니티의 규모도 Kubernetes 쪽이 훨씬 크다.
결론적으로, 소규모 조직에서 오케스트레이션을 처음 시도하는 단계에서는 Docker Swarm을 사용하고 시스템의 규모가 커지고 복잡해지면 kubernetes로 전환을 시도하는 것이 가장 효과적인 접근법이라고 생각된다.