Docker Installation
From May 2026, the standard mass production/field deployment for PlantPulse Edge is a single Docker container image.
Seven components (Tomcat / Cassandra / Redis / HiveMQ / TSE / Dashboard / Node-RED) are contained within one image. install.sh handles everything from OS dependencies to systemd registration, after which plantpulse-edge.service manages the container.
For a summary of the procedure to quickly deploy a single unit in the field, see Quick Install (install.sh).
This page is a reference that dives deep into what the installation does internally — image coordinates, docker run flags, bind mounts, EnvironmentFile, and OTA. For day-to-day operations, refer to Container Mode Operations.
1. Image Coordinates
| Item | Value |
|---|---|
| Registry | docker.kopens.io/pe (anonymous pull) |
| Image Name | plantpulse-edge |
| Full Coordinates | docker.kopens.io/pe/plantpulse-edge:<tag> |
| Tag Format | YYYY.MM-YYYYMMDD-HHMM e.g., 2026.11-20261103-1006 (During installation, latest is also possible; OTA requires immutable tags only) |
| Download Server | https://product.kopens.io/plantpulse-edge/ (LAN alias) |
Fixed paths within the image: KOPENS_HOME=/opt/kopens, PE_HOME=/opt/kopens/plantpulse-edge, PE_DATA_DIR=/data1, JAVA_HOME=/usr/lib/jvm/java-21-openjdk.
2. Installation Flow — bootstrap.sh → install.sh
2.1 One-liner
curl -fsSL https://product.kopens.io/plantpulse-edge/install.sh | sudo bash
install.sh is identical to bootstrap.sh. This script performs the following:
- Unpacks the repo tarball (
plantpulse-edge-docker.tar.gz) to/opt/kopens/plantpulse-edge-docker/(falls back togit cloneupon failure) - Applies
PROFILEpreset (if available, see Section 3 below) - Executes the 9 steps of the
install.shmain body
If executed directly in the terminal, it asks for input (default behavior). Values in brackets are defaults and are accepted by pressing Enter.
EDGE(Default) — Must ask for the platform address and API key; will ask again if left blank.STANDALONE— Does not ask for either of those.Edge idDefaults vary by box (follows theEDGE_3F8A21format derived from NET1 MAC). Enter the field number here if applicable.
curl | bash — provide values as environment variablesWhen executed via pipe, the terminal is not attached, so the script cannot ask for input. In such cases, it states that it «cannot ask» and proceeds using environment variables and default values (it does not pass silently).
curl -fsSL https://product.kopens.io/plantpulse-edge/install.sh | \
sudo EDGE_ID=EDGE_00303 DEV_MODE=EDGE \
SERVER_HOST=<플랫폼IP> SERVER_API_KEY=<token> bash
To enable interactive prompts, download and execute the script directly. For automation (CI/unattended installation), it is safer to disable prompts using INTERACTIVE=0.
env.shWrite it in env.sh in the same folder as the script, and the installation will read it automatically. The same value will be used during re-installation.
2.1a «Verification» of Platform Key During Installation
If DEV_MODE=EDGE is enabled, the installer actually queries the platform before writing the settings. Previously, it only checked if the value was non-empty, and all connections failed with 401 errors only after booting.
| Scenario | Installer Behavior |
|---|---|
| Platform unreachable | Warning only — The platform may not be up yet, or the firewall may not be configured |
| Server 5xx | Warning only — Indicates a failure to determine the status, not a key issue |
| 401 · 403 | 🔴 Halt — Key rejected. Typos are caught here |
| 400 | 🔴 Halt — Issue with the installer; please report this |
If the platform must be installed after the Edge, disable this with SKIP_PLATFORM_VERIFY=1.
2.1b --help is the Official Usage Guide
sudo bash install.sh --help # root 없이도 읽힙니다
The output includes a banner followed by sections USAGE · MODE decides what else is required · IDENTITY · PLATFORM · IMAGE · NETWORK · SKIP FLAGS · PROFILE · AFTER INSTALL. The full text is not transcribed here because transcribed copies quietly become outdated. There were previous instances where the headers in this repository diverged from the default values in the code.
2.2 install.sh 9 Steps
| # | Step |
|---|---|
| 1 | OS Detection (Rocky/Alma/RHEL/Ubuntu/Debian) |
| 2 | Docker Installation (dnf or apt) |
| 3 | Directory creation for /data1, /etc/kopens, /var/log/kopens |
| 4 | sysctl + firewalld ports + chrony + hostname + nmcli static IP |
| 5 | Creation of /etc/kopens/app.properties (EDGE_ID / SITE_ID / random credentials per box) |
| 6 | systemd unit installation — plantpulse-edge.service + OTA kopens-upgrade.path/.service |
| 7 | docker pull (cosign signature verification — warning only during install, halt if verification fails during upgrade) |
| 8 | systemctl enable --now plantpulse-edge.service |
| 9 | Registration of weekly cron cleanup |
During the first installation, the admin / MQTT / OPC-UA / API key / keystore passwords are generated randomly per box and stored once in /etc/kopens/credentials.txt (chmod 0600 root).
3. PROFILE Preset
Apply default values for each site type at once using the PROFILE environment variable.
| PROFILE | Applied Defaults |
|---|---|
production | DEV_MODE=EDGE (Requires explicit platform SERVER_HOST/SERVER_API_KEY) |
staging | DEV_MODE=EDGE, EDGE_ID=EDGE_00303, SITE_ID=SITE_00001, SERVER_HOST=192.168.0.235, SKIP_COSIGN_VERIFY=1 |
standalone | DEV_MODE=STANDALONE, SKIP_COSIGN_VERIFY=1 (Platform disconnected) |
airgap | IMAGE_URL=tarball, SKIP_PULL=1, DEV_MODE=STANDALONE (Air-gapped network installation) |
# 양산 (플랫폼 연결)
curl -fsSL https://product.kopens.io/plantpulse-edge/install.sh \
| sudo PROFILE=production EDGE_ID=EDGE_00303 \
SERVER_HOST=10.0.0.5 SERVER_API_KEY=<uuid> bash
# 단독 운영 (플랫폼 없이)
curl -fsSL https://product.kopens.io/plantpulse-edge/install.sh \
| sudo PROFILE=standalone EDGE_ID=EDGE_LOCAL_01 bash
The staging box is a clone of dev with the same EDGE_00303 / SITE_00001. The only difference should be the platform connection info (SERVER_HOST=192.168.0.235 / API key). Using a site not registered on the platform will cause the Edge self-diagnostic OPC to fail due to an FK violation, so use the registered EDGE/site. If connected to the platform simultaneously with dev, they will be recognized as the same edge; operate them so that verification does not overlap.
For a full list of environment variables commonly used during installation, see env Configuration §6.
4. systemd Unit Anatomy — plantpulse-edge.service
This is the actual container startup definition deployed by install.sh as /etc/systemd/system/plantpulse-edge.service.
4.1 docker run (ExecStart)
/usr/bin/docker run --rm --name plantpulse-edge \
--network=host \
--init \
--stop-timeout=120 \
-v /data1:/data1:z \
-v /etc/kopens:/etc/kopens:z \
-v /etc/kopens/conf:/opt/kopens/plantpulse-edge/conf:z \
-v /var/security:/var/security:rw,z \
-v /etc/localtime:/etc/localtime:ro \
-v /var/run/docker.sock:/var/run/docker.sock \
-e PP_LANG=${PP_LANG} \
-e PP_TZ=${PP_TZ} \
-e CERT_PASS=${CERT_PASS} \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--cap-add=NET_RAW \
--cap-add=DAC_OVERRIDE \
--cap-add=CHOWN \
--cap-add=FOWNER \
--log-driver=journald \
--log-opt tag="plantpulse-edge" \
${KOPENS_IMAGE}:${PE_VERSION}
| Flag | Meaning |
|---|---|
--network=host | Automatically expose 9 ports + natural multicast / OPC-UA discovery |
--init | tini as PID 1 (zombie reap + signal forward) |
--stop-timeout=120 | Ensures time for Cassandra graceful drain |
--cap-drop=ALL + individual --cap-add | Minimum privilege. NET_RAW for PLC ping, NET_BIND_SERVICE for 80/443 bind |
4.2 Bind Mount
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
/data1 | /data1 | rw,z | Data (Cassandra/Redis/HiveMQ/Node-RED) — preserved across container replacement |
/etc/kopens | /etc/kopens | rw,z | Configuration + signal files |
/etc/kopens/conf | /opt/kopens/plantpulse-edge/conf | rw,z | app.properties / log4j2.xml |
/var/security | /var/security | rw,z | TLS keystore |
/etc/localtime | /etc/localtime | ro | Host timezone |
/var/run/docker.sock | /var/run/docker.sock | rw | /ui/apps Docker app management |
4.3 EnvironmentFile + Defaults
Built-in unit defaults (when file is missing):
Environment=PE_VERSION=latest
Environment=KOPENS_IMAGE=docker.kopens.io/pe/plantpulse-edge
Environment=PP_LANG=en
Environment=PP_TZ=Asia/Seoul
Environment=CERT_PASS=kopens123!
EnvironmentFile (overrides if present — latest value takes priority):
| File | Key | Creator |
|---|---|---|
/etc/kopens/version.env | PE_VERSION=<tag> | OTA upgrade.sh |
/etc/kopens/i18n.env | PP_LANG / PP_TZ | install.sh |
/etc/kopens/cert.env | CERT_PASS | TLS issuance script |
4.4 Resource Limits / Restart Policy
MemoryMax=12G # 16GB 박스 기준 — 호스트 OOM 방지
MemoryHigh=11G
CPUQuota=600% # 6 cores
TasksMax=8192
Restart=on-failure
RestartSec=30s
TimeoutStartSec=300
TimeoutStopSec=180
For heap reduction overrides (drop-ins) for 8GB boxes, see Container Mode §Resource Limits.
5. Container Runtime Configuration Read Paths
In WAR mode (from 2026-06-13~), configurations are read directly from /etc/kopens on the host — no image rebuild required.
/etc/kopens/app.properties ← 운영자가 편집하는 canonical
│ (entrypoint 가 symlink 생성)
▼
/etc/kopens/conf/app.properties ──bind──▶ /opt/kopens/plantpulse-edge/conf/app.properties
▲
Tomcat setenv.sh: -Dpe.conf.dir=/opt/kopens/plantpulse-edge/conf
- app.properties: Host
/etc/kopens/app.propertiesis the source-of-truth. If missing, the entrypoint seeds it with the image default. Operator edits → reflected viaconfig.sh --restart. - log4j2.xml: The entrypoint copies the webapp default to
conf/log4j2.xmlat every boot (code artifact — change log level and restart without image rebuild). - HiveMQ auth.properties: The entrypoint automatically syncs
mqtt.server.*ofapp.propertiesat every boot — onlyapp.propertiesneeds to be modified. - TLS Password: The entrypoint interprets
CERT_PASSfromcert.envand bulk-patches the Tomcatserver.xml/ HiveMQ config / OPC-UA keystore passwords.
For detailed env→configuration mirroring, see Environment Variable Configuration. For the meaning of each key, see app.properties Reference.
6. OTA Upgrade / Rollback
The version is fixed in /etc/kopens/version.env — OTA replaces this file with a verified digest and restarts.
# 자동 (META-INF/VERSION.JSON 이 가리키는 빌드)
sudo bash /opt/kopens/install/upgrade.sh
# 특정 불변 태그 (YYYY.MM-YYYYMMDD-HHMM). 움직이는 태그는 거부합니다
sudo bash /opt/kopens/install/upgrade.sh --to 2026.11-20261103-1006
# 진행 중인 현재 업그레이드만 롤백 (trial · rollback_failed 상태에서만)
sudo bash /opt/kopens/install/upgrade.sh --rollback
# 사전 점검만 (0 최신, 10 새 빌드 있음)
sudo bash /opt/kopens/install/upgrade.sh --check
Status: cat /etc/kopens/upgrade.status → idle · downloading · verified · snapshot · switching · trial · committed · rolling_back · rolled_back · rollback_failed.
For detailed flow, see Upgrade.
7. Manual docker run for Debugging
Operations must always go through systemd / install.sh, but manual startup is used for isolated debugging:
sudo docker run --rm --name pe-debug \
--network=host --init \
-v /data1:/data1:z \
-v /etc/kopens:/etc/kopens:z \
-v /etc/kopens/conf:/opt/kopens/plantpulse-edge/conf:z \
-v /var/security:/var/security:rw,z \
-e PP_LANG=en -e PP_TZ=Asia/Seoul -e CERT_PASS="$(. /etc/kopens/cert.env; echo $CERT_PASS)" \
docker.kopens.io/pe/plantpulse-edge:<tag>
Deployments must only occur via pipeline — do not perform image (re)build / push / staging redeployment locally. Use the release chain of
plantpulse-edge-docker(edge:libs→edge:deploy-dev→edge:image→edge:staging→edge:version, triggered by pipeline variableRELEASE=1). The above command is for isolated debugging only.
8. Post-Installation Verification
systemctl is-active plantpulse-edge.service
sudo bash /opt/kopens/install/bin/status.sh
# version: container_mode=true 여야 함
curl -ks https://127.0.0.1/api/v1/system/version | python3 -m json.tool
# health: HTTP 200 + components UP
curl -ks https://127.0.0.1/api/v1/system/health | python3 -m json.tool
| Screen | URL |
|---|---|
| Web UI | https://<gateway-ip>/ui/main |
| Node-RED | https://<gateway-ip>/ui/flow/ |
| Swagger UI | https://<gateway-ip>/public/swagger-ui/index.html |
For action by symptom, see Installation Troubleshooting. For day-to-day operations/failures, see Container Mode Operations.
9. Next Documents
- Quick Install (
install.sh) — Summary of the procedure for installing a single unit in the field - Environment Variable Configuration —
PROFILE/PP_LANG/CERT_PASS/-Dpe.conf.dir - Container Mode Operations — pe-* tools / logs / failure response
- Air-gapped network installation / Mass Production Line (
factory.sh) - Production Readiness Criteria