Files
pangolin/server/internal/provision/doc.go
wangjia 3d5bac66b4 feat(provision): 弹性节点基建 Terraform + 一键更换 (tsk_6u0FxmbC7Yeq)
IaC 面 (infra/) 与控制面 (server/internal/provision) 双产出,落地 doc/04 §4
「节点是牲口」弹性拓扑与 make-before-break 一键更换。

server/internal/provision:
- CloudAdapter 适配层 + Registry(首发 vultr 消耗品池 / hetzner 精品池各一);
  厂商凭证仅从 PROVISION_<VENDOR>_* env 注入,不入库不入 git。
- ProvisionService:CreateNode(幂等键重放不重复开机)、DestroyNode(幂等)、
  RotateIP(换 IP 不换机 + version bump)、ListProviders。
- Replace 一键更换:先建后拆,新机 up 先于旧机 draining(容量不下降),
  replacement_uuid 幂等键 + replacements 表分步记录,崩溃可续跑不重复。
- RotatePool:池内滚动轮换,并发度 1–2。
- cmd/nodectl CLI:create/destroy/rotate-ip/replace/rotate-pool/providers。
- 单测(mock 厂商 API + 内存 Store):幂等重放、make-before-break 时序断言、
  开机失败/探活超时→destroyed+失败计数+告警钩子、崩溃续跑、RotatePool。

infra/:
- terraform/:探针机 + 控制面基线模块化(probe / control-plane)+ README,
  低频基线进 state,节点不进 Terraform。
- cloud-init/node.yaml.tmpl:节点引导模板(注入一次性 bootstrap token,task #5)。
- identity-isolation.md:身份隔离登记表(doc/06 §2 红线,无任何凭证)。

migrations/000008:nodes 增 provider_instance_id/elastic_ip_id、node_events
增 ip_rotated、provision_idempotency / replacements 表(附加式,不动现网)。

红线:仅面向新厂商池,绝不纳管现网生产 EC2(deploy/ marzban)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:23:39 +08:00

32 lines
1.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package provision owns the elastic-node control plane: it turns the
// "nodes are cattle, not pets" principle (doc/04 §2) into running code.
//
// Responsibility split (doc/04 §4):
//
// - Terraform (infra/terraform) manages low-frequency baseline resources:
// probe machines and the control-plane environment. Those live in
// Terraform state.
// - This package drives high-frequency, minute-scale node lifecycle through
// vendor APIs. Disposable nodes are NOT in Terraform state.
//
// The package exposes a ProvisionService with idempotent operations:
//
// - CreateNode — insert nodes(status=provisioning) → vendor API boot →
// render cloud-init (injecting a one-time bootstrap token, task #5) →
// return. The agent self-registers (task #6) and flips the node to up.
// - DestroyNode — vendor destroy + IP release + nodes→destroyed.
// - RotateIP — swap the elastic IP without re-creating the machine
// (change IP, keep the box), then bump the directory version.
// - Replace — make-before-break one-click replacement: bring a fresh
// node up BEFORE draining/destroying the old one, so capacity never dips.
// - RotatePool — rolling Replace across a whole pool, concurrency 12.
//
// Vendor adapters live in providers/ behind the CloudAdapter interface.
// Vendor credentials are injected ONLY from independent secrets (env/file) —
// never stored in the database and never committed to git. The providers table
// holds just name/api_kind/regions/pool/enabled.
//
// Hard red line (doc/06 §2): every operation here targets the new vendor pools.
// It MUST NOT ever manage the production EC2 host (deploy/ marzban machine).
package provision