본문으로 건너뛰기

시스템 시작 및 종료

개요

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

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

up.shrestart.sh0 은 «명령이 성공했다» 가 아니라 «이제 쓸 수 있다» 입니다. 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_onservice_healthy 조건으로 순서를 지킵니다 — «프로세스가 떴다»가 아니라 «쓸 수 있다»를 기다립니다. 이 순서는 임의가 아니라 애플리케이션 오케스트레이터의 기동 순서를 그대로 옮긴 것입니다.

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

데이터레이크 컨테이너 안

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

순서영역주요 컴포넌트대표 포트
1스토리지Cassandra, PostgreSQL, Valkey, MinIO9042 / 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 워밍업)이지만, 클린 설치는 Cassandra 스키마 마이그레이션과 안정화 때문에 **전 컴포넌트가 안정되기까지 1518분**이 걸립니다.

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

종료 순서

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

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

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

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

Cassandra 의 플러시되지 않은 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 storage · pd restart analytics · pd restart messaging · pd restart timeseries · pd restart workflow · pd restart cep · pd restart data-gateway · pd restart sql · restart-monitor.sh 입니다. 자세한 내용은 시작 가이드를 참고해 주세요.

상태 확인

한 줄 요약

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

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

판정내용
서비스 목록을 못 읽음compose 해석 실패 또는 docker 접근 불가
compose 가 선언한 서비스에 컨테이너가 없음기동되지 않음
상시 컨테이너가 running 이 아님원샷(plantpulse-certs)은 제외
상시 컨테이너의 health 가 unhealthystarting / none 은 판정 보류
헬스 API 가 OK 가 아님데이터레이크 안에서 probe

볼륨과 conf 는 보고만 하고 종료 코드에 넣지 않습니다 — 2노드 분리 설치(PP_TIER=APP)에서는 일부가 없는 것이 정상이기 때문입니다.

원샷의 Exited (0) 은 성공입니다

plantpulse-certs 는 인증서를 굽고 스스로 끝납니다. compose 가 이 컨테이너의 헬스체크를 명시적으로 꺼 두었으므로(healthcheck: disable) health 칸은 비어 있습니다 — 원샷에 health probe 를 걸면 «정상 동작하는 컨테이너가 영원히 unhealthy» 로 보이고, 모든 사람이 그 하나만 예외로 기억해야 하기 때문입니다. status.shops-check.sh 는 이 컨테이너만 종료 코드로 판정합니다 — 손으로 볼 때도 그렇게 봐 주세요.

컨테이너 확인

docker ps # 여덟 개가 (healthy), certs 는 Exited (0)
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 에 restart: always 로 선언되어 있어, 호스트를 재부팅해도 Docker 데몬이 뜨면 함께 올라옵니다. 원샷(plantpulse-certs)은 restart: "no" 라서 다시 돌지 않습니다 — 다시 돌면 인증서를 새로 굽기 때문입니다.

확인할 것은 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(기본 80G), 앱은 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/healthstatusOK 또는 WARN
컨테이너docker ps여덟 개 (healthy), certs 는 Exited (0)
디스크 사용량df -h /data1사용률 80% 미만
컨테이너 자원docker stats --no-stream한계값 대비 여유 있음
Cassandra 상태컨테이너 안에서 pd node status모든 노드 UN (Up/Normal)

주간 점검

점검 항목명령어 / 확인 방법정상 기준
Cassandra Compaction컨테이너 안에서 pd node compactionstatsPending 작업 과다 아님
Cassandra 테이블컨테이너 안에서 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 패키지 업데이트 확인알려진 취약점 없음

바이너리(네이티브) 환경

현재 릴리즈는 바이너리(네이티브) 설치를 지원하지 않습니다

아래 내용은 바이너리 설치로 구축된 기존 시스템을 위해 남겨 둔 것입니다. 현행 출하본은 위의 Docker Compose 스택 하나이므로, 컨테이너 환경에서는 아래 절차(systemd 서비스, Windows 서비스, 개별 프로세스 기동)를 사용하지 마세요.

바이너리 환경에서는 운영 스크립트가 /opt/kopens/plantpulse-platform/plantpulse-startup/ 에 있습니다 — start-daemon.sh · stop.sh · restart.sh · status.sh · kill.sh · log-viewer.sh. 자세한 내용은 바이너리 설치를 참고해 주세요.

