feat(distributed): 支持单主控多节点部署和停服迁移

复用现有 k3s 调度和 Job 生命周期,增加 worker 接入与批准、受保护节点身份、归档传输、持久迁移锁及活动 PVC 切换;同步管理员 API、CLI、面板和隔离规则。分布式模式默认关闭,保持单机兼容。

验证:Go 全量测试与 vet;面板 874 个测试、lint/build;Linux VM 安装器测试、清单服务端 dry-run、网络命名空间防火墙实测。A/B/C 三机 WireGuard、Velocity 和迁移验收仍待完成。
This commit is contained in:
Lemon-miaow committed 2026-10-01 19:48:37 +08:00
1 parent 26e817f2c9
commit adf563ffe3
77 files changed
+5224 -73

No files matched your search

+13 -1
View File
@@ -20,6 +20,7 @@ import (
"time"
"felis.lolicon.best/internal/naming"
"felis.lolicon.best/internal/placement"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
@@ -47,6 +48,7 @@ type Request struct {
// cmd/felis leaves the API's Exporter nil when either is missing, and the
// routes answer 503.
type Config struct {
ResolveWorld placement.Resolver
Namespace string
ServiceAccount string
Image string
@@ -112,9 +114,19 @@ func New(cs kubernetes.Interface, cfg Config) *Exporter {
// Start creates the export Job for r and returns its name.
func (e *Exporter) Start(ctx context.Context, r Request) (string, error) {
c := e.cfg
claim := naming.WorldPVCName(r.Server)
node := ""
if c.ResolveWorld != nil && r.Mode != ModeBackup {
world, err := c.ResolveWorld(ctx, r.Server)
if err != nil {
return "", err
}
claim, node = world.Claim, world.Node
}
job, err := ExportJob(JobParams{
Server: r.Server, ID: r.ID, Mode: r.Mode,
WorldPVC: naming.WorldPVCName(r.Server), BackupPVC: c.BackupPVC, BackupRef: r.BackupRef,
NodeName: node,
WorldPVC: claim, BackupPVC: c.BackupPVC, BackupRef: r.BackupRef,
BackupSHA256: r.BackupSHA256, Path: r.Path, Dir: r.Dir,
TargetURL: r.TargetURL, Token: r.Token,
Namespace: c.Namespace, ServiceAccount: c.ServiceAccount, Image: c.Image,