跳到主要内容

量产线安装 (factory.sh)

用于产线上批量处理 100 ~ 1000 台设备。操作员只需在一个界面填完 prompt, EDGE_ID / hostname / 凭据 / Docker / cosign verify / 容器启动即全部自动完成。 每台 30 秒

本页为量产线 SOP

如果是单台设备 / 现场安装(SI 人员),请先阅读 快速安装(一行命令)。 量产线与现场安装的差异仅在于入口,结果完全相同。


0. 一览

sudo -i
mkdir -p /home/kopens
curl -fsSL https://product.kopens.io/plantpulse-edge/plantpulse-edge-docker.tar.gz \
| tar xz -C /home/kopens
cd /home/kopens/plantpulse-edge-docker/bin
sudo bash factory.sh

factory.sh 会自动完成:

  1. LAN1 NIC MAC 自动识别 — 取 MAC 后 6 位生成 EDGE_<HEX6>(例如:EDGE_3F8A21)。
  2. 主机名同步hostname 也一并改为 edge-<hex6>(RFC 1123,小写+连字符)。
  3. 5 个字段的 prompt — SITE_ID / SERVER_HOST / SERVER_API_KEY / LAN1 NIC / LAN2 NIC。
  4. 委派给 install.sh — Docker / cosign / random secret / app.properties / 容器启动。
  5. 输出 factory-label.txt — 用于贴在设备上。打印后封箱。
  6. 追加 factory-inventory.csv — 产线末端回收 → 上传至公司 inventory DB。

1. ID / hostname 自动生成

EDGE_ID — EDGE_<HEX6>

LAN1 NIC eth1 MAC = 00:1a:2b:3f:8a:21
─────
마지막 6 자 (HEX6) = 3F8A21
EDGE_ID = EDGE_3F8A21
hostname = edge-3f8a21

Why MAC?

  • hostname 可能随每次 OS install 变化(cloud-init / hostnamectl),且可能冲突
  • MAC 固化在硬件中,可保证每台设备唯一
  • 24-bit 后 6 位 → 约 1670 万种组合。1000 台量产的冲突概率约 0.003%(按 Birthday paradox 评估是安全的)

强制遵守域规则(产品仓库的 CLAUDE.md):

标识符正则表达式示例
EDGE_ID^EDGE_[A-Z0-9_]{1,60}$EDGE_3F8A21
SITE_ID^SITE_[A-Z0-9_]{1,60}$SITE_FAB1_042
hostname (RFC 1123)小写 + 连字符edge-3f8a21

factory.sh 会先校验上述 regex 再继续 — 未通过则立即 abort。

MAC 冲突 / 无 NIC 的设备

  • 冲突可能性 — 若 /data1/factory-inventory.csv 中已存在相同 EDGE_ID 则立即 abort (防止静默重复)。可自动检出同一台设备被 provisioning 两次或 MAC 冲突的情况。
  • 无 MAC 的设备(虚拟 NIC 等)derive_edge_id_from_mac 失败 → install.sh 回退为基于 hostname 的方式。产线上几乎不会发生。

2. Prompt 的 5 个字段

操作员在产线上输入:

══════════════════════════════════════════════════════════════════════
PlantPulse Edge — Factory Provisioning
══════════════════════════════════════════════════════════════════════
Detected NIC eth1 MAC : 00:1a:2b:3f:8a:21
Auto EDGE_ID : EDGE_3F8A21
Auto hostname : edge-3f8a21
══════════════════════════════════════════════════════════════════════
Site ID (^SITE_[A-Z0-9_]+) [SITE_00001]: SITE_FAB1_042
Platform server host [192.168.0.41]: 10.10.0.5
Platform API key []: kFa7bGz8pQrN3xMv9wT2sLcEjY1uV6oH
LAN1 NIC (PLC) [eth1]: ← Enter = default
LAN2 NIC (WAN) [eth2]: ← Enter = default
══════════════════════════════════════════════════════════════════════
Summary
EDGE_ID : EDGE_3F8A21
hostname : edge-3f8a21
SITE_ID : SITE_FAB1_042
SERVER_HOST : 10.10.0.5
SERVER_API_KEY : kFa7…(32 chars)
LAN1 NIC (PLC) : eth1
LAN2 NIC (WAN) : eth2
══════════════════════════════════════════════════════════════════════
Proceed with install.sh? [y/N]

按下 y 后,install.sh 运行 5 ~ 10 分钟(含首次镜像 pull 3 GB),随后输出标签。


3. 自动生成的凭据 (G2)

install.sh 为每台设备生成不同的 random 密码(详见下载包中的 plantpulse-edge-docker/README.mdSecrets 一节):