Linux 시작 (systemd)

systemd 서비스가 등록되어 있는 경우 다음 명령어로 시작할 수 있습니다.

# 1. 스토리지 서비스 시작
sudo systemctl start plantpulse-postgresql
sudo systemctl start plantpulse-redis
sudo systemctl start plantpulse-cassandra

# Cassandra가 완전히 시작될 때까지 대기 (약 30~60초)
until cqlsh 127.0.0.1 -e "DESCRIBE KEYSPACES" > /dev/null 2>&1; do
echo "Cassandra 시작 대기 중..."
sleep 5
done
echo "Cassandra 시작 완료"

# 2. 메시징 서비스 시작
sudo systemctl start plantpulse-kafka
sudo systemctl start plantpulse-mqtt

# 3. 엔진 서비스 시작
sudo systemctl start plantpulse-timeseries
sudo systemctl start plantpulse-cep

# 4. 웹서버 시작
sudo systemctl start plantpulse-server

# 5. 에이전트 시작
sudo systemctl start plantpulse-agent

Linux 수동 시작

systemd를 사용하지 않는 경우 각 모듈의 시작 스크립트를 직접 실행할 수 있습니다.

# 스토리지
/opt/kopens/plantpulse-platform/plantpulse-storage/db/postgres/bin/pg_ctl start -D /opt/kopens/plantpulse-platform/plantpulse-storage/db/postgres/data
/opt/kopens/plantpulse-platform/plantpulse-storage/db/valkey/bin/valkey-server /opt/kopens/plantpulse-platform/plantpulse-storage/db/valkey/conf/valkey.conf &
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/cassandra

# 메시징
/opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/bin/kafka-server-start.sh -daemon /opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/config/server.properties
/opt/kopens/plantpulse-platform/plantpulse-messaging/mqtt/bin/startup.sh

# 엔진
/opt/kopens/plantpulse-platform/plantpulse-timeseries/bin/startup.sh
/opt/kopens/plantpulse-platform/plantpulse-cep/bin/startup.sh

# 웹서버
/opt/kopens/plantpulse-platform/plantpulse-server/bin/startup.sh

# 에이전트
/opt/kopens/plantpulse-platform/plantpulse-plugin/opc-ua/bin/startup.sh

시작 스크립트 (의존성 체크 포함)

아래는 의존성을 확인하면서 순차적으로 시작하는 스크립트 예시입니다.

#!/bin/bash
# plantpulse-start-all.sh - 전체 플랫폼 시작 스크립트

KOPENS_HOME="/opt/kopens"
LOG_FILE="/var/log/plantpulse/startup.log"

log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

wait_for_port() {
local host=$1 port=$2 timeout=${3:-60}
local elapsed=0
while ! nc -z "$host" "$port" 2>/dev/null; do
if [ $elapsed -ge $timeout ]; then
log "ERROR: $host:$port 연결 타임아웃 (${timeout}초)"
return 1
fi
sleep 2
elapsed=$((elapsed + 2))
done
log "OK: $host:$port 연결 확인"
return 0
}

# 1. PostgreSQL
log "PostgreSQL 시작 중..."
sudo systemctl start plantpulse-postgresql
wait_for_port 127.0.0.1 5432 30 || exit 1

# 2. Redis
log "Redis 시작 중..."
sudo systemctl start plantpulse-redis
wait_for_port 127.0.0.1 6379 15 || exit 1

# 3. Cassandra
log "Cassandra 시작 중..."
sudo systemctl start plantpulse-cassandra
wait_for_port 127.0.0.1 9042 120 || exit 1

# 4. Kafka & MQTT
log "Kafka 시작 중..."
sudo systemctl start plantpulse-kafka
wait_for_port 127.0.0.1 9092 30 || exit 1

log "MQTT 시작 중..."
sudo systemctl start plantpulse-mqtt
wait_for_port 127.0.0.1 1883 15 || exit 1

# 5. TSE
log "시계열 엔진 시작 중..."
sudo systemctl start plantpulse-timeseries
wait_for_port 127.0.0.1 7800 30 || exit 1

