Docker (Container) Installation Details — plantpulse-edge.service
As of 2026.05, the standard production/field deployment of PlantPulse Edge is a single Docker container image.
All 7 components (Tomcat / Cassandra / Redis / HiveMQ / TSE / Dashboard / Node-RED) are bundled in one image, with install.sh handling everything from OS dependencies to systemd registration, after which plantpulse-edge.service manages the container.
For a procedure summary to bring up a single box quickly in the field, see Quick Install (install.sh).
This page is a reference that digs deep into what that installation does internally — image coordinates, docker run flags, bind mounts, EnvironmentFile, OTA. For day-to-day operation, see the
Container Mode Operations Guide.
The container is plantpulse-edge.service, native is plantpulse.service. The systemd unit carries
Conflicts=plantpulse.service, but forcing both services up at once will cause port/data conflicts.
1. Image Coordinates
| Item | Value |
|---|---|
| Registry | docker.kopens.io/pe (anonymous pull) |
| Image name | plantpulse-edge |
| Full coordinate | docker.kopens.io/pe/plantpulse-edge:<tag> |
| Tag format | <VERSION>-<BUILD_DATE> e.g. 2026-20260524 (or latest) |
| Download server | https://product.kopens.io/plantpulse-edge/ (LAN alias) |
Fixed paths inside 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:
- Extracts the repo tarball (
plantpulse-edge-docker.tar.gz) into/opt/kopens/plantpulse-edge-docker/(falls back togit cloneon failure) - Applies the
PROFILEpreset (if present, see section 3 below) - Interactive prompts — Edge ID (auto-suggested from MAC) / Site ID (default
SITE_00001) / Mode (1=EDGEdefault /2=STANDALONE) / for EDGE mode, platform server + API key - Runs the 9 stages of
install.shitself
2.2 install.sh — 9 stages
| # | Stage |
|---|---|
| 1 | OS detection (Rocky/Alma/RHEL/Ubuntu/Debian) |
| 2 | Docker installation (dnf or apt) |
| 3 | Create /data1, /etc/kopens, /var/log/kopens directories |
| 4 | sysctl + firewalld ports + chrony + hostname + nmcli static IP |
| 5 | Generate /etc/kopens/app.properties (EDGE_ID / SITE_ID / per-box random credentials) |
| 6 | Install systemd units — plantpulse-edge.service + OTA kopens-upgrade.path/.service |
| 7 | docker pull (cosign signature verification — soft-fail by default) |
| 8 | systemctl enable --now plantpulse-edge.service |
| 9 | Register weekly cron cleanup |
On first installation, the admin / MQTT / OPC-UA / API key / keystore passwords are generated randomly per box and saved once to /etc/kopens/credentials.txt (chmod 0600 root).
3. PROFILE Presets
The PROFILE env applies a set of defaults for each site type in one shot.
| PROFILE | Applied defaults |
|---|---|
production | DEV_MODE=EDGE (platform SERVER_HOST/SERVER_API_KEY must be specified) |
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 (no platform connection) |
airgap | IMAGE_URL=tarball, SKIP_PULL=1, DEV_MODE=STANDALONE (Offline 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
A staging box is a clone of dev with the same EDGE_00303 / SITE_00001. The only things that must differ are the platform connection details (SERVER_HOST=192.168.0.235 / API key). Using a site that is not registered on the platform makes the edge self-diagnostic OPC fail with an FK violation, so use the registered EDGE/site as-is.
If it connects to the platform at the same time as dev, both are recognized as the same edge, so schedule validation runs so they do not overlap.
For the full list of env vars commonly used at install time, see env Configuration §6.
4. Anatomy of the systemd unit — plantpulse-edge.service
This is the actual container startup definition that install.sh places at /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 exposes all 9 ports + makes multicast / OPC-UA discovery work naturally |
--init | tini runs as PID 1 (zombie reaping + signal forwarding) |
--stop-timeout=120 | Allows time for a graceful Cassandra drain |
--cap-drop=ALL + individual --cap-add | Least privilege. NET_RAW is for PLC ping, NET_BIND_SERVICE for binding 80/443 |
4.2 Bind mounts
| 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 time zone |
/var/run/docker.sock | /var/run/docker.sock | rw | /ui/apps Docker app management |
4.3 EnvironmentFile + defaults
Defaults built into the unit (when no file is present):
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 when present — latest value wins):
| File | Key | Created by |
|---|---|---|
/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 the heap-reduction override (drop-in) for 8GB boxes, see Container Mode §Resource Limits.
5. Container Runtime Configuration Read Paths
In WAR mode (from 2026-06-13), configuration is 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: the host's
/etc/kopens/app.propertiesis the source of truth. If absent, the entrypoint seeds it from the image default. Operator edits → applied viaconfig.sh --restart. - log4j2.xml: the entrypoint copies it from the webapp default to
conf/log4j2.xmlon every boot (build artifact — change the log level and restart, no image rebuild needed). - HiveMQ auth.properties: the entrypoint auto-syncs it with
mqtt.server.*inapp.propertieson every boot — you only need to editapp.properties. - TLS passwords: the entrypoint resolves
CERT_PASSfromcert.envand patches the Tomcatserver.xml/ HiveMQ config / OPC-UA keystore passwords in one pass.
For details on env→configuration mirroring, see env Configuration; for the meaning of each key, see the app.properties Guide.
6. OTA Upgrade / Rollback
The version is pinned by a single PE_VERSION line in /etc/kopens/version.env — OTA only changes this file and restarts.
# 최신으로 업그레이드 (pre-snapshot → pull → restart → 90초 health probe → 실패 시 auto-rollback)
sudo bash /opt/kopens/install/upgrade.sh
# 특정 tag 로
sudo bash /opt/kopens/install/upgrade.sh --to 2026-20260601
# 직전 tag 로 rollback
sudo bash /opt/kopens/install/upgrade.sh --rollback
# 새 빌드 존재만 확인
sudo bash /opt/kopens/install/upgrade.sh --check
Manual rollback:
echo 'PE_VERSION=2026-20260524' > /etc/kopens/version.env
sudo systemctl restart plantpulse-edge.service
Status: cat /etc/kopens/upgrade.status → idle | running | success | rolling-back | rolled-back | error.
For the detailed flow, see Container Mode §OTA.
7. Manual docker run for Debugging
Operations must always go through systemd / install.sh, but for isolated debugging you can start it manually:
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>
Deployment goes through the pipeline only — do not (re)build / push the image or redeploy staging locally; use the release chain in
plantpulse-edge-docker(edge:libs→edge:deploy-dev→edge:image→edge:staging→edge:version, triggered by the pipeline variableRELEASE=1). The command above 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 symptom-based remedies see Installation Troubleshooting; for day-to-day operation and failures see the Container Mode Operations Guide.
9. Next Documents
- Quick Install (
install.sh) — summary of the field single-box installation procedure - env Configuration —
PROFILE/PP_LANG/CERT_PASS/-Dpe.conf.dir - Native Installation — direct installation without a container (dev/legacy)
- Container Mode Operations Guide — pe-* tools / logs / failure response
- Offline / Air-gapped Installation / Production Line (
factory.sh) - Production Readiness Criteria