pd — DataLake CLI
pd(PlantPulse DataLake) is a single entry point command that starts, stops, and diagnoses eight services running inside the DataLake container, renders configuration, and takes backups. Nearly everything the admin console displays is output from this command's --json.
| Item | Value |
|---|---|
| Module | plantpulse-datalake-cli |
| Location | Inside container at /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd (in PATH) |
| On the host | Not present — you must docker exec plantpulse-datalake pd … |
docker exec plantpulse-datalake pd status # 하나만 칠 때
/opt/kopens/plantpulse-platform-docker/bin/shell.sh # 여러 개 칠 때 — 셸을 열고 pd … 만 친다
Platform-wide start/stop/restart is managed from /opt/kopens/plantpulse-platform-docker/bin/ on the host — up.sh · down.sh · restart.sh · restart-datalake.sh · status.sh. pd is one layer lower, a tool for managing services inside the container. The container itself runs pd start on startup and pd stop on shutdown, so operators rarely invoke pd start by hand. Most use cases are viewing status and restarting a single service.
30-second summary
Safety level: Read = changes nothing · Modify = alters state · Destructive = removes data or processes.
| Verb | One-liner | Level |
|---|---|---|
pd status [서비스] [--wait] | Port table. Exits 0 only when all rows are RUNNING | Read |
pd doctor | Check environment, secrets, templates, runtime tree (PASS / FAIL / N/A) | Read |
pd env | Directory and image identity of this node — declaration only, no measurement | Read |
pd logs [--list] [--lines N] [서비스…] | Follow service logs | Read |
pd storage | Volumes, WAL, replication slots, storage size, Kafka retention | Read |
pd retention | Table TTL, topic retention, cold tier, archive jobs | Read |
pd flow | Kafka consumer group lag | Read |
pd downtime | Unplanned downtime windows — restarts only | Read |
pd config list · diff · diff --templates | Template → path table, runtime vs rendered, host template vs image defaults | Read |
pd node status · info · cql · psql … | Cassandra / PostgreSQL queries and shells | Read |
pd backup list · schedule · status | Physical backup sets, timers, currently running | Read |
pd backup restore … --dry-run | Restore plan only | Read |
pd start [서비스] · stop · restart [--clean] | Start in order, stop in reverse (with stop proof), both | Modify |
pd config render | Actually writes configuration artifacts | Modify |
pd secret rotate VAR=값 | Credential rotation — invoked by passwd.sh on the host. Do not invoke directly | Modify |
pd backup · pd backup run --engine E --type full|diff | Logical dump, one physical backup | Modify |
pd backup schedule set|reset | Backup timer schedule | Modify |
pd node add · repair · compact · flush · drain … | Cassandra maintenance | Modify |
pd clean | Delete stopped module logs, temp files | Destructive (logs) |
pd kill [--dry-run] | SIGKILL all processes under PP_HOME | Destructive |
pd recover [파일] | DROP pp database and restore from logical dump | Destructive |
pd backup restore … --yes | Rewind data directory to physical backup | Destructive |
pd node cleanup · remove <host-id> | Delete snapshots, remove node from ring | Destructive |
Options have the same meaning for all verbs.
| Option | Meaning |
|---|---|
--json | Single JSON document for machines, not a human table. Format read by console. Accepted only by specific verbs; attaching to others exits 2 with rejection |
--show-secrets | config diff only. Passwords not masked with ***. Cannot be used with --json |
PD_DEBUG=1 | DEBUG logging. Prepended like PD_DEBUG=1 pd start |
Services and startup order
Eight services start in strict order. The authoritative source is services/order.txt alone. pd start runs top-to-bottom; pd stop runs in reverse.
| Order | Service | MASTER | WORKER | Internal components | pd status row (ports) |
|---|---|---|---|---|---|
| 1 | storage | ○ | ○ | valkey → postgres → cassandra → minio(MASTER only) | 6379 · 5432 · 9042 · 9000 |
| 2 | analytics | ○ | ○ | spark-master → hive → gravitino → kyuubi (WORKER has spark-worker · kyuubi) | 7077 · 4440 · 9083 · 19001 · 10000 |
| 3 | messaging | ○ | — | kafka · mqtt(HiveMQ) | 9092 · 1883 |
| 4 | timeseries | ○ | — | engine(TSE) · dashboard(Grafana) | 7800 · 3000 |
| 5 | cep | ○ | — | Tomcat | 7400 |
| 6 | workflow | ○ | — | temporal → kestra | 7233 · 8233 · 8380 |
| 7 | data-gateway | ○ | — | Tomcat | 5500 |
| 8 | admin-api | ○ | ○ | Admin console backend | 4949 |
- After starting each service, wait until its health check returns UP before proceeding to the next (ceiling: storage 1800 seconds, analytics 600 seconds, others 300 seconds).
storageandanalyticsare gatekeepers. If they fail to start, nothing further is attempted and exit 5. Others warn and continue (exit 6 at the end).timeseriesis MASTER-only as of 2026-09-05.plantpulse-sqlis deprecated as of 2026-09-07 and removed from this list.
Lifecycle
pd status # 전체 표 — 마지막 줄 "0 STOPPED" 면 정상
pd status storage # 서비스 하나의 헬스체크
pd status storage --wait # UP 이 될 때까지 대기
pd start cep # 죽은 서비스 하나 다시 띄우기
pd stop cep # 서비스 하나 내리기 — «멈췄다» 를 증명한다 (30초 + SIGTERM 15초 + SIGKILL 10초)
pd restart cep # stop → (정지가 증명되면) 5초 → start
pd restart cep --clean # 사이에 pd clean
pd restart # 전부 — 몇 분 걸린다. storage 가 먼저 돌아온다
pd status has four states.
| State | Meaning |
|---|---|
RUNNING | Port is open |
STOPPED | Port is closed. A startup window of tens of seconds is normal; check again after 1 minute |
UNKNOWN | Could not measure — no tool available to check port. Not necessarily dead |
DISABLED | Shut down via PD_OPTIONS. Exit code is not changed |
pd stop exits with 7, do not pd start immediatelySTILL RUNNING means stop proof failed. Starting over a surviving process causes port collision and data corruption. Use pd kill --dry-run to see what remains, then verify empty with pd kill, pd status, and pd start. Do not use FORCE=1 pd start.
The container's Docker HEALTHCHECK does not invoke pd status (too slow and occasionally flaky). Instead it checks whether postgres and cassandra answer actual queries and whether all ports are open. So "docker ps is healthy but pd status is STOPPED" is a startup window or a single transient miss; "unhealthy but pd status all RUNNING" means ports are open but queries fail (pd logs storage).
Diagnostics
pd doctor # 여섯 절 검사. 마지막 줄 FAIL 0 이면 된다
pd env # 디렉터리 · 이미지 정체 (0.25초)
pd logs --list # 따라갈 파일 목록만
pd logs --lines 50 cep # cep 만, 마지막 50줄부터
pd storage # 볼륨 90% 이상이면 FAIL
pd retention # 왜 안 줄어드나 — TTL · 토픽 보존 · 콜드 티어
pd flow # 데이터가 안 들어온다 — 컨슈머 lag
pd downtime # 자꾸 죽는 것 같다 — 계획 밖 정지 기록
pd doctor has six sections: [1] inputs (secrets, node files, image) · [2] tools · [3] config templates (fully rendered?) · [4] runtime tree · [5] TLS material · [6] core ports. N/A reads "unmeasurable here" with reason in parentheses. Missing sidecar files inside the container is normal — values come from environment variables.
pd flow's NA means "never read" not "fell behind." If the MEMB column is 0, no consumer is running; if greater than 0 but the topic is empty, that is normal (nothing to read); if greater than 0 with data in the topic, that is a real warning sign.
Configuration
pd config list # 이 모드의 템플릿 → 경로 표
pd config diff # 런타임 파일 vs 지금 렌더하면 나올 것 (0 같음 / 1 다름 / 3 시크릿 없음 / 4 렌더 실패)
pd config diff --templates # 호스트 템플릿 vs 이미지 기본값 (same / differs / local / missing)
pd config render # 실제로 쓴다 — 그 뒤 pd restart <서비스> 까지가 한 세트
Procedures for changing values and "where to edit" are in how to change configuration. Do not edit artifacts inside the container directly — they disappear after the next pd start.
Cassandra · PostgreSQL node operations
pd node status # nodetool status — UN 이 정상, DN 이면 죽은 노드
pd node status --json # + PostgreSQL 복제 · Valkey 복제 · 워커 명부
pd node info # 노드 상세
pd node cql # cqlsh (cassandra 계정)
pd node psql # psql (postgres OS 사용자)
pd node errors # cassandra debug.log 의 최근 WARN/ERROR
pd node topic # kafka 토픽 "event" describe
pd node tpstats | compactionstats | proxyhistograms | table-stats [ks] | table-histograms <ks> <tbl> | sstable-size <ks> <tbl> | disk
| Modifying verb | Level | One-liner |
|---|---|---|
pd node add | Modify | Raise keyspace RF to number of live nodes (max 3) and repair. Add workers first, then run once on master |
pd node repair · repair-table <ks> <tbl> | Modify (heavy) | Reconcile data inconsistency between nodes |
pd node flush · drain | Modify | Flush writes from memory to disk. drain blocks writes afterward, use only before shutdown |
pd node compact [ks] [tbl] | Modify (heavy) | Merge SSTables |
pd node cleanup | Destructive | Delete all snapshots + data this node no longer owns |
pd node remove <host-id> | Destructive | Remove dead node from ring. Do not run on a live node |
pd node upgrade · init-cms · train-zstd · cache-clear | Modify | Installation procedure, upgrade, OS page cache flush |
Backup · Restore
pd backup # PostgreSQL 논리 덤프 → /data1/pp-data/postgres/dump/
pd backup list | schedule | status
pd backup run --engine postgres --type diff
pd backup restore --engine postgres --set <세트> --dry-run # 계획 먼저
pd recover [덤프파일] # pp DB 하나를 논리 덤프로 되돌림 (파괴적)
Procedures are in backup and restore.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success. status all RUNNING, doctor zero FAIL, config diff no difference |
| 1 | General failure, "differs," "has issues" |
| 2 | Usage error — unknown verb, service, option; --json rejected; PP_HOME missing |
| 3 | Required secret missing — message lists all names. For backup run · restore: "another backup is running" |
| 4 | Render failed — unsubstituted ${PP_*}; all names listed |
| 5 | Gatekeeper service (storage · analytics) failed to start; startup halted |
| 6 | Startup finished but some services not ready |
| 7 | Stop proof failed (STILL RUNNING) |
| 8 | Advertisement address is loopback (127.0.0.1) — render rejected |
Log format and journal
Every line pd writes has one shape — [시각] [DATALAKE-CLI] [레벨] [동사] 메시지. INFO to stdout, rest to stderr.
pd start · stop · restart · backup each write one JSON line to the event journal plantpulse-datalake-admin-api/logs/pd-events.jsonl, which the console displays as an event timeline. Commands run from the console are logged by actor as operator:<name>.
Legacy name mapping
The collection of scripts in plantpulse-startup was merged into pd on 2026-09-03, and the old directory is no longer in the image.
| Old script | Now |
|---|---|
start-daemon.sh · start.sh | pd start |
stop.sh | pd stop |
restart.sh · restart-<module>.sh | pd restart [서비스] |
restart-monitor.sh | pd restart admin-api |
status.sh | pd status |
kill.sh · clean.sh | pd kill · pd clean |
configure.sh | pd config render |
log-viewer.sh | pd logs |
node-<동사>.sh · node-added.sh · node-error.sh | pd node <동사> · pd node add · pd node errors |
secrets/rotate.sh | pd secret rotate (invoked by passwd.sh on host) |
env.sh · env-reset.sh · env-validate.sh | Removed — values are reconciled by host sidecar, node files, and compose |
prepare-ssl.sh | plantpulse-certs container handles it → security configuration |
PP_OPTIONS | PD_OPTIONS (2026-09-07). Old name not read |
Server, Batch, Warehouse, OPC-UA, and AASX are handled in their own containers. The DataLake container has no such modules. Restart apps from the host.
cd /opt/kopens/plantpulse-platform-docker/bin
./restart-server.sh # 또는 restart-batch.sh · restart-warehouse.sh · restart-one.sh <서비스>
Related docs
- Start, stop, restart — relationship between host verbs and
pd - Logs and health
- How to change configuration