# 6. CEP
log "CEP 엔진 시작 중..."
sudo systemctl start plantpulse-cep
wait_for_port 127.0.0.1 7400 30 || exit 1

# 7. 웹서버
log "PlantPulse 웹서버 시작 중..."
sudo systemctl start plantpulse-server
wait_for_port 127.0.0.1 80 60 || exit 1

# 8. OPC Agent
log "OPC Agent 시작 중..."
sudo systemctl start plantpulse-agent
wait_for_port 127.0.0.1 60000 30 || exit 1

log "전체 플랫폼 시작 완료"

Windows 시작

Windows 서비스

Windows 환경에서 서비스로 등록된 경우 서비스 관리자(services.msc) 또는 명령 프롬프트에서 시작할 수 있습니다.

# 서비스 시작 (관리자 권한 PowerShell)
Start-Service PlantPulse-PostgreSQL
Start-Service PlantPulse-Redis
Start-Service PlantPulse-Cassandra
Start-Service PlantPulse-Kafka
Start-Service PlantPulse-MQTT
Start-Service PlantPulse-TSE
Start-Service PlantPulse-CEP
Start-Service PlantPulse-Server
Start-Service PlantPulse-Agent

배치 파일 시작

@echo off
REM plantpulse-start-all.bat - 전체 시작 배치 파일

echo [%date% %time%] PostgreSQL 시작 중...
net start PlantPulse-PostgreSQL
timeout /t 10 /nobreak > nul

echo [%date% %time%] Redis 시작 중...
net start PlantPulse-Redis
timeout /t 5 /nobreak > nul

echo [%date% %time%] Cassandra 시작 중...
net start PlantPulse-Cassandra
timeout /t 60 /nobreak > nul

echo [%date% %time%] Kafka 시작 중...
net start PlantPulse-Kafka
timeout /t 10 /nobreak > nul

echo [%date% %time%] MQTT 시작 중...
net start PlantPulse-MQTT
timeout /t 5 /nobreak > nul

echo [%date% %time%] 시계열 엔진 시작 중...
net start PlantPulse-TSE
timeout /t 10 /nobreak > nul

echo [%date% %time%] CEP 시작 중...
net start PlantPulse-CEP
timeout /t 10 /nobreak > nul

echo [%date% %time%] 웹서버 시작 중...
net start PlantPulse-Server
timeout /t 30 /nobreak > nul

echo [%date% %time%] OPC Agent 시작 중...
net start PlantPulse-Agent
timeout /t 10 /nobreak > nul

echo [%date% %time%] 전체 시작 완료
pause

종료 순서

종료는 시작의 역순으로 수행해야 합니다. 데이터를 수집하는 에이전트부터 먼저 종료하고, 마지막으로 데이터베이스를 종료합니다.

순서서비스설명
1OPC Agent데이터 수집 중지
2PlantPulse 웹서버 (Tomcat)웹 서비스 중지
3CEP이벤트 처리 중지
4TSE시계열 엔진 중지
5MQ (Kafka / MQTT)메시지 브로커 중지
6Cassandra시계열 DB 중지
7Redis (Valkey)캐시 중지
8PostgreSQL메타 DB 중지

주의: Cassandra를 다른 서비스보다 먼저 종료하면 아직 플러시되지 않은 Memtable 데이터가 유실될 수 있습니다. 반드시 에이전트와 웹서버를 먼저 종료하여 데이터 쓰기를 중지한 후 Cassandra를 종료해 주세요. Cassandra 종료 전에 nodetool drain 명령으로 Memtable을 강제 플러시하는 것을 권장합니다.

Linux 종료 명령어

# 1. 에이전트 종료
sudo systemctl stop plantpulse-agent

# 2. 웹서버 종료
sudo systemctl stop plantpulse-server

# 3. 엔진 종료
sudo systemctl stop plantpulse-cep
sudo systemctl stop plantpulse-timeseries

# 4. 메시징 종료
sudo systemctl stop plantpulse-mqtt
sudo systemctl stop plantpulse-kafka

# 5. Cassandra 안전 종료 (Memtable 플러시 후 종료)
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/nodetool drain
sudo systemctl stop plantpulse-cassandra

# 6. Redis 종료
sudo systemctl stop plantpulse-redis

# 7. PostgreSQL 종료
sudo systemctl stop plantpulse-postgresql

