How to Change Settings
What you need to change determines which file you edit and how the change takes effect. First, find your case in the table below.
The data lake re-renders its configuration at every startup. It reads the templates in plantpulse-datalake-cli/config/templates/, populates ${PP_*}, and then overwrites the configuration locations for each component (such as plantpulse-storage/db/cassandra/conf/cassandra.yaml). Which template goes where is documented on a single page in config/render.map.
Therefore, even if you open and edit cassandra.yaml · postgresql.conf · kafka.properties, they will revert at the next pd start. The place to edit is the template.
# ❌ 이렇게 고치면 다음 기동에 사라진다
vi /opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/conf/cassandra.yaml
# ✅ 템플릿을 고친다 — 호스트의 /etc/kopens/conf 가 템플릿 자리로 마운트돼 있다
vi /etc/kopens/conf/cassandra.yaml.template
docker exec plantpulse-datalake pd config render # 렌더해 보고
docker exec plantpulse-datalake pd config diff # 「지금 도는 설정」과의 차이 (0 = 같다)
docker exec plantpulse-datalake pd restart storage # 해당 서비스만 재시작
If pd config diff is not 0, it means the runtime files differ from the template — either someone edited them directly, or the render hasn't been completed yet.
| What you want to change | Example | Where to edit | How it takes effect |
|---|---|---|---|
| Passwords · API keys | PostgreSQL password, CEP API key | bin/passwd.sh | The tool does the restart for you |
| This box's address · identity | The address other boxes connect to, Kafka advertised address, NAT public IP | /etc/kopens/platform.node.env | bin/restart-datalake.sh |
| Non-secret values common to all nodes | Language · timezone, backup schedule switch, console log endpoint | /etc/kopens/plantpulse-platform.env | bin/restart-datalake.sh |
| Container resources | Data lake memory limit | /etc/kopens/platform.node.env (DOCKER_DATALAKE_MEMORY) | bin/restart-datalake.sh |
| A "line" in engine settings | postgresql.conf parameters, Kafka retention period, Aster TSDB heap | /etc/kopens/conf/<파일>.template | bin/restart-datalake.sh or, inside the container, pd config render + pd restart <서비스> |
| Backup schedule | Nightly backup time | pd backup schedule set inside the container | Immediately |
| Public ports | Ports opened on the host | compose/docker-compose.yml | bin/restart-datalake.sh — Caution |
cd /opt/kopens/plantpulse-platform-docker/bin
./status.sh # 0 = 정상
docker exec plantpulse-datalake pd config diff # 런타임 파일 = 렌더 결과인가 (0 = 같다)
docker exec plantpulse-datalake pd doctor # FAIL 0
1. Passwords · API keys
Don't open a file. passwd.sh handles the server-side account change → sidecar update → configuration re-render → restart in a single command.
cd /opt/kopens/plantpulse-platform-docker
bin/passwd.sh --list # 바꿀 수 있는 키
bin/passwd.sh PP_PG_PASSWORD # 값은 프롬프트로 (권장)
For details, see Changing Passwords · API Keys.
2. Node file — This box's address and identity
/etc/kopens/platform.node.env is a file for values that are true only for this box. Do not copy it to another box — once, a box that had copied another box's file was silently reinstalled with the wrong role.
| Variable | When to set it | If left empty |
|---|---|---|
PP_MASTER_IP | When other boxes (edge, AI, worker) need to connect to this data lake — this host's LAN address | The address within the compose network (10.99.0.100) — works only within this box |
PP_KAFKA_ADVERTISED_HOST | Only when behind NAT or connecting to Kafka via a second interface | The tool will guide you at startup (operator value > PP_MASTER_IP > host's default IP). Usually leave it empty |
DOCKER_PP_EXTERNAL_IP | Public IP in a NAT environment. It goes into the TLS certificate SAN | Leave it empty — if you enter a wrong IP, no certificates will be generated at all |
PP_NODE_ID | When there are multiple boxes, this box's short, unique name | Derived from the container hostname — if there are two boxes, they'll push each other out. Set this before you add a second box |
sudo vi /etc/kopens/platform.node.env
# PP_MASTER_IP=192.168.10.20
cd /opt/kopens/plantpulse-platform-docker/bin
./restart-datalake.sh # 데이터레이크만 재생성 + 준비 대기 + 의존 앱 판정
127.0.0.1, the render is rejected (exit 8)If the address a server gives clients to "reconnect here" (Kafka advertised.listeners, Aster TSDB broadcast_rpc_address, Temporal broadcastAddress) is a loopback, the server is fine in place, but every other container will connect to itself. You'll see all port checks UP, yet clients can't connect. The error message tells you which name to fix — it's PP_HOST_IP · PP_MASTER_IP · PP_KAFKA_ADVERTISED_HOST in the node file.
3. Sidecar — Non-secret values common to all nodes
The sidecar /etc/kopens/plantpulse-platform.env is not just for secrets. Non-secret common values can also be added as a single line VAR=값, and bin/env.sh will read it and pass it to compose. Which variables are available is fully documented with comments in compose/platform.env.example — pick the lines from there and copy them over.
Frequently used ones:
| Variable | Default | Meaning |
|---|---|---|
PP_LANG | en | For Korean operation, set to ko |
PP_TZ | Asia/Seoul | Time series are stored as epoch in this timezone, so keep it for Korean operation |
PP_BACKUP_SCHEDULE_ENABLED | true | If false, all five backup timers just record "skipped" and do nothing |
PP_DATALAKE_ADMIN_LOGS_ENABLED | true | If false, only the console's log screen (endpoint) goes down |
PP_KEYSPACE · PP_DB_NAME · PP_TOPIC_PREFIX | pp | Identifiers that the data lake "creates" and the app "reads." Don't change them after installation |
sudo vi /etc/kopens/plantpulse-platform.env
# PP_LANG=ko
cd /opt/kopens/plantpulse-platform-docker/bin
./restart.sh # 언어 · 타임존은 앱에도 닿으므로 전체 재시작
# generated: and # last rotation: are managed by the tool. The rest of the lines can be VAR=값. Old export VAR=값 lines are still read, but will be rewritten in the new format at the next update.
4. Container memory
The memory limit of the data lake container is DOCKER_DATALAKE_MEMORY. The default is 96G, and that is the minimum — 64G is not a supported size. It is capped at 90% of host RAM, so a host with less than 107G cannot give it 96G and is below spec (System Requirements). To raise it, put it in the node file.
sudo vi /etc/kopens/platform.node.env
# DOCKER_DATALAKE_MEMORY=128g
cd /opt/kopens/plantpulse-platform-docker/bin
./restart-datalake.sh
PID 1 inside the container is systemd, so only the Java process gets OOM-killed in the cgroup, and docker ps keeps showing Up. The kill record is only in the host's dmesg. This actually happened on 2026-09-04 with a 64g limit (measured peak 63.9G), and the default was raised to 80G. It was raised again to 96G on 2026-10-04. On 2026-10-29 the container hit the 96G limit and Kafka went down with a memory allocation failure (ENOMEM) — do not lower it below 96G.
dmesg -T | grep -i "memory cgroup"
docker inspect plantpulse-datalake --format '{{.State.OOMKilled}}'
5. Engine configuration "lines" — Templates
When you're changing lines, not values — like adding a parameter to postgresql.conf or changing Kafka's retention period — edit the host template. Which template becomes which file is listed in Template List.
# 1. 호스트에서 템플릿 편집
sudo vi /etc/kopens/conf/postgresql.conf.template
# 2-a. 데이터레이크 전체 재시작 — 기동 때 자동 렌더
cd /opt/kopens/plantpulse-platform-docker/bin
./restart-datalake.sh
# 2-b. 또는 서비스 하나만 — 컨테이너 안에서
docker exec plantpulse-datalake pd config diff # 무엇이 바뀔지 먼저 본다
docker exec plantpulse-datalake pd config render # 생성물을 실제로 쓴다
docker exec plantpulse-datalake pd restart storage # 그 서비스만 재기동
# 3. 확인
docker exec plantpulse-datalake pd config diff # 0 = 런타임이 렌더 결과와 같다
Just typing pd config render and not restarting is not "applied." The file has only changed. pd restart <서비스> completes the set.
When an image ships new defaults — 3-way seed
/etc/kopens/conf are host files, so they won't change automatically even if the image brings new defaults. Therefore, the startup tool compares sets per file at each deployment — the current image's defaults, the last deployment's defaults (/etc/kopens/conf.dist), and the host file.
| Case | What the tool does |
|---|---|
| File untouched by operator, default changed | Replace with the new default |
| File modified by operator, default also changed | Keep the operator file + [WARN] operator edit kept, but THE IMAGE DEFAULT CHANGED + print the diff of default changes |
| File modified by operator, default unchanged | Keep (silently) |
| Image has a new template | Install it |
| Image removes a template | Keep the host file and warn |
In the output of restart.sh · update.sh, if you see the [WARN] operator edit kept line, you need to manually merge your edits with the new defaults. The same line tells you where the new default file is.
You can see how your template differs from the image default inside the container.
docker exec plantpulse-datalake pd config diff --templates
# same — 같다
# differs — 호스트 사본이 다르다 (렌더는 이쪽을 쓴다)
# local — 운영자가 추가한 파일
# missing — 이미지엔 있는데 호스트엔 없다
To revert the host directory entirely to the image defaults (the tool keeps a backup in /etc/kopens/conf.backup/<시각>/):
cd /opt/kopens/plantpulse-platform-docker/bin
TEMPLATE_FORCE_SEED=1 ./restart-datalake.sh
6. Backup schedule
No file editing. Inside the container, pd backup schedule set writes a Quartz cron into the backup_schedule table of the datalake DB — it's the scheduler in plantpulse-datalake-admin-api that reads and executes that table. The "Schedule editor" on the backup screen of the admin console issues the same command.
docker exec plantpulse-datalake pd backup schedule # 지금 일정
docker exec plantpulse-datalake pd backup schedule set --job postgres-diff --calendar "*-*-* 02:45:00"
docker exec plantpulse-datalake pd backup schedule set --job purge --enabled false
docker exec plantpulse-datalake pd backup schedule reset --job postgres-diff # 기본값으로
The five job names are postgres-diff · postgres-full · cassandra-diff · cassandra-full · purge. The calendar follows systemd syntax (*-*-* 02:45:00 daily, Sun *-*-* 01:00:00 Sunday). An invalid expression is rejected without writing anything. Your selection persists in /data1/pp-data/backup/schedule.json, so it survives container recreation → Backup · Restore
7. Public ports
The ports opened on the host are determined by the plantpulse-datalake service ports: in compose/docker-compose.yml. When changing them, consider two things.
- The port that listens inside the container is defined by
defaults.env(PP_*_PORT) and the template. If you only change the published port, you get a mismatch like "the container binds to 6379, while compose publishes 6399." You must look at both together. 1883/1884(MQTT) are published by the proxy container, not the data lake. If you add the same port to the data lake, startup will fail due to a bind conflict.
See Ports and Services Management for the full port list and firewall.
When changes don't take effect — check in order
| Check | What to look for |
|---|---|
| ① Which file wins | The # source: column in bin/env.sh --print. Node file > Sidecar > Shell > Defaults |
| ② Does the name reach the container? | Names not written by compose won't get in → Variable Reference |
| ③ Did you recreate the container? | Sidecar and node file values are only applied at container recreation. docker restart won't work — use restart-datalake.sh |
| ④ Was it rendered? | Is pd config diff 0? If it's 1, restart after pd config render |
| ⑤ Is it a password? | File editing won't change it → passwd.sh |
| ⑥ Is the template stale? | differs · missing in pd config diff --templates → see 3-way seed above |
Don't do this
- Don't edit
PP_HOME/…/conf/*inside the container. It will disappear at the next startup, and until it does, no one knows which one is the real one. - Don't try to apply value changes with
docker restart plantpulse-datalake. Environment variables are set when the container is recreated.restart-datalake.shdoes that job. - Don't use
FORCE=1 pd start. It will start another instance on the same port on top of a live process. - Don't change
PP_KEYSPACE·PP_DB_NAME·PP_TOPIC_PREFIXafter installation. A new empty repository will be created under the new name, and the old data will remain under the old name.