IT·테크/개발

Docker Swarm — 여러 도커 호스트를 하나의 클러스터로 묶기

레루루 2026. 7. 28. 21:55
반응형

이 글은 2022년 10월 기준 기록입니다.

 

지금까지는 호스트 한 대 안에서 컨테이너를 늘리고 앞에 로드 밸런서를 세웠습니다. 이번에는 도커 호스트들 자체를 클러스터로 구성해 관리해 봅니다.

스웜 모드는 매니저와 워커로 이루어진다

도커 스웜 모드는 여러 개의 도커 호스트를 하나의 클러스터로 묶어서 사용하는 모드입니다. 구성원은 두 종류입니다. 스웜(클러스터) 관리자인 manager node와 참여자인 worker node입니다.

 

매니저 노드에서 스웜 모드를 초기화합니다.

$ docker swarm init

참여할 때는 join 명령을 사용합니다.

$ docker swarm join --token 토큰값 매니저IP:포트

토큰과 주소를 따로 찾아 헤맬 필요는 없습니다. 매니저 노드에서 init을 실행하면 join할 수 있는 명령어를 그대로 표시해 줍니다.

묶인 노드는 다음 명령으로 확인합니다.

$ docker node ls

스웜에서 도는 컨테이너는 service라고 부른다

도커 스웜 모드에서 작동하는 컨테이너를 service라고 합니다. 명령은 스웜 매니저 노드에서 사용하며, 클러스터로 구성된 노드에 자동으로 서비스를 분산하여 작동시킵니다. 어느 호스트에 몇 개를 띄울지 직접 배치하지 않아도 되는 것이 스웜을 쓰는 이유입니다.

 

명령의 전체 목록은 docker service 문서에 있습니다.

Compose 파일을 그대로 쓰는 통로가 stack이다

Docker Stack은 도커 스웜 모드에서 Docker Compose를 활용하는 방식입니다. 지금까지 쓰던 docker-compose.yml을 버리지 않고 클러스터로 넘어갈 수 있습니다.

 

자세한 내용은 docker stack 문서를 참고합니다.

스택을 배포하고 replica를 늘려 본다

배포에 사용한 Compose 파일입니다.

version: "3.9"
services:
  postgres-db:
    image: postgres-iochord
    expose: 
      - "5432"
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - ./init_db:/docker-entrypoint-initdb.d
    env_file:
      - .env
  spring-crud:
    image: test-crud-app:latest
    depends_on: 
      - postgres-db
    ports:
      - 8080:8080
    env_file:
      - .env

volumes:
  postgres_data:
    driver: local
    name : ${DB_VOLUME}

스웜을 초기화하고, Compose 내용에 기반해 스택을 배포한 뒤, 서비스의 replica 개수를 지정합니다.

$ docker swarm init
$ docker stack deploy -c docker-compose.yml test # docker compose 내용에 기반한 스택 배포
$ docker service scale test_spring-crud=3 # 서비스 replica 개수 설정

$ docker service ls
ID             NAME               MODE         REPLICAS   IMAGE                     PORTS
v4loyyvcs05w   test_postgres-db   replicated   1/1        postgres-iochord:latest
nltksek4l7eb   test_spring-crud   replicated   3/3        test-crud-app:latest      *:8080->8080/tcp

test_spring-crud3/3으로 올라온 것이 보입니다.

 

요청이 실제로 서로 다른 컨테이너로 들어가는지 확인하려면 응답에 자기 호스트명을 실어 보내면 됩니다.

@RestController
public class TestController {

    @RequestMapping("host")
    public String host() {
        String hostname = null;
        try {
            hostname = InetAddress.getLocalHost().getCanonicalHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

        return hostname;
    }

}

 

 

구조를 보면 호스트의 8080 포트가 Docker/Swarm Manager Node 안의 Docker Stack으로 이어지고, 그 안에서 Spring CRUD App이 세 개, Postgres DB가 한 개 떠 있습니다. 앱 컨테이너들은 postgres-db:5432로 DB에 접근하며, 스택 배포에 쓰이는 docker-compose.ymltest.envdev.env.env로 받아 갑니다.

 

당시 기록된 테스트 결과는 이렇습니다. 컨테이너 목록에서 test_spring-crud의 세 replica는 각각 f6bac538279c, fc565c0ff9d7, f8df445539e6라는 컨테이너 ID를 가지고 있었고, localhost:8080/host를 반복 호출하자 응답 본문이 fc565c0ff9d7, f8df445539e6, f6bac538279c로 번갈아 나왔습니다. 같은 주소로 보낸 요청이 세 컨테이너에 나뉘어 도착했다는 뜻입니다.

override 파일로 환경별 차이만 얹는다

환경마다 Compose 파일을 통째로 복제하는 대신, 공통 부분을 담은 기본 파일 위에 차이만 얹을 수 있습니다. 기본 파일은 이렇습니다.

version: '3.8'
services:
  postgres-db:
    image: postgres-iochord
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - ./init_db:/docker-entrypoint-initdb.d

  spring-crud:
    image: test-crud-app:latest
    depends_on: 
      - postgres-db

volumes:
  postgres_data:
    driver: local

test 환경에서 얹을 내용입니다. 환경 변수 파일과 포트만 지정합니다.

version: '3.8'
services:
  postgres-db:
    env_file:
      - test.env

  spring-crud:
    image: test-crud-app:latest
    depends_on: 
      - postgres-db
    ports:
      - 8080:8080
    env_file:
      - test.env

volumes:
  postgres_data:
    driver: local

dev 환경에서는 다른 DB 정보를 쓰고 포트도 다릅니다.

version: '3.8'
services:
  postgres-db:
    environment:                           # 다른 디비 정보를 활용한다면
      - POSTGRES_USER=spring
      - POSTGRES_PASSWORD=spring
      - POSTGRES_DB=postgres_dev
    env_file:
      - dev.env

  spring-crud:
    image: test-crud-app:latest
    depends_on: 
      - postgres-db
    ports:
      - 8081:8081
    env_file:
      - dev.env

volumes:
  postgres_data:
    driver: local

배포할 때는 -c 옵션을 여러 번 주어 파일을 겹칩니다.

$ docker stack deploy -c docker-compose.yml -c docker-compose.test.yml test
$ docker stack deploy -c docker-compose.yml -c docker-compose.dev.yml dev

호스트가 여러 대가 되면 로드 밸런서가 밖으로 나간다

지금까지는 매니저 노드 한 대 안에서 스택이 돌았습니다. 클러스터를 실제로 여러 호스트로 구성하고 외부 로드 밸런서를 이용하는 경우에는 아래와 같은 구조도 가능합니다.

 

External Load Balancer가 세 호스트의 8080 포트로 요청을 나누고, Host-1의 매니저 노드와 Host-2·Host-3의 워커 노드에 걸쳐 하나의 Docker Stack이 놓입니다. Spring CRUD App의 replica들과 Postgres DB는 그 스택 안에 분산되어 있고, 배포는 여전히 docker-compose.yml.env 조합으로 이루어집니다.

반응형