Windows 종료 명령어

# 역순으로 서비스 중지 (관리자 권한 PowerShell)
Stop-Service PlantPulse-Agent
Stop-Service PlantPulse-Server
Stop-Service PlantPulse-CEP
Stop-Service PlantPulse-TSE
Stop-Service PlantPulse-MQTT
Stop-Service PlantPulse-Kafka
Stop-Service PlantPulse-Cassandra
Stop-Service PlantPulse-Redis
Stop-Service PlantPulse-PostgreSQL
@echo off
REM plantpulse-stop-all.bat - 전체 종료 배치 파일

echo [%date% %time%] OPC Agent 종료 중...
net stop PlantPulse-Agent
timeout /t 5 /nobreak > nul

echo [%date% %time%] 웹서버 종료 중...
net stop PlantPulse-Server
timeout /t 10 /nobreak > nul

echo [%date% %time%] CEP 종료 중...
net stop PlantPulse-CEP
timeout /t 5 /nobreak > nul

echo [%date% %time%] 시계열 엔진 종료 중...
net stop PlantPulse-TSE
timeout /t 5 /nobreak > nul

echo [%date% %time%] MQTT 종료 중...
net stop PlantPulse-MQTT
timeout /t 5 /nobreak > nul

echo [%date% %time%] Kafka 종료 중...
net stop PlantPulse-Kafka
timeout /t 10 /nobreak > nul

echo [%date% %time%] Cassandra 종료 중...
net stop PlantPulse-Cassandra
timeout /t 30 /nobreak > nul

echo [%date% %time%] Redis 종료 중...
net stop PlantPulse-Redis
timeout /t 5 /nobreak > nul

echo [%date% %time%] PostgreSQL 종료 중...
net stop PlantPulse-PostgreSQL
timeout /t 10 /nobreak > nul

echo [%date% %time%] 전체 종료 완료
pause

재시작

일반 재시작

전체 플랫폼을 재시작하려면 종료 후 시작을 순서대로 수행합니다.

# 전체 종료 (역순)
sudo systemctl stop plantpulse-agent
sudo systemctl stop plantpulse-server
sudo systemctl stop plantpulse-cep
sudo systemctl stop plantpulse-timeseries
sudo systemctl stop plantpulse-mqtt
sudo systemctl stop plantpulse-kafka
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/nodetool drain
sudo systemctl stop plantpulse-cassandra
sudo systemctl stop plantpulse-redis
sudo systemctl stop plantpulse-postgresql

# 전체 시작 (정순)
sudo systemctl start plantpulse-postgresql
sudo systemctl start plantpulse-redis
sudo systemctl start plantpulse-cassandra
sleep 60 # Cassandra 시작 대기
sudo systemctl start plantpulse-kafka
sudo systemctl start plantpulse-mqtt
sudo systemctl start plantpulse-timeseries
sudo systemctl start plantpulse-cep
sudo systemctl start plantpulse-server
sudo systemctl start plantpulse-agent

Rolling Restart (무중단 재시작)

클러스터 환경에서는 서비스 중단 없이 노드를 하나씩 재시작하는 Rolling Restart를 수행할 수 있습니다.

#!/bin/bash
# rolling-restart.sh - 클러스터 Rolling Restart
# 사용법: ./rolling-restart.sh node1 node2 node3

NODES=("$@")

for NODE in "${NODES[@]}"; do
echo "=== $NODE 재시작 시작 ==="

# 1. 로드밸런서에서 노드 제거
echo "$NODE 로드밸런서에서 제거 중..."
# curl -X POST http://loadbalancer/api/remove-node -d "node=$NODE"

# 2. 연결 드레인 대기 (기존 요청 처리 완료 대기)
echo "기존 연결 드레인 대기 (30초)..."
sleep 30

# 3. 서비스 재시작
echo "$NODE 서비스 재시작 중..."
ssh "$NODE" "sudo systemctl restart plantpulse-server"

# 4. 헬스체크 통과 대기
echo "$NODE 헬스체크 대기 중..."
until ssh "$NODE" "curl -sf http://localhost/api/v5/ping > /dev/null 2>&1"; do
sleep 5
done

