Kubernetes 安装 (Helm)
PlantPulse 平台有一个 用于在 Kubernetes 上运行的 Helm Chart。
这是什么
这是一个将 Docker Compose 配置 翻译成 Kubernetes 的 Chart,而不是替代方案。
权威版本仍然是 compose。如果两者不一致,以 compose 为准,Chart 是错误的。 新配置会先添加到 compose,Chart 随后跟进。
| Chart 位置 | plantpulse-platform-k8s 仓库中的 charts/plantpulse-platform |
| 镜像仓库 | 平台使用 docker.kopens.io/pp,第三方使用 docker.kopens.io/proxy-dockerhub |
| 验证环境 | k3s v1.32.5+k3s1 · 单节点 |
| 涉及的 compose 服务 | 全部 10 个 |
开始之前
Kubernetes 版本
该操作系统使用 cgroup v1,而 k3s v1.36(Kubernetes 1.36)已移除对 cgroup v1 的支持。 升级后 kubelet 会报如下错误并无法启动。
kubelet is configured to not run on a host using cgroup v1
存储 — 需要 RWX
承载 TLS 材料的 pp-security 卷会被 多个 Pod 同时挂载。因此需要有支持
ReadWriteMany 的 Provisioner — 例如 NFS · CephFS · Longhorn RWX 等。
local-path 仅在单节点时有效local-path 是 RWO 且位于节点本地。在单节点环境下,所有 Pod 都部署在该节点上,
因此可以工作,但 一旦加入第二个节点,就会悄无声息地出问题。 这不是 Chart 的缺陷,而是实际的限制,
在此记录,以免在客户现场部署时才发现。
资源
平台资源需求不会因为使用 Kubernetes 而减少。 请遵循 系统要求 — 最低 16 vCPU · 128GB RAM · 1TB SSD 。
如果没有集群 — K3s → Rancher → Helm
如果您已经使用 Kubernetes,请跳过本节,直接进入 安装。 如果从零开始,则 K3s 创建集群,Rancher 提供界面, 再在其上部署 PlantPulse Chart,这是最短路径。
这是 SUSE 的开源 Kubernetes 管理 UI。可选组件,仅使用 kubectl 也能完全完成
安装和运维。当您想直观查看 Pod·日志·事件时,使用它会很方便,因此一并介绍。
1. 安装 K3s
这是一个单节点集群。安装脚本会一并启动容器运行时 · kubelet · 默认
存储(local-path)。
# Oracle Linux 8.10 은 cgroup v1 이라 v1.32 라인을 고정합니다 (위 경고 참고)
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.32.5+k3s1 sh -
sudo systemctl status k3s # active (running)
sudo k3s kubectl get nodes # STATUS = Ready
要在普通账户下使用 kubectl,请复制 kubeconfig。
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$(id -u):$(id -g)" ~/.kube/config
kubectl get nodes
K3s 使用 6443(API)端口。如果打算加入其他节点,还需要节点之间的 8472/udp(flannel VXLAN) · 10250(kubelet)端口。 平台自身使用的端口见 端口配置 。
2. 安装 Rancher
Rancher 需要证书,因此先部署 cert-manager。
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 1) cert-manager
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set crds.enabled=true
kubectl -n cert-manager rollout status deploy/cert-manager
# 2) Rancher — <호스트> 는 브라우저로 칠 주소입니다
helm install rancher rancher-stable/rancher --namespace cattle-system --create-namespace --set hostname=<호스트> --set bootstrapPassword=<초기비밀번호> --set replicas=1
kubectl -n cattle-system rollout status deploy/rancher
在浏览器中访问 https://<호스트>,使用上面准备的 bootstrapPassword 进行首次登录,
并立即更改密码。登录后,此 K3s 集群会被识别为 local。
Rancher 使用 hostname 创建证书。如果计划用 IP 访问,请将该 IP 直接填入
hostname,并接受浏览器对自签名证书的警告。
3. 安装 PlantPulse
从这里开始,无论是使用 kubectl 还是在 Rancher 界面操作,都是一样的。请严格按照下面的 安装 部分
执行。如果使用 Rancher,也可以将 Chart 仓库注册到 Apps → Charts → Repositories 并通过界面安装,
但处理值文件时,使用 helm 命令更好。
Rancher 真正有用的是安装之后 — 可以在一屏上查看 Pod 的 Init 阶段在哪里等待、 日志显示了什么、事件拒绝了什么。阅读启动顺序时尤其如此。
安装
1. 将机密信息创建为 Secret
Chart 不包含任何一行密码。 values.yaml 中也没有,而且在默认配置下,
Chart 不会创建 Secret — 它只引用已有的 Secret。
权威版本是与 compose 相同的 sidecar 文件。逐字节使用相同内容。
kubectl -n plantpulse create secret generic plantpulse-platform-env \
--from-env-file=/etc/kopens/plantpulse-platform.env
2. 安装
helm install pp charts/plantpulse-platform -n plantpulse --create-namespace
默认仓库(docker.kopens.io/pp · docker.kopens.io/pd)是公开的,外部也可以拉取。
因此,通常安装时不需要 --set。
3. 如果已镜像到私有仓库
helm install pp charts/plantpulse-platform -n plantpulse --create-namespace \
--set global.image.registry=<사설 레지스트리>/pp \
--set global.image.registryDatalake=<사설 레지스트리>/pd \
--set global.image.registryThirdParty=<사설 레지스트리>/proxy-dockerhub \
--set global.imagePullSecrets[0].name=<레지스트리 시크릿>
registryThirdParty只覆盖前面两个镜像会导致 无法拉取用于启动顺序等待的 busybox。这样,依赖它的 Pod 将全部
在 Init:0/1 中永远等待,而这种失败看起来不像仓库问题。
启动顺序 — Kubernetes 不会自动保证
平台有必须遵守的顺序。
certs → datalake → server → batch
→ warehouse · opcua · aasx · ha
server → proxy
Kubernetes 中没有与 compose 的 depends_on 相对应的机制。通常认为可以替代的方案
做的都是其他事情。
| 常用方案 | 实际作用 |
|---|---|
readinessProbe | 阻止流向该 Pod 的流量。无法延迟其他 Pod 的启动 |
StatefulSet | 是同一个 StatefulSet 内部的 Pod 顺序。与其他工作负载无关 |
Helm hook · --wait | 是清单应用的顺序。不是已创建对象的就绪状态 |
因此,Chart 将等待逻辑放在 Kubernetes 真正能阻止的地方 — initContainer。 等待的不是「Pod 是否已启动」,而是 「产出物是否存在」。
Init:0/2 不是故障这表示 Chart 正在运行。请询问它在等待什么。
kubectl -n plantpulse logs <파드> -c wait-for-certs
默认等待超时为 1800 秒,每 5 秒检查一次。超过超时后,等待会结束,kubelet 会 重新启动它 — 目的是让原因保留在 Pod 事件中。如果永远阻塞,则不会留下任何信息。
容器«内部»的顺序,Chart 不会干预。 数据湖内部的启动顺序由
pd 在容器内强制执行。如果 Chart 重新实现它,就会产生两个权威版本并导致分裂。
如果代理返回 502
Docker 网络会转发容器的所有端口,但 Kubernetes Service 只转发 «自己声明的 端口»。 在 compose 中正常的 upstream,在 Kubernetes 中变成 502 的路径就在这里。
Chart 中有一个 Gate 来捕获此问题 — 检查所有代理 upstream 是否指向 «此 Chart 创建的 Service 的、 该 Service 已声明的端口»。
bash hack/run-gates.sh
| Gate | 检查内容 |
|---|---|
gate-render.sh | 渲染结果中的代理 upstream 是否为真实存在的 Service · 端口 |
gate-no-plaintext-secrets.sh | 渲染结果中是否混入了明文机密 |
prove-gates-fail.sh | Gate 是否在«应该失败时确实失败»(Gate 的 Gate) |
在安装前运行并通过。502 的大部分问题会在这里被先行捕获。
节点需要多大
🔴 Chart 声明的 requests 之和就是节点需求。 不足时 Pod 不会启动,而是停留在
Pending 状态 — 这是「看起来安装卡住了」的首要原因。
| 工作负载 | CPU 请求 | 内存请求 | 内存上限 |
|---|---|---|---|
datalake | 8 | 64 Gi | 64 Gi |
server | 2 | 12 Gi | 16 Gi |
batch | 1 | 6 Gi | 8 Gi |
warehouse | 1 | 4 Gi | 8 Gi |
opcua · aasx | 各 0.5 | 各 2 Gi | 各 4 Gi |
ha | 0.5 | 1 Gi | 4 Gi |
proxy | 0.2 | 256 Mi | 1 Gi |
certs | 0.1 | 256 Mi | 1 Gi |
| 合计(默认配置) | 约 14 | 约 92 Gi | — |
仅 datalake 就请求 CPU 8 · 内存 64 Gi(请求与上限相同 —
已设置为 Guaranteed)。如果要部署在单节点上,该节点必须至少具备 CPU 16 ·
内存 128 Gi 的规格。
JVM 堆与 Pod 限制是«分开»声明的
Java 应用套件的堆大小由 Chart 直接传递。它不是从 Pod 限制推导的 — 如果推导,则在降低限制时堆会静默缩小,而实际上镜像内的字面量会覆盖设置,导致无论怎么调整限制, JVM 都不知道。
| 应用 | 堆 | 直接内存 | 相关变量 |
|---|---|---|---|
server | 8g | 4g | PP_SERVER_HEAP · PP_SERVER_DIRECT |
batch | 3g | — | PP_BATCH_HEAP |
warehouse | 1g | — | PP_WAREHOUSE_HEAP |
Chart 在渲染时会断言以下内容。如果违反,安装会立即失败。
힙 + 다이렉트 + 여유(기본 2048Mi) ≤ limits.memory
힙 + 여유 ≤ requests.memory
🔴 只增大堆而不提高 Pod 限制,会导致预触达期间 OOMKill。 -Xms=-Xmx 中
有 AlwaysPreTouch,堆会在启动时立即全部驻留,而此时代码不会留下指向堆的日志行。请同时提高两者。
目前验证到哪个阶段了
验证环境是 k3s v1.32.5+k3s1 · 单节点,并且全部使用真实仓库镜像。
| 组件 | 状态 |
|---|---|
plantpulse-certs | ✅ 就绪。TLS 材料已实际创建在共享卷上 |
plantpulse-datalake | ✅ 通过此 Chart 全新安装,19/19 启动(2026-09-09,2026.09 镜像,删除 PVC 后) |
| 启动顺序等待 | ✅ 已实际验证阻塞和解除 |
server · batch · warehouse · proxy | ⬜ 尚无实际启动记录 — 但 Chart 侧的缺陷仍在持续修复中(2026-09-09:备份卷 · JVM 堆约定 · 代理 upstream) |
opcua · aasx · ha | ⬜ 仅确认到等待状态 |
mirror-maker | 默认关闭(对应 compose 的 mirror profile) |
数据湖 Pod 现在可以无特权启动 — 由于镜像中 systemd 已从 PID 1 移除,
privileged · SYS_ADMIN · cgroup:host 都不再需要。
TOTAL SERVICES : 19 RUNNING / 0 STOPPED
/proc/1/comm : bash # systemd 아님
securityContext: (비어 있음) # privileged·SYS_ADMIN·cgroup 없음
遇到阻塞时
| 症状 | 首先检查 |
|---|---|
Pod 在 Init:0/1 中无进展 | 可能是无法拉取 busybox — 检查 registryThirdParty |
Pod 在 Init:0/2 中等待 | 正常。使用 kubectl logs <파드> -c wait-for-certs 查看它在等待什么 |
| 代理路径返回 502 | bash hack/run-gates.sh — upstream 是否指向真实存在的 Service·端口 |
| 加入第二个节点后出现 TLS 相关错误 | pp-security 不是 RWX |
| 数据仓库控制台的列表始终为空 | Iceberg 相关必需配置为空。空值会导致渲染失败,请查看安装日志 |