본문으로 건너뛰기

클러스터 설치

대규모 워크로드를 위해 PlantPulse 를 마스터 + 워커 노드 클러스터 로 구성하는 방법입니다. 단일 노드로 시작했다가 처리량이 한계에 도달했을 때 점진적으로 확장할 수 있습니다.

다중 노드는 «수평 확장» 하나뿐입니다​

인프라(Aster TSDB·Kafka·Spark)를 여러 노드로 나누는 마스터 / 워커 클러스터가 이 문서의 내용입니다. 처리량이 한계에 이르렀을 때 씁니다.

계층을 나누는 설치(데이터레이크와 애플리케이션을 다른 박스에)는 2026-09-02 에 없어졌습니다. 모든 박스가 전체 설치입니다.

언제 클러스터로 확장하나요?​

환경 규모권장 구성비고
태그 ~5,000단일 마스터클러스터 불필요
태그 5,000 ~ 50,000마스터 + 1~2 워커분석 / 메시징 분산
태그 50,000+마스터 + 3+ 워커본격 분산 운영

클러스터 토폴로지​

하드웨어 요구사항​

각 워커 노드 사양 권장(마스터 노드는 시스템 요구사항을 따릅니다 — 데이터레이크 마스터 96 GB 이상):

구분최소표준대규모
CPU16 vCPU32 vCPU48 vCPU
메모리67 GB 이상 (워커 컨테이너 60 GB 가 호스트 RAM 의 90% 안에 들어야 함 — 64 GB 는 사양 미달)128 GB200+ GB
데이터 디스크200 GB NVMe1 TB NVMe4 TB NVMe
네트워크1 Gbps10 Gbps10 Gbps

노드 간 네트워크: 클러스터 노드들 간에는 10 Gbps 이상 권장. Aster TSDB repair, Kafka replication, Spark shuffle 트래픽이 큽니다.

사전 요건​

마스터 노드와 모든 워커 노드에서 다음이 완료되어야 합니다.

  • 시스템 요구사항 충족
  • 호스트명 / 고정 IP / DNS 설정
  • 시간 동기화 (chronyd) — 노드 간 시간차가 100ms 이하여야 합니다
  • OS 튜닝 (limits / sysctl / swap off)
  • 노드 간 사설망 통신 가능 (RFC 1918 또는 Tailscale)
  • 클러스터 내부 포트 허용 (Aster TSDB 7000/7001/9042, Kafka 9092/9093, Spark 7077/8081 등)

/etc/hosts 설정 (모든 노드 동일)​

# /etc/hosts — 마스터 / 워커 모든 노드에 동일하게
192.168.0.41 plantpulse-master plantpulse-master.local
192.168.0.101 plantpulse-worker-1 plantpulse-worker-1.local
192.168.0.102 plantpulse-worker-2 plantpulse-worker-2.local
192.168.0.103 plantpulse-worker-3 plantpulse-worker-3.local

Docker 클러스터 (권장 경로)​

Docker/원라인 설치 환경에서는 워커를 compose 오버레이로 띄웁니다. 마스터 노드에 기본 스택이 떠 있는 상태에서 bin/worker-add.sh 가 워커를 하나씩 추가합니다. 시크릿·인증서는 아래 절차대로 사이드카 파일로 노드 간 복사하므로 값을 손으로 옮겨 적을 필요가 없습니다.

워커 목록의 정본 — compose/workers.roster​

어떤 워커가 존재하는가의 정본은 compose/workers.roster 파일 하나입니다. 한 줄에 <id> <ip> 형식이며, 단일 노드 설치라면 비어 있는 것이 정상입니다.

# compose/workers.roster
1 10.99.0.101
항목뜻
idPP_WORKER_ID. 컨테이너 이름(plantpulse-worker-<id>)과 볼륨 이름(pw-<id>-*)의 접미사
ippp-net(10.99.0.0/24) 위의 고정 주소. .1 은 게이트웨이, .100 은 데이터레이크이므로 .101 부터 사용합니다

compose/docker-compose.worker.yml 은 이 파일에서 생성되고(bin/gen-worker-compose.sh), bin/env.sh 도 같은 파일에서 워커 IP 와 노드 목록을 유도합니다. 그래서 compose·운영 스크립트·시크릿 회전 가드가 서로 다른 워커 집합을 보는 일이 생기지 않습니다.