# 5. 로드밸런서에 노드 재등록
echo "$NODE 로드밸런서에 재등록 중..."
# curl -X POST http://loadbalancer/api/add-node -d "node=$NODE"

echo "=== $NODE 재시작 완료 ==="
echo "다음 노드 진행 전 안정화 대기 (60초)..."
sleep 60
done

echo "Rolling Restart 완료"

안내: Rolling Restart는 웹서버(Tomcat)에 적용됩니다. Cassandra 클러스터의 Rolling Restart는 nodetool drain 후 각 노드를 순차적으로 재시작해 주세요.


상태 확인

프로세스 확인

# 전체 PlantPulse 관련 프로세스 확인
ps aux | grep plantpulse

# 특정 서비스 프로세스 확인
ps aux | grep plantpulse-server
ps aux | grep cassandra
ps aux | grep kafka

포트 확인

# 핵심 포트 한 번에 확인
for port in 5432 6379 9042 9092 1883 7800 7400 80 60000; do
if nc -z 127.0.0.1 $port 2>/dev/null; then
echo "OK: 포트 $port 열림"
else
echo "FAIL: 포트 $port 닫힘"
fi
done

헬스체크 API

PlantPulse 웹서버는 /api/v5/ping 엔드포인트를 통해 헬스체크를 제공합니다.

# 기본 헬스체크
curl -sf http://localhost/api/v5/ping
# 응답: {"status":"OK","timestamp":1709884800000}

# HTTP 상태 코드만 확인
curl -sf -o /dev/null -w "%{http_code}" http://localhost/api/v5/ping
# 200이면 정상

로그 확인

# PlantPulse 웹서버 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-server/logs/system.log

# Cassandra 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/logs/system.log

# Kafka 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/logs/server.log

# 에이전트 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-plugin/opc-ua/logs/agent.log

# 시작 시 에러 로그만 필터링
grep -i "error\|exception\|fail" /opt/kopens/plantpulse-platform/plantpulse-server/logs/system.log | tail -20

JVM 상태 확인

# Java 프로세스 목록 확인
jps -lv

# PlantPulse 서버 힙 메모리 확인
jstat -gc $(pgrep -f plantpulse-server) 1000 5

# GC 로그 확인
tail -f /opt/kopens/plantpulse-platform/plantpulse-server/logs/gc.log

# 스레드 덤프 (문제 진단 시)
jstack $(pgrep -f plantpulse-server) > /tmp/thread-dump-$(date +%Y%m%d%H%M%S).txt

systemd 서비스 상태

# 전체 PlantPulse 서비스 상태 확인
systemctl list-units 'plantpulse-*' --all

# 특정 서비스 상세 상태
sudo systemctl status plantpulse-server
sudo systemctl status plantpulse-cassandra

자동 시작 설정

Linux (systemd enable)

서버 부팅 시 자동으로 서비스가 시작되도록 설정합니다.

# 자동 시작 활성화
sudo systemctl enable plantpulse-postgresql
sudo systemctl enable plantpulse-redis
sudo systemctl enable plantpulse-cassandra
sudo systemctl enable plantpulse-kafka
sudo systemctl enable plantpulse-mqtt
sudo systemctl enable plantpulse-timeseries
sudo systemctl enable plantpulse-cep
sudo systemctl enable plantpulse-server
sudo systemctl enable plantpulse-agent

# 자동 시작 상태 확인
systemctl list-unit-files 'plantpulse-*' | grep enabled

안내: systemd 유닛 파일에 After= 지시자를 사용하여 서비스 간 시작 순서 의존성을 설정해 두면, 부팅 시에도 올바른 순서로 시작됩니다. 예시:

[Unit]
Description=PlantPulse Server
After=plantpulse-postgresql.service plantpulse-redis.service plantpulse-cassandra.service
Requires=plantpulse-postgresql.service plantpulse-redis.service

[Service]
Type=forking
User=kopens
ExecStart=/opt/kopens/plantpulse-platform/plantpulse-server/bin/startup.sh
ExecStop=/opt/kopens/plantpulse-platform/plantpulse-server/bin/shutdown.sh
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Windows 서비스 자동 시작

