Files
AriWeb-Suite/docs/HAL-AGENT.md
T

7.0 KiB

HAL ↔ Node Agent 프로토콜·설치·운영 (v0.1.1)

Dev-Order §5(아키텍처)·§28·§29·§32·§33·§34 의 백엔드 구현. 코드: hal/, agent/, deploy/, scripts/release.mjs, portal/hal/client.mjs.

1. 구성

구성요소 위치 역할
HAL /srv/ariweb/hal/current, 127.0.0.1:8900, nginx hal.ariweb.net 서버·Agent 등록부, 릴리스 등록부, 내구성 작업 엔진(lib/jobs), 모듈 배포, 포털 API, 운영자 API, 긴급 복구, 재해복구, 공개 상태
Node Agent /srv/ariweb/agent/current, 유닛 ariweb-agent heartbeat(30초, 지표·모듈 버전·시계 차이), 작업 long-poll·실행(단계 저장·재개), 모듈 설치, 사이트 배포·백업·이전
External Pull Agent 고객 외부 서버, 같은 코드 --external --site <id> site.deploy / site.remove / site.check / site.rollback 만, 사이트 하나에 귀속

2. 인증

  • Agent·포털·HAL 간 모든 요청은 lib/serviceauth HMAC: X-Service-Key-Id(agent:<id> / portal / hal), X-Service-Ts(±5분), X-Service-Sign.
  • Agent 비밀은 등록 응답에서 한 번만 전달되어 Agent 보관소(data/vault.json, 키 agent-secret)에, HAL 쪽은 service:agent:<id> 로 보관. 표에는 해시만.
  • 큰 전송(POST /agent/v1/transfers/:id)은 빈 본문 서명 + X-Transfer-Sha256 헤더, HAL 이 받은 뒤 해시를 다시 계산해 비교.

3. Agent 프로토콜(/agent/v1)

경로 설명
GET install.sh 설치 스크립트(deploy/agent-install.sh)
GET bootstrap-artifact?module=agent&version= + X-Registration-Token 등록 전 Agent 코드 내려받기(유효 토큰 확인, 소비하지 않음)
POST register {token, facts, version} 일회용 토큰(10분) → {agentId, secret(1회), serverId, kind, siteId}
POST heartbeat {version, metrics, modules, clockSkewMs, facts, sitesHosted} 지표 저장(90일+), 서버 last_seen·용량·모듈 실제 버전 갱신. 90초 무응답 → offline
GET jobs/next?wait=25 long-poll. {job:{id, kind, payload, halJobId}} 또는 null
GET jobs/unfinished 재시작 뒤 이어서 할 running 작업 목록
POST jobs/:id/progress {progress, steps, log} → {cancelRequested} / POST jobs/:id/result {status: done|failed|needs_user, result, error, errorCode, userMessage}
GET releases/:version/artifact?module= tar.gz 스트리밍, X-Sha256
POST/GET transfers/:id HAL 경유 파일 전송(이전·원격 백업), 24시간 보관

4. 포털 API(/portal/v1, 키 portal) — docs/HAL-JOBS.md

부트스트랩이 끝나기 전에는 health 외 503 bootstrap_incomplete. 작업 상태 변화는 outbox 를 통해 포털 POST /internal/hal-events 로 밀린다(실패 시 지수 백오프, 7일 보관).

5. 작업 모델

  • HAL 작업(lib/jobs) 한 개가 Agent 작업(agent_jobs) 하나 이상을 배정하고 결과를 기다린다(core.awaitAgentJob: 진행률 반영, 취소 전달, Agent 10분 무응답 → 사용자 확인 필요).
  • 복합 작업: backup.create(생성 → 저장 서버로 복사 → 검증), backup.restore(가져오기 → 보호 시점 → 격리 확인 → 복원 → 외부 확인, 되돌리기 지원), site.relocate(precheck → prepare → precopy → verify_copy → final_sync → verify_new → switch → external_check → cleanup; verify_new 실패 시 전환하지 않음, 되돌리기 지원).
  • 운영자 작업: module.deploy/module.rollback/module.health/module.reconcile 은 서버마다 자식 작업(module.deploy.target)을 만들고 childrenSummary 로 대상별 성공·실패·대기를 보인다. 일부 실패는 partial_failure 로 끝난다.
  • 배포 순서(§32.2): 릴리스 승인 → HAL 자체 건강 → 부트스트랩 완료 → hal 모듈이 그 릴리스로 실행 중일 때만 다른 모듈 배포(hal_first).

