포털·hostinger Node Agent 제어 평면 이전(hal.ariweb.net → hal21.ariweb.net) 실제 적용 기록: docs/verification/portal-hal21-link-2026-10-27.md(리비전·preflight·백업 sha256·link-portal 파이프·HAL21 작업 배포·readback·전후 집계·blocker), RUNBOOK §10, VERSION_HISTORY

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
zzabisagent-lab
2026-10-27 09:43:36 +00:00
co-authored by Claude Fable 5.1
parent dfb708e933
commit d8e7beeb86
3 changed files with 84 additions and 0 deletions
+23
View File
@@ -121,3 +121,26 @@ node hal/index.mjs server-token --server <srv_id> --by hera # 1회 표시
```
되돌리기: `node hal/index.mjs mail-import-rollback --import <mimp_id>`(그 적용이 만든 행 삭제·갱신 행 복원), 서버 행은 운영자 콘솔 서버 삭제(3단계 확인). Agent 는 `systemctl disable --now ariweb-agent` + `/srv/ariweb/agent` 제거(메일 서비스 영향 없음). 원본 메일 데이터 복원은 각 백업의 RESTORE.md(운영자 승인 뒤에만 — 메일 중단 동반).
hostinger 주의: `arihakdang-mail` 은 hostinger HAL(`hal.ariweb.net`)의 `module_targets.arimail` 로도 관리된다. hal21 에 같은 호스트의 두 번째 Agent 를 설치하면 두 제어 평면이 같은 유닛에 배포할 수 있으므로(§34 "하나의 HAL") **설치하지 않고** 서버 행을 pending(Agent 미연결)으로 두었다 — 제어 평면 이전은 사람 결정.
## 10. 포털·Node Agent 제어 평면 이전 — hostinger HAL(hal.ariweb.net) → bear HAL21 (2026-10-27)
전제: 포털은 hostinger 에서 이미 active(신규 초기화·빈 DB 생성 금지), Agent 는 한 HAL 에만 연결(단일 제어 평면), 비밀값은 파이프로만 이동. 기록: `docs/verification/portal-hal21-link-2026-10-27.md`.
```bash
# 0) 읽기 전용 preflight: DNS(공개·권한 resolver)·TLS·login·/api/health, 유닛 PID/NRestarts/cwd/REVISION/리스너, Agent 의 halUrl(agent.json 의 비밀 아닌 값), 포털 config 값·vault 이름, DB integrity/집계, 구 HAL·HAL21 의 servers/agents/jobs/module_targets
# 1) 사설 백업(각 호스트, root 0700/0600, RESTORE.md 먼저): 포털 DB VACUUM 사본(+wal/shm 크기 기록)·vault·config·유닛·nginx·cert 메타·Agent data·구 HAL DB/config, HAL21 DB/config/release — SHA256SUMS·stage 추출 readback·복원 경로 존재 검증
# 2) HAL21(bear, HAL 데이터 소유자): main 릴리스 artifact 등록·승인, 포털 주소 설정(재시작 필요), current 전환
cd /srv/ariweb/hal/releases/0.1.1-<commit12> && export ARIWEB_HAL_DATA=/srv/ariweb/hal/data
node hal/index.mjs register-release --manifest <dist>/manifest.json --approve --by <who>
node hal/index.mjs bootstrap-release --version 0.1.1 --commit <sha> --sha256 <hal artifact sha>
node hal/index.mjs config-set --portalUrl https://my.ariweb.net --by <who> --reason '…' # 포털이 다른 호스트일 때
ln -sfn $PWD /srv/ariweb/hal/current && sudo systemctl restart ariweb-hal && curl -s http://127.0.0.1:8900/api/health
# 3) 포털 연동 키: 값을 화면에 두지 않고 host-to-host 파이프로 포털 vault 에 넣는다(service:hal 하나 — 포털은 양방향에 같은 이름을 쓴다)
ssh bear 'cd /srv/ariweb/hal/current && ARIWEB_HAL_DATA=/srv/ariweb/hal/data node hal/index.mjs link-portal | sed -n "s/^ service:hal = //p"' \
| ssh hostinger 'node -e "let s=\"\";process.stdin.on(\"data\",c=>s+=c).on(\"end\",async()=>{const m=await import(\"/srv/ariweb/portal/current/lib/vault.mjs\");m.openVault(\"/srv/ariweb/portal/data\").set(\"service:hal\",s.trim(),{kind:\"service-key\"})})"'
# 4) 포털 주소(비밀 아님): portal/config.mjs 의 set 으로 config.json 기록(0600, 원자적). 포털은 기동 때 읽으므로 다음 단계의 재배포(재시작)로 반영된다
ARIWEB_PORTAL_DATA=/srv/ariweb/portal/data node -e "import('/srv/ariweb/portal/current/portal/config.mjs').then(m=>m.loadConfig().set({publicUrl:'https://my.ariweb.net',halUrl:'https://hal21.ariweb.net'},'cli:<who>'))"
# 5) HAL21 작업으로 portal 재배포(같은 0.1.1 이면 Agent 가 현재 릴리스를 <ver>.prev-<시각> 으로 보존하고 health 실패 시 자동 복귀). 실행은 ariweb-hal 서비스가 맡는다
node hal/index.mjs module-deploy --module portal --version 0.1.1 --servers <srv_id> --by <who> --reason '…' # → jobId
node hal/index.mjs job --id <j_id> # status done, children[].steps await.result.actualVersion/previousVersion/health
# 6) readback: module_targets.portal target=actual=0.1.1 health ok · 포털의 실제 client+config+vault 로 /portal/v1/health·servers·jobs 계약 · bear nginx access log 의 포털 요청 200 · 포털 DB 집계·Webmaker 인벤토리 전후 비교 · 외부 URL/TLS · 유닛/NRestarts/journal
```
주의: 포털 vault 교체와 포털 재시작 사이(수 초)에는 포털→HAL 호출이 인증 실패한다(화면은 '정보 확인 지연'). 서버 행의 role 이 `mail` 이면 `pickServer(web)` 이 null 이라 포털 사이트 배포 대상이 없다 — 운영자 콘솔에서 role 을 control 로 바꾼다(운영자 API 만 있음). 구 HAL 은 Agent 가 떠나면 server offline 으로 남는다; 중지·폐기는 사람 결정.