본문으로 건너뛰기

시스템 시작 및 종료

개요​

PlantPulse 는 Docker Compose 스택으로 동작합니다. 시작 / 종료 / 재시작은 /opt/kopens/plantpulse-platform-docker/bin/ 의 공통 동사 한 곳에서 관리하며, 컨테이너 간 의존성 순서는 compose 의 depends_on 이 자동으로 적용하므로 운영자가 일일이 순서를 신경 쓸 필요는 없습니다.

종료 코드 0 의 뜻이 다릅니다

up.sh 와 restart.sh 의 0 은 «명령이 성공했다» 가 아니라 «이제 쓸 수 있다» 입니다. 2026-08-14 자격증명 회전 때 «시작됨» 만 보고 다음 단계로 넘어갔다가 아직 뜨지 않은 브로커에서 멈춘 사고가 있어, 두 동사가 준비될 때까지 기다리도록 바뀌었습니다.

status.sh 는 다릅니다 — 0 = 정상 / 2 = 비정상 입니다.

권장 운영 명령 (요약)​

cd /opt/kopens/plantpulse-platform-docker/bin

./up.sh # 기동 (멱등) — 준비될 때까지 대기. 0 = 준비 완료
./down.sh # 안전 종료 (의존 순서의 역순, 상태 보존)
./restart.sh # graceful drain → 정지 → 기동 → 준비 대기
./status.sh # 서비스 / health / 볼륨 요약. 0 = 정상 / 2 = 비정상
./ops-check.sh # 헬스 + 최근 critical log
./logs.sh [서비스] # 로그 보기 — 1회 출력, -f 로 따라가기 (인자 없으면 전체)
./stack-verify-boot.sh # 스택 전체 준비 판정
./doctor.sh # 진단 tarball (시스템 변경 없음)

모든 동사가 --help 를 지원합니다. 옛 이름(stack-run.sh · stack-stop.sh · stack-bash.sh · stack-update.sh · stack-remove.sh)도 그대로 동작합니다.

환경 변수기본값뜻
PP_READY_TIMEOUT900준비 대기 상한(초)
PP_READY_INTERVAL15확인 간격(초)
PP_WAIT=0—대기하지 않음. 이때의 0 은 준비 완료를 뜻하지 않습니다

시작 순서 (자동)​

컨테이너 사이​

compose 의 depends_on 이 service_healthy 조건으로 순서를 지킵니다 — «프로세스가 떴다»가 아니라 «쓸 수 있다»를 기다립니다. 이 순서는 임의가 아니라 애플리케이션 오케스트레이터의 기동 순서를 그대로 옮긴 것입니다.

마지막 넷(warehouse · opcua · aasx · ha)은 서로 순서가 없습니다.

데이터레이크 컨테이너 안​

인프라 컴포넌트는 plantpulse-datalake 한 컨테이너 안에서 다시 순서대로 기동합니다.

순서영역주요 컴포넌트대표 포트
1스토리지Aster TSDB, PostgreSQL, Valkey, RustFS9042 / 5432 / 6379 / 9000
2분석Spark, Hive, Kyuubi, Gravitino7077 / 9083 / 10000 / 19001
3시계열TSE Engine, UI7800 / 3000
4메시징Kafka, MQTT9092 / 1883
5워크플로우Temporal, Kestra7233 / 8233 / 8380
6처리CEP, Data Gateway, SQL, Monitor7400 / 5500 / 4000 / 4950
소요 시간

프로세스 기동 자체는 35분(JVM 워밍업)이지만, 클린 설치는 Aster TSDB 스키마 마이그레이션과 안정화 때문에 **전 컴포넌트가 안정되기까지 1518분**이 걸립니다.

실측(2026-08-31, 32 vCPU / 128GiB): 데이터레이크 217초, 웹 서버 316초. 데이터가 이미 있는 재시작은 훨씬 빠릅니다.

종료 순서​

cd /opt/kopens/plantpulse-platform-docker/bin
./down.sh

순서를 손으로 지킬 필요가 없습니다. compose 가 의존 순서의 역순으로 정지하므로, 데이터를 쓰는 쪽(앱)이 먼저 멈추고 데이터레이크가 마지막에 멈춥니다. 각 컨테이너에는 넉넉한 정지 유예(stop_grace_period)가 걸려 있어 — 데이터레이크는 180초 — Aster TSDB 가 Memtable 을 플러시할 시간을 확보합니다.

볼륨(pp-data · pp-temp · pp-backup · pp-security · pp-proxy-certs)은 정지·제거와 무관하게 항상 보존됩니다.

docker kill 이나 호스트 강제 종료를 쓰지 마세요

Aster TSDB 의 플러시되지 않은 Memtable 데이터가 유실될 수 있습니다. 반드시 ./down.sh 를 사용해 주세요. 이미 컨테이너가 응답하지 않는다면 비상 절차를 따르세요.

재시작​

전체 재시작​

