Two-Node Separated Installation (Datalake / Application)
Overview
This procedure installs the PlantPulse Platform across two servers: a Datalake node and an Application node. Unlike a single-box (FULL) installation, the storage, messaging, and analytics layer runs on one box while the console and batch layer runs on another. Large batch jobs (such as archiving) do not impact console responsiveness, and per-node memory requirements are reduced.
When to use this? This architecture suits environments where a single server has 128GB or less RAM, or when you want to isolate data processing load from console service to improve stability. If a single server is sufficient (recommended 256GB), use the default (FULL) installation from one-line install.
Tier (PP_TIER) Concept
At installation, the PP_TIER environment variable specifies the node's role.
| PP_TIER | Role | Services Started |
|---|---|---|
FULL (default) | Single-box all-in-one | All services (equivalent to existing installation if unspecified) |
DATALAKE | Datalake node | Cassandra · PostgreSQL · Kafka · MQTT · Redis · MinIO · Spark · Hive · TSE · CEP · Data Gateway · Temporal · Kestra · Monitor and other infrastructure layer |
APP | Application node | Server (console 80/443) · Batch · Warehouse · OPC-UA · AASX · HA and other application layer |
PP_TIERis independent of the clustering variablePP_MODE(MASTER/WORKER).- All Datalake connections from the APP node (host variables) automatically connect to
PP_MASTER_IP(Datalake node IP).
Configuration Files by Node (Copy Targets vs. Per-Node)
In a two-node installation, files in /etc/kopens/ have different roles. What to copy and what not to copy is the most critical point.
| File/Directory | Contents | Nature | Copy Between Nodes |
|---|---|---|---|
/etc/kopens/plantpulse-platform.env | Service secrets sidecar (DB/messaging passwords, etc.) | Cluster-shared | ✅ Copy |
/etc/kopens/ca/ | Shared cluster CA (CA.crt/CA.key) — TLS trust between nodes | Cluster-shared | ✅ Copy |
/etc/kopens/platform.node.env | Node topology (PP_TIER, PP_MASTER_IP) — auto-recorded at installation | Per-node identity | ❌ Do not copy |
Path verification — The authoritative sidecar secrets location is
/etc/kopens/plantpulse-platform.env(permissions0600). Older installations may have the same name under/opt/kopens/, but it is not read; the installation script restores the canonical location → Environment Variable Reference
platform.node.envis auto-created and recorded bystack-run.shat installation, so the node remembers its tier even after restart or upgrade.- Topology (
PP_TIER) is kept in a separate file from the secrets sidecar for this reason: the sidecar is copied as-is to the app node, so if tier information were there, the Datalake node's tier would leak into the app node, causing it to install incorrectly as DATALAKE.
Per-Node Specifications
| Node | Minimum Specs | Notes |
|---|---|---|
| Datalake | 16 vCPU / 64GB RAM / 500GB+ disk | Increase disk as data volume grows |
| Application | 8 vCPU / 48GB RAM / 100GB disk | Resident footprint ~35GB measured |
Both nodes must be on the same network and reach each other (see firewall section below for port list).
Installation Procedure
Step 1 — Install Datalake Node
Run this on the server to be used as Datalake.
sudo -i
export PP_TIER=DATALAKE
curl -fsSL https://product.kopens.io/plantpulse-platform/install.sh | bash
- The boot gate auto-detects the tier. The Datalake node waits until monitor health (
:4950/api/health) reaches OK/WARN, then must pass stack readiness (bin/stack-verify-boot.sh) to be considered successfully installed. - When installation completes, a join bundle is auto-generated:
/etc/kopens/plantpulse-platform.env— Service secrets (cluster-shared)/etc/kopens/ca/— Shared cluster CA (TLS trust between nodes)
The Datalake node is the cluster's CA issuing authority. The Application node receives and reuses this CA, so inter-node TLS (CEP event channel) is automatically trusted.
Step 2 — Copy Join Bundle
Copy two items from the Datalake node to the Application node.
# 데이터레이크 노드에서 실행 (<app-ip> = 애플리케이션 노드 IP)
scp /etc/kopens/plantpulse-platform.env root@<app-ip>:/etc/kopens/
scp -r /etc/kopens/ca root@<app-ip>:/etc/kopens/
Warning: Do not copy the
/etc/kopens/platform.node.envfile. This file holds the node's tier identity (its role). Copy only the two items listed above (Configuration Files by Node).If you previously installed on an older version,
platform.env.generatedmay contain a remainingexport PP_TIER=...line. The latest installation script auto-removes it (migration), but it is safer to delete that line before copying.
Step 3 — Install Application Node
Run this on the Application node. Specify the Datalake node IP in PP_MASTER_IP.
sudo -i
export PP_TIER=APP
export PP_MASTER_IP=<datalake-node-ip>
curl -fsSL https://product.kopens.io/plantpulse-platform/install.sh | bash
stack-run.shauto-applies the join bundle's shared CA (/etc/kopens/ca/) to thepp-securityvolume before first boot. During the certificate preparation phase, that CA signs this node's certificate and constructs the truststore, so the Datalake node's TLS services (CEP event channel, etc.) are automatically trusted.- All Datalake backend connections (Cassandra/PostgreSQL/Kafka/Redis/MinIO/TSE/CEP, etc.) are auto-configured to
PP_MASTER_IP. - The app node has no monitor (:4950), so the boot gate uses console (
:80/status) HTTP 200 response as the readiness criterion.
Firewall (Datalake Node)
The Datalake node must allow connections from the Application node. The simplest method is to add the Application node IP to the firewalld trusted zone.
# 데이터레이크 노드에서 실행
firewall-cmd --permanent --zone=trusted --add-source=<app-ip>
firewall-cmd --reload
Key cross-node ports: 9042 (Cassandra) · 5432 (PostgreSQL) · 9092/9093/9094 (Kafka) · 1883/1884 (MQTT) · 6379 (Redis) · 9000 (MinIO) · 7077 (Spark) · 9083 (Hive) · 10000 (Kyuubi) · 19001 (Gravitino) · 7800/7801 (TSE) · 7400 (CEP) · 5500 (Data Gateway) · 7233 (Temporal) · 4950 (Monitor)
Installation Verification
# 데이터레이크 노드 — 인프라 헬스 (OK 또는 WARN 이면 정상)
curl -kfsS https://127.0.0.1:4950/api/health | jq .status
# 애플리케이션 노드 — 콘솔 상태
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:80/status # 200 이면 정상
Web console access: https://<app-node-ip> — successful login is the final confirmation (see Login for initial account).
Cross-Node TLS (Shared CA) Verification
Print the CA fingerprint on both nodes and confirm they match. If fingerprints differ, inter-node TLS trust is broken.
The CA material is in the pp-security volume; read it from a container that mounts that volume. The container you query differs per node — the Datalake node has plantpulse-datalake, the app node does not.
# 데이터레이크 노드에서
docker exec plantpulse-datalake \
openssl x509 -in /var/security/plantpulse/CA.crt -noout -fingerprint -sha256
# 애플리케이션 노드에서 (앱 컨테이너면 무엇이든 같은 볼륨을 읽습니다)
docker exec plantpulse-server-web \
openssl x509 -in /var/security/plantpulse/CA.crt -noout -fingerprint -sha256
Verify zero TLS trust errors (PKIX) in the Application node logs.
# 애플리케이션 노드에서 — 아무 것도 출력되지 않아야 정상
grep -Rl "PKIX" /opt/kopens/plantpulse-platform-docker/logs 2>/dev/null
Datalake Connection Verification
To verify Datalake connectivity from the Application node:
The app container does not have the Datalake's configuration renderer and does not read its env.sh. The only source of truth for values seen by the app is compose, so verify environment variables actually injected into the container.
# 애플리케이션 노드에서 — 백엔드 호스트가 데이터레이크 IP 로 잡혀 있는지
docker exec plantpulse-server-web env | grep -E '_HOST=|MASTER_IP='
If the value is 127.0.0.1, the installation was run without PP_MASTER_IP.
Restart and Upgrade Behavior
- Tier identity is stored in each node's
/etc/kopens/platform.node.envand persists after restart or upgrade. You need not re-specifyPP_TIERunless doing a reinstall. - Container image upgrades follow the existing procedure per node (
update.sh).
Tier Switch and Reinstall Precautions
-
Before reinstalling as single-box (FULL), delete
/etc/kopens/platform.node.envfirst. If this file remains, environment configuration auto-reads it and boots with the previous tier (DATALAKE/APP). An unspecifiedPP_TIER(FULL) installation does not overwrite this file.rm -f /etc/kopens/platform.node.env -
To convert an APP node to FULL (single-box), perform a clean reinstall. The APP node has never initialized local infrastructure (database schemas, etc.), so remove all containers, volumes, and configuration, then install FULL from scratch (removal procedure is in Docker Installation full removal section).
Troubleshooting
| Symptom | Root Cause / Action |
|---|---|
APP node service attempts connection to 127.0.0.1 | PP_MASTER_IP not specified — check node.env and reinstall |
| Reinstalled but boots with previous tier | /etc/kopens/platform.node.env persists — delete and reinstall (Tier Switch and Reinstall Precautions) |
| App node installs as DATALAKE | Older sidecar with PP_TIER line remains from copy — remove that line from sidecar and reinstall |
| CEP event TLS error (PKIX) | ca/ from join bundle not copied (CA fingerprint mismatch) — redo Step 2, then reinstall APP node |
| APP node Kafka publish fails (Expiring records) | Datalake firewall does not allow APP node, or older installation script — verify firewall, then reinstall with latest script |
| Login screen shows error | APP node boot delay in Datalake connection — restart console container (docker compose -f compose/docker-compose.yml restart plantpulse-server-web) |