6. 설치(부트스트랩)와 첫 Agent

# 작업 PC: main 에 병합된 커밋에서
node scripts/release.mjs build            # dist/0.1.1/*.tar.gz + manifest.json (테스트 통과 필요)
scp -r dist/0.1.1 hostinger:/tmp/ariweb-dist
# 대상 서버(ariweb.net 호스트, master, sudo):
bash /tmp/ariweb-dist/… (artifact 안의 deploy/bootstrap-hal.sh) --dist /tmp/ariweb-dist --host hal.ariweb.net --cert /etc/letsencrypt/live/wh-wild-ariweb.net

부트스트랩은 HAL 설치·보관소·유닛·nginx·릴리스 등록(승인)·운영자 설정 토큰까지만 한다. 이어서 운영자 계정 생성 → 서버 생성·등록 토큰 → agent-install.sh → 서버 승인. 첫 Agent 승인 시 bootstrap_state.completed_at 이 기록되고 수동 설치가 잠긴다. 그 뒤 portal·webmaker·arimail 은 운영자 API POST /ops/api/modules/<name>/deploy {version, serverIds} 로 배포한다.

도입 모듈 배치: Agent facts 가 서버의 기존 유닛(webmaker, arihakdang-mail/arimail/heart-mail)과 WorkingDirectory 를 읽어 그 appDir(/srv/webmaker, /srv/arihakdang-mail …)의 releases/<ver> 에 풀고 current 를 바꾼다. Webmaker 는 원본 remote-update.sh 순서(데이터 백업 → 교체 → 재시작 → unit-check), AriMail 은 원본 deploy.sh 순서(DB 백업 → 교체 → db-migrate → 재시작 → health → haraka 재시작)를 Agent 가 수행한다.

7. 운영자 접근(§25)

/ops/* 는 허용 CIDR(config.opsAllowCidrs) 안이거나 접근권 쿠키(aw_ops_grant, 사용자·기기 귀속, 최대 72시간)가 있어야 하며 아니면 로그인 화면도 403. 접근권: node hal/index.mjs grant --login <id> --hours 8 또는 허용 네트워크 안의 운영자가 POST /ops/api/access-grants. 고위험 작업은 재인증(10분)과 3단계 확인(confirmImpact, confirmIdentifiers, confirmExecute).

8. 긴급 복구(§33)·재해복구(§34)

  • POST /ops/api/emergency 선언(HAL 정상이고 열린 critical 사건이 없으면 거부) → approve 1·2·3단계(서로 다른 입력) → credential(최대 60분, 1회 표시) → perform(허용 범위·허용 행동만; 일반 배포 거부) → verify(자격 폐기) → reconcile(목표·실제 비교) → close.
  • DR: PUT /ops/api/dr/config(RTO·RPO·주기·보존·외부 보관), 사본 POST /ops/api/dr/snapshots(VACUUM INTO + vault.json + config.json, vault.key 제외), 복원 요청→승인→시작(기존 제어 중지 확인 문구)→deploy/hal-restore.sh→완료 확인(운영자 로그인·HAL 제어·HTTPS·고객 서비스), 훈련 기록과 측정 RTO/RPO. readiness.ready 가 true 여야 정식 운영 준비 완료.
  • 하나의 HAL: 기동 때 bootstrap_state.live_instance_id/live_lease_at 임대(20초 갱신, 60초 유효). 다른 인스턴스의 임대가 살아 있으면 기동 거부(--takeover 는 복원 절차에서만).

9. 테스트

node --no-warnings test/hal.test.mjs, node --no-warnings test/agent.test.mjs. Agent 테스트는 ARIWEB_AGENT_STUB_CMDS=1 과 임시 루트로 실제 시스템을 건드리지 않는다.