cd /opt/kopens/plantpulse-platform-docker/bin
./restart.sh
  1. (돌고 있다면) 데이터레이크에 graceful drain 요청
  2. 스택 전체를 의존 순서의 역순으로 정지
  3. depends_on 순서로 다시 기동
  4. 준비될 때까지 대기 — 종료 코드 0 이면 쓸 수 있는 상태

bin/env.sh 변경, 로케일·타임존 변경, 일시적 문제 해소, 정기 재시작에 사용합니다.

앱 하나만 재시작​

앱 여섯은 각자 컨테이너에서 돌기 때문에, 그 컨테이너만 다시 띄우면 나머지 앱과 인프라는 그대로 살아 있습니다. 이것이 컨테이너를 나눈 이유 중 하나입니다.

cd /opt/kopens/plantpulse-platform-docker
docker compose -f compose/docker-compose.yml restart plantpulse-server-web
docker compose restart 는 의존 순서를 지키지 않습니다

여러 앱을 함께 되살려야 한다면 ./restart.sh 로 스택 전체를 재시작하는 편이 안전합니다.

인프라 컴포넌트만 재시작​

./shell.sh # 데이터레이크 진입
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd restart storage
exit

pd restart <서비스> 가 받는 이름은 services/order.txt 에 있는 여덟뿐입니다 — storage · analytics · messaging · timeseries · cep · workflow · data-gateway · admin-api. 그 밖의 이름은 unknown service 로 끝납니다. 자세한 내용은 시작 가이드를 참고해 주세요.

상태 확인​

한 줄 요약​

./status.sh # 0 = 정상 / 2 = 비정상

status.sh 가 비정상으로 보는 것은 다섯 가지입니다.

판정내용
서비스 목록을 못 읽음compose 해석 실패 또는 docker 접근 불가
compose 가 선언한 서비스에 컨테이너가 없음기동되지 않음
컨테이너가 running 이 아님아홉 개 전부 상시 동작합니다 — 제외 대상이 없습니다
상시 컨테이너의 health 가 unhealthystarting / none 은 판정 보류
헬스 API 가 OK 가 아님데이터레이크 안에서 probe

볼륨과 conf 는 보고만 하고 종료 코드에 넣지 않습니다 — 설치 구성에 따라 일부가 없는 것이 정상이기 때문입니다.

아홉 개를 같은 기준으로 봅니다

plantpulse-certs 는 인증서를 한 번 굽고 계속 떠 있으면서 만료를 감시합니다. 아홉 개를 같은 기준(healthy)으로 보면 됩니다.

헬스체크는 이미지가 갖고 있습니다. compose 에 probe 블록이 없는 것은 의도한 것이고 pp.healthcheck: image 라벨이 그것을 명시합니다. 프로브 경로가 다른 저장소의 것이라 compose 에 적어 두면 그쪽이 파일을 옮기는 순간 고객사에서 깨집니다.

컨테이너 확인​

docker ps # 아홉 개가 모두 (healthy)
docker stats --no-stream # 컨테이너별 CPU / 메모리

헬스체크 API​

# 호스트 / 외부에서 — 4950 이 publish 되어 있습니다
curl -kfsS https://<서버IP>:4950/api/health | jq

# 컨테이너 안에서 — 어떤 구성에서도 동작합니다
docker exec plantpulse-datalake curl -kfsS https://127.0.0.1:4950/api/health | jq

"status" 값은 OK · WARN · FAIL 셋뿐이며, OK/WARN 이 정상 범위입니다.

4949 로도 같은 API 가 나옵니다

콘솔과 헬스 API 는 두 포트 모두에서 서비스됩니다 — 4950(HTTPS)와 4949(평문 HTTP). 같은 콘솔·같은 API 이고 스킴만 다릅니다. 4949 는 더 이상 4950 으로 리다이렉트하지 않습니다.

4949 는 평문입니다 — 로그인 비밀번호와 세션 쿠키가 그대로 흐릅니다. 신뢰할 수 없는 망에서는 4950 을 쓰세요. 4949 는 자체 서명 인증서 경고가 실제로 운영자를 막아 세우는 상자를 위한 선택지입니다.

로그 확인​

./logs.sh # 여덟 컨테이너를 시간순으로 한 화면에
./logs.sh plantpulse-server-web -n 200 # 특정 컨테이너
./logs.sh cassandra # 데이터레이크 안 컴포넌트 로그 파일
./logs.sh --list # 볼 수 있는 대상 전체
./logs.sh -f plantpulse-proxy # 계속 따라가기 (Ctrl-C 로 종료)

기본은 마지막 N줄(기본 200)을 찍고 끝입니다. 따라가려면 -f 를 붙이세요.

자동 시작 설정​

별도 설정이 필요하지 않습니다. 컨테이너는 compose 에 재시작 정책이 선언되어 있어 호스트를 재부팅해도 Docker 데몬이 뜨면 함께 올라옵니다. plantpulse-certs 는 restart: unless-stopped 입니다 — 사람이 일부러 멈춘 경우에는 데몬을 재시작해도 멈춘 채로 둡니다. 재시작해도 인증서를 새로 굽지 않습니다.