变量长度位置
ADMIN_PASS (UI 登录)random 14位+!/etc/kopens/credentials.txt
API_KEY (REST)random 16位上述文件 + env.sh.generated
MQTT_PASS (HiveMQ)random 14位+!上述文件
OPCUA_PASSrandom 14位+!上述文件
CERT_PASS (SSL keystore)random 14位+!上述文件

/etc/kopens/env.sh.generated(chmod 0600 root)是所有后续脚本(upgrade.sh / restart.sh) 都会 source 的 sidecar 文件 — 重启后仍保持相同凭据。


4. 镜像签名 verification (G3)

install.sh 会自动安装 cosign + 部署 cosign.pub,并在 docker pull 之后立即自动 verify。

[install] Installing cosign ...
[install] OK — cosign installed (cosign version 2.4.1)
[install] cosign.pub installed — image verification enabled
[install] docker pull — docker.kopens.io/pe/plantpulse-edge:2026-20260523
[install] OK — Pull complete
[cosign] OK — signature verified for docker.kopens.io/pe/plantpulse-edge:2026-20260523

如果 cosign.pub 仍是 placeholder(运维团队尚未生成 keypair),则仅输出 WARN,安装继续进行。 参见下载包中的 plantpulse-edge-docker/README.mdCosign 一节。


5. 标签 + 库存清单

/etc/kopens/factory-label.txt — 用于贴在设备上

安装结束后会打印到屏幕并保存为 chmod 0600 文件。产线人员用标签打印机打印后封箱:

══════════════════════════════════════════════════════════════════════
PlantPulse Edge — Factory Label
══════════════════════════════════════════════════════════════════════
EDGE_ID : EDGE_3F8A21
hostname : edge-3f8a21
SITE_ID : SITE_FAB1_042
build_date : 2026-05-19 14:25:33
──────────────────────────────────────────────────────────────────────
LAN1 (PLC) : eth1 MAC=00:1a:2b:3f:8a:21
LAN2 (WAN) : eth2 MAC=00:1a:2b:3f:8a:22
──────────────────────────────────────────────────────────────────────
UI admin : admin / aBcD1234EfGh!
REST API : kFa7bGz8pQrN3xMv9wT2sLcEjY1uV6oH
(full credentials → /etc/kopens/credentials.txt — root only)
══════════════════════════════════════════════════════════════════════

/data1/factory-inventory.csv — 用于产线回收

每台设备追加一行。产线末端由操作员回收 → 上传至公司 inventory DB:

edge_id,hostname,site_id,server_host,lan1_iface,lan1_mac,lan2_iface,lan2_mac,build_date,iso8601
EDGE_3F8A21,edge-3f8a21,SITE_FAB1_042,10.10.0.5,eth1,00:1a:2b:3f:8a:21,eth2,00:1a:2b:3f:8a:22,2026-05-19 14:25:33,2026-05-19T05:25:33Z
EDGE_5B7C03,edge-5b7c03,SITE_FAB1_043,10.10.0.5,eth1,00:1a:2b:5b:7c:03,eth2,00:1a:2b:5b:7c:04,2026-05-19 14:28:12,2026-05-19T05:28:12Z

6. 产线末端批量回收

# 라인 마지막 박스 처리 후 회수 워크스테이션에서
scp root@edge-3f8a21:/data1/factory-inventory.csv ./inventory-line1-$(date +%F).csv

# 회수한 CSV 들을 사내 inventory DB 로 업로드 (예: scripts/import-inventory.py)
python3 import-inventory.py inventory-line1-2026-05-19.csv

也可以添加 hook,在设备上电时自动 push 到 platform 侧(Phase 1 — 引入公司内部 provisioning REST API 时)。


7. 常见陷阱

现象原因处理
EDGE_ID '...' fails ^EDGE_[A-Z0-9_]{1,60}$LAN1 NIC 的 MAC 非 ASCII 的虚拟 NICLAN1_IFACE=enp1s0 bash factory.sh 一样显式指定
already_in_inventory: EDGE_3F8A21 already provisioned同一台设备重复执行或 MAC 冲突vi /data1/factory-inventory.csv 删除对应行后重新执行。若为 MAC 冲突则停线并上报
cosign verify FAILED (COSIGN_REQUIRE=1)image 未签名 或 cosign.pub 错误确认构建服务器是否漏调用 sign-image.sh,并更新 cosign.pub
hostnamectl set-hostname failed在 container 内执行 / 无权限factory.sh 强制 root — sudo bash factory.sh
看不到 prompt(标签未打印)install.sh 中途失败确认 journalctl -u plantpulse-edge.service -n 50 后参见故障排查

8. 相关文档