생성 파일을 손으로 고치지 마세요

docker-compose.worker.yml 은 생성물입니다. 손으로 고치면 CI 의 gen-worker-compose.sh --check 가 실패합니다. 워커를 늘리고 줄이는 것은 roster 에 줄을 넣고 빼는 것이 아니라 아래의 worker-add.sh / worker-decommission.sh + worker-remove.sh 로 합니다 — 워커는 Aster TSDB 토큰 레인지와 PostgreSQL 복제 슬롯을 들고 있어서 목록만 고쳐서는 만들어지지도 없어지지도 않습니다.

워커 관련 환경 변수 (bin/env.sh)​

변수기본값설명
DOCKER_PW_NAMEplantpulse-worker워커 컨테이너 이름 접두어 (plantpulse-worker-1 …)
DOCKER_PW_MEMORY60G, 호스트가 작으면 RAM 의 90% (마스터의 DOCKER_DATALAKE_MEMORY 와 따로 잡습니다)워커 컨테이너 메모리 상한
DOCKER_PW_IP_<n> · PP_WORKER_NODESroster 에서 유도손으로 적지 않습니다
워커 메모리를 임의로 낮추지 마세요

워커는 데이터레이크 마스터와 같은 이미지를 쓰므로(2026-08-31 통합) 그 이미지에 구워진 JVM 크기도 그대로 따릅니다 — Aster TSDB 하나가 -Xms16G/-Xmx16G 를 요구합니다. 호스트 크기에 비례해 잡는 방식은 틀렸습니다. 필요한 양은 호스트가 아니라 서비스 구성이 정합니다.

2026-08-31 실측: 옛 12g 기본값의 워커가 Aster TSDB 가 링에 닿기 전에 OOMKilled 되었고, 컨테이너는 OOMKilled=true 로 죽었는데 조인은 일어나지 않은 채 health: starting 을 유지했습니다.

워커 추가​

cd /opt/kopens/plantpulse-platform-docker

bin/worker-add.sh # 빈 id·빈 주소 자동 선택
bin/worker-add.sh 3 # id 지정
bin/worker-add.sh 3 10.99.0.103 # id·주소 지정

worker-add.sh 가 순서대로 수행합니다.

  1. roster 에 등록 (이미 있는 id 는 «추가» 가 아니므로 거부합니다)
  2. 오버레이 compose 재생성
  3. 볼륨 생성 → 이미지 pull → up -d
  4. 링 합류 확인 — 마스터의 nodetool 로 직접 검증
「컨테이너가 떴다」는 조인의 증거가 아닙니다

워커는 Aster TSDB 토큰 레인지, Spark 워커 등록, PostgreSQL 복제 슬롯, Redis 복제 링크를 함께 들고 있습니다. 컨테이너 자체의 준비 검사는 «마스터에 닿는가»만 보기 때문에, 조인에 실패한 워커도 성공한 워커와 똑같이 정상으로 보고합니다.

2026-08-31 실측: Aster TSDB 가 OOMKilled 된 워커가 링은 1노드인 채로 health: starting 을 유지했습니다. 그래서 worker-add.sh 는 링 자체를 물어봅니다.

워커 운영​

cd /opt/kopens/plantpulse-platform-docker

# 진입 (워커는 기본 스택의 서비스가 아니라 shell.sh 로는 잡히지 않습니다)
docker exec -ti plantpulse-worker-3 /bin/bash

# 정지 — compose 동사 그대로
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 stop plantpulse-worker-3

# 이미지 갱신 (이미 도는 워커. 추가 시점의 pull 은 worker-add.sh 안에 들어 있습니다)
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 pull plantpulse-worker-3
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 up -d plantpulse-worker-3

워커 제거 — 반드시 이 순서​

bin/worker-decommission.sh 3 # 데이터 이관 + 링 이탈 확인 + 복제 슬롯 정리
bin/worker-remove.sh # 그 다음에 컨테이너 제거
살아 있는 워커에 docker rm 은 제거가 아니라 「유기」 입니다