확인할 것은 Docker 데몬의 자동 시작 하나뿐입니다.

systemctl is-enabled docker # enabled 여야 합니다
sudo systemctl enable docker # 아니라면
재부팅 직후 프록시가 잠시 빨갛게 보일 수 있습니다

호스트 재부팅은 depends_on 순서가 적용되지 않는 유일한 경로입니다 — 전부 한꺼번에 올라오기 때문에, 웹 서버가 뜰 때까지(실측 최대 316초) 프록시의 헬스체크가 잠시 실패할 수 있습니다. 재시도 예산이 360초로 잡혀 있고 docker 는 unhealthy 를 이유로 컨테이너를 재시작하지 않으므로, 스스로 회복되는 일시적 상태입니다.

비상 절차​

웹 콘솔이 응답하지 않음​

cd /opt/kopens/plantpulse-platform-docker/bin

# 1. 어느 컨테이너가 문제인가
./status.sh

# 2. 프록시와 웹 서버 로그
./logs.sh plantpulse-proxy -n 100
./logs.sh plantpulse-server-web -n 200

# 3. 웹 서버만 재시작 (인프라는 유지)
cd /opt/kopens/plantpulse-platform-docker
docker compose -f compose/docker-compose.yml restart plantpulse-server-web

# 4. 회복되지 않으면 진단 번들
bin/doctor.sh
프록시가 초록인데 화면이 502 라면

프록시의 헬스체크는 자기 자신 + 업스트림 도달까지만 봅니다(백엔드의 건강 상태는 웹 서버 자신의 헬스체크가 판정합니다). 프록시가 초록인데 화면이 안 나온다면 plantpulse-server-web 쪽을 보세요.

OOM (Out Of Memory) 발생​

# 1. 어느 컨테이너가 OOM 인가
docker inspect plantpulse-server-web --format '{{.State.OOMKilled}} {{.State.ExitCode}} {{.RestartCount}}'

# 2. 호스트 커널 로그
dmesg | grep -i "out of memory\|oom"

# 3. 컨테이너별 사용량
docker stats --no-stream

컨테이너마다 한계값이 따로 있습니다 — 데이터레이크는 DOCKER_DATALAKE_MEMORY(기본 96G), 앱은 DOCKER_SERVER_MEMORY · DOCKER_BATCH_MEMORY 등입니다(환경 변수). 값을 조정한 뒤 ./restart.sh 로 적용합니다.

한 앱의 OOM 이 전체를 내리지 않습니다

앱마다 mem_limit 을 따로 두는 것이 컨테이너 분리의 첫 번째 목적입니다. 한 앱이 한계에 닿아도 인프라와 다른 앱은 살아 있습니다.

DB 연결 실패​

데이터베이스는 모두 plantpulse-datalake 안에 있습니다.

cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh # 데이터레이크 진입

/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node psql # PostgreSQL
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node cql # Cassandra
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node status # Cassandra 링 상태

인프라만 되살리려면 컨테이너 안에서 pd restart storage 를, 그래도 안 되면 호스트에서 ./restart.sh 를 사용합니다.

데이터 손상 의심 시​

cd /opt/kopens/plantpulse-platform-docker/bin

./down.sh # 즉시 정지 (추가 손상 방지)
ls -lh /data1/pp-backup/docker-volume/ # 최신 백업 확인
./doctor.sh # 진단 번들 (데이터를 임의로 수정하지 마세요)

생성된 tarball 을 webmaster@kopens.com 으로 전달해 주세요.

운영 체크리스트​

일일 점검​

점검 항목명령어 / 확인 방법정상 기준
전체 서비스 상태./status.sh종료 코드 0
운영 헬스./ops-check.shcritical 로그 없음
헬스 APIcurl -kfsS https://<서버IP>:4950/api/healthstatus 가 OK 또는 WARN
컨테이너docker ps아홉 개 모두 (healthy)
디스크 사용량df -h /data1사용률 80% 미만
컨테이너 자원docker stats --no-stream한계값 대비 여유 있음
Aster TSDB 상태컨테이너 안에서 pd node status모든 노드 UN (Up/Normal)

주간 점검​

점검 항목명령어 / 확인 방법정상 기준
Aster TSDB Compaction컨테이너 안에서 pd node compactionstatsPending 작업 과다 아님
Aster TSDB 테이블컨테이너 안에서 pd node table-stats비정상 증가 없음
Kafka 토픽 / lag컨테이너 안에서 pd node topic지연 메시지 수 정상 범위
백업 확인ls -lh /data1/pp-backup/docker-volume/정상 백업 존재
Docker 사용량docker system df미사용 이미지 누적 없음
로그 용량du -sh /opt/kopens/plantpulse-platform-docker/logs비정상적 증가 없음
보안 업데이트OS 패키지 업데이트 확인알려진 취약점 없음