# 서비스 자동 시작 설정
Set-Service -Name "PlantPulse-PostgreSQL" -StartupType Automatic
Set-Service -Name "PlantPulse-Redis" -StartupType Automatic
Set-Service -Name "PlantPulse-Cassandra" -StartupType Automatic
Set-Service -Name "PlantPulse-Kafka" -StartupType Automatic
Set-Service -Name "PlantPulse-Server" -StartupType Automatic
Set-Service -Name "PlantPulse-Agent" -StartupType Automatic

# 자동 시작 상태 확인
Get-Service PlantPulse-* | Select-Object Name, StartType, Status

비상 절차

서버 응답 없음

웹서버가 응답하지 않는 경우 다음 순서로 조치해 주세요.

# 1. 헬스체크 확인
curl -sf --connect-timeout 5 http://localhost/api/v5/ping
echo "HTTP 응답 코드: $?"

# 2. 프로세스 상태 확인
ps aux | grep plantpulse-server

# 3. 포트 점유 확인
ss -tlnp | grep ':80'

# 4. 스레드 덤프 (행(hang) 의심 시)
jstack $(pgrep -f plantpulse-server) > /tmp/thread-dump-$(date +%Y%m%d%H%M%S).txt

# 5. GC 상태 확인
jstat -gcutil $(pgrep -f plantpulse-server) 1000 3

# 6. 웹서버만 재시작 (다른 서비스는 유지)
sudo systemctl restart plantpulse-server

# 7. 재시작 후 헬스체크 확인
sleep 30
curl -sf http://localhost/api/v5/ping

OOM (Out Of Memory) 발생

# 1. OOM 발생 확인
dmesg | grep -i "out of memory\|oom"

# 2. 힙 덤프 확인 (자동 생성된 경우)
ls -la /opt/kopens/plantpulse-platform/plantpulse-server/logs/heapdump*

# 3. 메모리 사용량 확인
free -h
ps aux --sort=-%mem | head -10

# 4. JVM 힙 크기 조정 (catalina.sh 또는 setenv.sh)
# JAVA_OPTS="-Xms4g -Xmx8g -XX:+HeapDumpOnOutOfMemoryError"
# 설정 변경 후 재시작
sudo systemctl restart plantpulse-server

DB 연결 실패

# 1. PostgreSQL 연결 확인
psql -h 127.0.0.1 -U plantpulse -d plantpulse -c "SELECT 1"

# 2. Cassandra 연결 확인
cqlsh 127.0.0.1 -e "DESCRIBE KEYSPACES"

# 3. Redis 연결 확인
redis-cli -h 127.0.0.1 ping

# 4. 연결 수 확인 (PostgreSQL)
psql -h 127.0.0.1 -U plantpulse -d plantpulse -c "SELECT count(*) FROM pg_stat_activity"

# 5. DB 서비스 재시작 (필요 시)
# 주의: DB 재시작 전 반드시 웹서버와 에이전트를 먼저 종료해 주세요
sudo systemctl stop plantpulse-agent
sudo systemctl stop plantpulse-server
sudo systemctl restart plantpulse-postgresql
sudo systemctl start plantpulse-server
sudo systemctl start plantpulse-agent

운영 체크리스트

일일 점검

점검 항목명령어 / 확인 방법정상 기준
전체 서비스 상태systemctl list-units 'plantpulse-*'모든 서비스 active (running)
핵심 포트 확인포트 확인 스크립트 (위 참조)모든 포트 열림
헬스체크 APIcurl http://localhost/api/v5/pingHTTP 200, status OK
디스크 사용량df -h사용률 80% 미만
메모리 사용량free -h사용률 85% 미만
에러 로그grep ERROR plantpulse.log | tail -20반복적 에러 없음
Cassandra 상태nodetool status모든 노드 UN (Up/Normal)

주간 점검

점검 항목명령어 / 확인 방법정상 기준
Cassandra Compactionnodetool compactionstatsPending 작업 과다 아님
PostgreSQL 통계pg_stat_activity 조회idle 연결 과다 아님
Kafka Consumer Lagkafka-consumer-groups.sh --describe지연 메시지 수 정상 범위
JVM GC 통계jstat -gcutilFull GC 빈도 낮음
백업 확인최근 백업 파일 확인정상 백업 존재
로그 파일 용량du -sh */logs/비정상적 증가 없음
보안 업데이트OS 패키지 업데이트 확인알려진 취약점 없음