시스템 시작 및 종료
개요
PlantPulse 는 Docker Compose 스택으로 동작합니다. 시작 / 종료 / 재시작은 /opt/kopens/plantpulse-platform-docker/bin/ 의 공통 동사 한 곳에서 관리하며, 컨테이너 간 의존성 순서는 compose 의 depends_on 이 자동으로 적용하므로 운영자가 일일이 순서를 신경 쓸 필요는 없습니다.
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_TIMEOUT | 900 | 준비 대기 상한(초) |
PP_READY_INTERVAL | 15 | 확인 간격(초) |
PP_WAIT=0 | — | 대기하지 않음. 이때의 0 은 준비 완료를 뜻하지 않습니다 |
시작 순서 (자동)
컨테이너 사이
compose 의 depends_on 이 service_healthy 조건으로 순서를 지킵니다 — «프로세스가 떴다»가 아니라 «쓸 수 있다»를 기다립니다. 이 순서는 임의가 아니라 애플리케이션 오케스트레이터의 기동 순서를 그대로 옮긴 것입니다.
마지막 넷(warehouse · opcua · aasx · ha)은 서로 순서가 없습니다.
데이터레이크 컨테이너 안
인프라 컴포넌트는 plantpulse-datalake 한 컨테이너 안에서 다시 순서대로 기동합니다.
| 순서 | 영역 | 주요 컴포넌트 | 대표 포트 |
|---|---|---|---|
| 1 | 스토리지 | Cassandra, PostgreSQL, Valkey, MinIO | 9042 / 5432 / 6379 / 9000 |
| 2 | 분석 | Spark, Hive, Kyuubi, Gravitino | 7077 / 9083 / 10000 / 19001 |
| 3 | 시계열 | TSE Engine, UI | 7800 / 3000 |
| 4 | 메시징 | Kafka, MQTT | 9092 / 1883 |
| 5 | 워크플로우 | Temporal, Kestra | 7233 / 8233 / 8380 |
| 6 | 처리 | CEP, Data Gateway, SQL, Monitor | 7400 / 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
- (돌고 있다면) 데이터레이크에 graceful drain 요청
- 스택 전체를 의존 순서의 역순으로 정지
depends_on순서로 다시 기동- 준비될 때까지 대기 — 종료 코드
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 가 unhealthy | starting / none 은 판정 보류 |
| 헬스 API 가 OK 가 아님 | 데이터레이크 안에서 probe |
볼륨과 conf 는 보고만 하고 종료 코드에 넣지 않습니다 — 2노드 분리 설치(PP_TIER=APP)에서는 일부가 없는 것이 정상이기 때문입니다.
Exited (0) 은 성공입니다plantpulse-certs 는 인증서를 굽고 스스로 끝납니다. compose 가 이 컨테이너의 헬스체크를 명시적으로 꺼 두었으므로(healthcheck: disable) health 칸은 비어 있습니다 — 원샷에 health probe 를 걸면 «정상 동작하는 컨테이너가 영원히 unhealthy» 로 보이고, 모든 사람이 그 하나만 예외로 기억해야 하기 때문입니다. status.sh 와 ops-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 이 정상 범위입니다.
콘솔과 헬스 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
프록시의 헬스체크는 자기 자신 + 업스트림 도달까지만 봅니다(백엔드의 건강 상태는 웹 서버 자신의 헬스체크가 판정합니다). 프록시가 초록인데 화면이 안 나온다면 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 로 적용합니다.
앱마다 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.sh | critical 로그 없음 |
| 헬스 API | curl -kfsS https://<서버IP>:4950/api/health | status 가 OK 또는 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 compactionstats | Pending 작업 과다 아님 |
| 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
종료 순서
종료는 시작의 역순으로 수행해야 합니다. 데이터를 수집하는 에이전트부터 먼저 종료하고, 마지막으로 데이터베이스를 종료합니다.
| 순서 | 서비스 | 설명 |
|---|---|---|
| 1 | OPC Agent | 데이터 수집 중지 |
| 2 | PlantPulse 웹서버 (Tomcat) | 웹 서비스 중지 |
| 3 | CEP | 이벤트 처리 중지 |
| 4 | TSE | 시계열 엔진 중지 |
| 5 | MQ (Kafka / MQTT) | 메시지 브로커 중지 |
| 6 | Cassandra | 시계열 DB 중지 |
| 7 | Redis (Valkey) | 캐시 중지 |
| 8 | PostgreSQL | 메타 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 ServerAfter=plantpulse-postgresql.service plantpulse-redis.service plantpulse-cassandra.serviceRequires=plantpulse-postgresql.service plantpulse-redis.service[Service]Type=forkingUser=kopensExecStart=/opt/kopens/plantpulse-platform/plantpulse-server/bin/startup.shExecStop=/opt/kopens/plantpulse-platform/plantpulse-server/bin/shutdown.shRestart=on-failureRestartSec=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) |
| 핵심 포트 확인 | 포트 확인 스크립트 (위 참조) | 모든 포트 열림 |
| 헬스체크 API | curl http://localhost/api/v5/ping | HTTP 200, status OK |
| 디스크 사용량 | df -h | 사용률 80% 미만 |
| 메모리 사용량 | free -h | 사용률 85% 미만 |
| 에러 로그 | grep ERROR plantpulse.log | tail -20 | 반복적 에러 없음 |
| Cassandra 상태 | nodetool status | 모든 노드 UN (Up/Normal) |
주간 점검
| 점검 항목 | 명령어 / 확인 방법 | 정상 기준 |
|---|---|---|
| Cassandra Compaction | nodetool compactionstats | Pending 작업 과다 아님 |
| PostgreSQL 통계 | pg_stat_activity 조회 | idle 연결 과다 아님 |
| Kafka Consumer Lag | kafka-consumer-groups.sh --describe | 지연 메시지 수 정상 범위 |
| JVM GC 통계 | jstat -gcutil | Full GC 빈도 낮음 |
| 백업 확인 | 최근 백업 파일 확인 | 정상 백업 존재 |
| 로그 파일 용량 | du -sh */logs/ | 비정상적 증가 없음 |
| 보안 업데이트 | OS 패키지 업데이트 확인 | 알려진 취약점 없음 |