Aster TSDB 는 그 노드의 토큰 레인지와 host id 를 DN 으로 붙들고 있습니다. RF=3 이면 QUORUM 이 그대로 성립하므로 아무 경보도 뜨지 않습니다. 그리고 마스터는 그 워커의 PostgreSQL 물리 복제 슬롯을 계속 들고 있어 디스크가 찰 때까지 WAL 을 고정합니다.

worker-remove.sh 는 컨테이너가 돌고 있으면 거부하고 worker-decommission.sh 를 먼저 부르라고 안내합니다.

삭제된 워커 스크립트 (2026-08-31)

worker-run.sh · worker-stop.sh · worker-update.sh · worker-bash.sh 네 개는 삭제되었습니다. 손으로 관리하던 워커 서비스 목록을 전제로 만들어진 것들이라, roster 생성 방식으로 바꾸면서 이름만 바꾼 게 아니라 없앴습니다. 대체는 각각 worker-add.sh(pull 포함) · compose 동사 · compose pull + up -d · docker exec 입니다.

시크릿 사이드카 복사 (손 복사 금지)​

마스터에서 생성된 서비스 시크릿은 /etc/kopens/plantpulse-platform.env 사이드카 파일에 있습니다. 이 파일을 워커 노드로 복사하면 워커가 동일한 자격증명으로 조인합니다 — 비밀번호를 하나씩 옮겨 적지 마세요(2노드 분리 문서의 조인 번들과 동일 패턴).

# 마스터 노드에서 각 워커로
scp /etc/kopens/plantpulse-platform.env root@<worker-ip>:/etc/kopens/

공유 CA 복사 → 자동 seed​

노드 간 TLS 신뢰는 공유 클러스터 CA 로 성립합니다. 마스터의 /etc/kopens/ca/ 를 워커로 복사하면 컨테이너 기동 시 pp-security 볼륨에 자동 seed 되어 인증서를 손수 배치할 필요가 없습니다.

# 마스터 노드에서 각 워커로 (컨테이너 경로 기준 자동 seed)
scp -r /etc/kopens/ca root@<worker-ip>:/etc/kopens/

platform.node.env 는 노드별 정체성 파일이므로 복사하지 마세요. 복사 대상은 위 두 항목(plantpulse-platform.env, ca/)뿐입니다.

클러스터 검증 (Docker 환경)​

# Cassandra 링 — 모든 노드가 UN (Up Normal) 이어야 합니다
docker exec plantpulse-datalake \
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node status

# Spark — 워커가 ALIVE 인지
# 브라우저에서 http://<마스터IP>:4440/ 의 Workers 탭

자주 발생하는 문제​

증상원인확인
워커가 링에 붙지 않음PP_MASTER_IP 가 이 박스에서 닿지 않는 주소/etc/kopens/platform.node.env 를 고치고 bin/restart-datalake.sh
워커에서 Kafka 클라이언트가 마스터로만 붙음광고 주소가 루프백PP_KAFKA_ADVERTISED_HOST 를 그 박스의 실제 주소로
사이드카 값이 워커에 없음비밀 파일을 손으로 복사위 「시크릿 사이드카 복사」 절차를 쓰세요 — 손 복사는 권한과 줄바꿈이 어긋납니다
nodetool status 에 워커가 DN방화벽에 7000 계열이 막힘포트 구성

클러스터 제거​

# 각 워커에서 — 컨테이너를 제거하고 데이터 볼륨은 남긴다
ssh root@<WORKER_IP> 'cd /opt/kopens/plantpulse-platform-docker && bin/remove.sh'

# 마스터에서
cd /opt/kopens/plantpulse-platform-docker && bin/remove.sh
remove.sh 와 down.sh 는 다릅니다
동사컨테이너볼륨
bin/down.sh멈추기만 — up.sh 로 그대로 되살아납니다그대로
bin/remove.sh제거그대로(기본값)

볼륨까지 지우려면 bin/tools/remove-all-volumes.sh 를 따로 씁니다. 이미지·네트워크까지 지우려면 RM_IMAGE=1 · RM_NETWORK=1 을 붙입니다.

bin/stop.sh 라는 이름은 없습니다 — 컴포즈 전환 때 공통 동사가 up · down · remove · restart · status · logs · update 로 정리됐습니다 (시작 가이드).

데이터 디스크는 별도 정책으로 관리합니다(필요하면 백업 후 삭제).

관련 문서​