양산 라인 설치 (factory.sh)
생산 라인에서 박스 100 ~ 1000 대를 처리할 때 사용. 운영자가 한 화면 prompt 만 채우면 EDGE_ID / hostname / 자격증명 / Docker / cosign verify / 컨테이너 기동까지 자동. 박스당 30 초.
단일 박스 / 현장 설치 (SI 직원) 라면 빠른 설치 (원라인) 페이지를 먼저 보세요. 양산 라인 vs 현장 설치 의 차이는 진입점 만 다르고, 결과는 동일합니다.
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 가 자동으로:
- LAN1 NIC MAC 자동 감지 — MAC 마지막 6 자로
EDGE_<HEX6>생성 (예:EDGE_3F8A21). - 호스트명 동기 —
hostname도edge-<hex6>(RFC 1123, 소문자+하이픈) 로 변경. - 5 필드 prompt — SITE_ID / SERVER_HOST / SERVER_API_KEY / LAN1 NIC / LAN2 NIC.
install.sh위임 — Docker / cosign / random secret / app.properties / 컨테이너 기동.- factory-label.txt 출력 — 박스 부착용. 인쇄 후 봉인.
- factory-inventory.csv append — 라인 끝에서 회수 → 사내 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 은 hardware 에 박혀있어 박스마다 unique 보장
- 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 (silent 중복 방지). 동일 박스를 두 번 provisioning 하거나 MAC 충돌 케이스 자동 검출. - MAC 없는 박스 (가상 NIC 등) —
derive_edge_id_from_mac가 fail → install.sh 가 hostname 기반 fallback. 라인에서는 거의 안 일어남.
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.md 의 비밀번호 / API 키 (Secrets) 절):
| 변수 | 길이 | 위치 |
|---|---|---|
ADMIN_PASS (UI 로그인) | random 14자+! | /etc/kopens/credentials.txt |
API_KEY (REST) | random 16자 | 위 파일 + env.sh.generated |
MQTT_PASS (HiveMQ) | random 14자+! | 위 파일 |
OPCUA_PASS | random 14자+! | 위 파일 |
CERT_PASS (SSL keystore) | random 14자+! | 위 파일 |
/etc/kopens/env.sh.generated (chmod 0600 root) 가 모든 후속 스크립트 (upgrade.sh / restart.sh)
가 source 하는 사이드카 — 재부팅 후에도 동일 자격증명 유지.
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.md 의 이미지 서명 (Cosign) 절 참고.
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 — 라인 회수용
박스마다 한 줄 append. 라인 끝에서 운영자가 회수 → 사내 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
또는 박스가 켜진 시점에 platform 측으로 자동 push 하도록 hook 추가 가능 (Phase 1 — 사내 provisioning REST API 도입 시).
7. 자주 빠지는 함정
| 증상 | 원인 | 대응 |
|---|---|---|
EDGE_ID '...' fails ^EDGE_[A-Z0-9_]{1,60}$ | LAN1 NIC 의 MAC 가 ASCII 가 아닌 가상 NIC | LAN1_IFACE=enp1s0 bash factory.sh 처럼 명시 |
already_in_inventory: EDGE_3F8A21 already provisioned | 같은 박스 재실행 또는 MAC 충돌 | vi /data1/factory-inventory.csv 로 해당 줄 제거 후 재실행. MAC 충돌이면 라인 stop + 보고 |
cosign verify FAILED (COSIGN_REQUIRE=1) | image 가 미서명 OR 잘못된 cosign.pub | 빌드 서버 sign-image.sh 호출 누락 확인, cosign.pub 갱신 |
hostnamectl set-hostname failed | container 안에서 실행 / 권한 없음 | factory.sh 는 root 강제 — sudo bash factory.sh |
| prompt 가 안 보임 (라벨 인쇄 안 됨) | install.sh 가 mid-way 실패 | journalctl -u plantpulse-edge.service -n 50 확인 후 트러블슈팅 |
8. 관련 문서
plantpulse-edge-docker/README.md— 운영 시나리오 (양산 / SI / CI) 절 (배포본에 함께 들어 있습니다)plantpulse-edge-docker/README.md— 이미지 서명 (Cosign) 절 (keypair 생성 · rollout · rotation)- 빠른 설치 (단일 박스, 현장 SI 용)
- 설치 직후 체크리스트
- 폐쇄망 / Airgap 설치