本文档介绍星尘(Stardust)应用发布系统的架构设计和工作原理。

概述

星尘发布系统是一个分布式应用部署平台,支持将应用程序包(zip)发布到多个节点服务器上运行。系统采用服务端-客户端架构:

  • 服务端(Stardust.Server):管理应用配置、版本、节点关系,下发部署指令
  • 客户端(StarAgent):接收指令,下载应用包,启动和守护应用进程
┌─────────────────────────────────────────────────────────────────┐
│                        Stardust.Server                          │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────────────────┐    │
│  │  AppDeploy  │  │AppDeployNode│  │  AppDeployVersion    │    │
│  │  应用部署集  │──│  应用节点    │──│     部署版本         │    │
│  └─────────────┘  └─────────────┘  └──────────────────────┘    │
└───────────────────────────┬─────────────────────────────────────┘
                            │ HTTP API / WebSocket
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│   StarAgent   │   │   StarAgent   │   │   StarAgent   │
│   (Node A)    │   │   (Node B)    │   │   (Node C)    │
└───────────────┘   └───────────────┘   └───────────────┘

数据模型

AppDeploy(应用部署集)

应用部署的核心配置,定义一个可部署的应用单元。

字段

说明

Id

编号

Name

应用名称,全局唯一

Enable

是否启用

Version

当前使用的版本号

FileName

启动文件名,支持 zip 包

Arguments

启动参数

WorkingDirectory

工作目录

UserName

运行用户

Environments

环境变量

Mode

部署模式:Standard(10)/Shadow(11)/Hosted(12)/Task(13)

AllowMultiple

是否允许多实例

MaxMemory

内存限制(MB)

AutoStop

是否随宿主退出

ReloadOnChange

文件变化时是否重启

AppDeployNode(应用节点)

应用和节点服务器的关联关系,支持单应用多节点部署。

字段

说明

Id

编号

DeployId

关联的应用部署集

NodeId

关联的节点服务器

DeployName

发布名,支持单节点多发布

Enable

是否启用

Port

应用监听端口

FileName

启动文件(覆盖应用配置)

Arguments

启动参数(覆盖应用配置)

WorkingDirectory

工作目录(覆盖应用配置)

Mode

部署模式(覆盖应用配置)

ProcessId

当前运行的进程ID

Version

当前运行的版本

AppDeployVersion(部署版本)

应用的版本管理,支持多版本切换。

字段

说明

Id

编号

DeployId

关联的应用部署集

Version

版本号,如 2.3.2022.0911

Enable

是否启用

Url

资源地址(zip 包)

Hash

文件哈希(MD5)

Size

文件大小

Overwrite

覆盖文件列表

Mode

发布模式(部分包/标准包/完整包)

部署模式

系统支持四种部署模式,通过 DeployMode 枚举定义:

模式

说明

Default

0

默认模式,兼容旧版,等同于 Shadow

Standard

10

标准模式,解压到工作目录,直接运行

Shadow

11

影子模式,解压到影子目录,工作目录保持干净

Hosted

12

托管模式,仅解压,由外部宿主(IIS/Nginx)运行

Task

13

任务模式,运行一次后完成,不守护

模式选择建议

Standard (10) - 推荐,简单直接
├── 适合:大多数应用
├── 特点:zip 解压到工作目录,直接运行
└── 场景:控制台应用、Web API、后台服务

Shadow (11) - 热更新场景
├── 适合:需要保持配置文件的应用
├── 特点:可执行文件在影子目录,配置在工作目录
└── 场景:频繁更新但配置不变的应用

Hosted (12) - 外部托管
├── 适合:IIS/Nginx 托管的应用
├── 特点:仅解压,不启动进程
└── 场景:ASP.NET 应用、静态网站

Task (13) - 一次性任务
├── 适合:脚本、迁移工具
├── 特点:运行后自动禁用
└── 场景:数据库迁移、初始化脚本

客户端架构

组件关系

┌─────────────────────────────────────────────────────────────┐
│                      ServiceManager                          │
│  ┌─────────────────────────────────────────────────────────┐│
│  │ - 管理多个 ServiceController                            ││
│  │ - 处理服务端指令(安装/卸载/启动/停止/重启)             ││
│  │ - 定时健康检查                                          ││
│  │ - 上报/拉取应用配置                                     ││
│  └─────────────────────────────────────────────────────────┘│
└──────────────────────────┬──────────────────────────────────┘
                           │ 1:N
        ┌──────────────────┼──────────────────┐
        ▼                  ▼                  ▼
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│ServiceController│ │ServiceController│ │ServiceController│
│   (App A)     │  │   (App B)     │  │   (App C)     │
└───────┬───────┘  └───────┬───────┘  └───────┬───────┘
        │                  │                  │
        ▼                  ▼                  ▼
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│IDeployStrategy│  │IDeployStrategy│  │IDeployStrategy│
│  (Standard)   │  │   (Shadow)    │  │   (Hosted)    │
└───────────────┘  └───────────────┘  └───────────────┘

ServiceManager

应用服务管理器,负责整体调度:

public class ServiceManager
{
    // 应用服务集合
    public ServiceInfo[] Services { get; }
    
    // 正在运行的控制器
    private List<ServiceController> _controllers;
    
    // 核心方法
    void Start();                    // 启动管理
    void Stop(String reason);        // 停止管理
    Boolean StartService(...);       // 启动服务
    Boolean StopService(...);        // 停止服务
    
    // 服务端指令处理
    Task<Boolean> OnInstall(...);    // 安装/发布
    Boolean OnStart(...);            // 启动
    Boolean OnStop(...);             // 停止
    Boolean OnRestart(...);          // 重启
    Boolean OnUninstall(...);        // 卸载
}

ServiceController

单个应用的生命周期控制器:

public class ServiceController
{
    public String Name { get; }           // 服务名
    public ServiceInfo Info { get; }      // 服务配置
    public Process Process { get; }       // 进程实例
    public Boolean Running { get; }       // 运行状态
    
    public Boolean Start();               // 启动应用
    public void Stop(String reason);      // 停止应用
    public Boolean Check();               // 检查并接管/重启
}

IDeployStrategy

部署策略接口,实现不同的部署行为:

public interface IDeployStrategy
{
    DeployMode Mode { get; }              // 部署模式
    Boolean NeedGuardian { get; }         // 是否需要守护
    Boolean AllowTakeOver { get; }        // 是否允许接管
    
    Boolean Extract(DeployContext ctx);   // 解压部署包
    Process Execute(DeployContext ctx);   // 执行应用
}

部署流程

1. 上传应用包

用户 ──[上传 zip]──> Stardust.Server ──[保存]──> AppDeployVersion
                          │
                          ▼
                    记录版本信息
                    - Version: 1.0.0
                    - Url: /files/app.zip
                    - Hash: MD5值
                    - Size: 文件大小

2. 发布指令

管理员 ──[点击发布]──> Stardust.Server
                          │
                          ▼
                    查询 AppDeployNode
                    找到目标节点
                          │
                          ▼
              ┌───────────┴───────────┐
              ▼                       ▼
        WebSocket 推送           HTTP 轮询
        deploy/publish           GetDeploy API
              │                       │
              └───────────┬───────────┘
                          ▼
                      StarAgent

3. 客户端处理

StarAgent 收到指令
        │
        ▼
ServiceManager.DoControl()
        │
        ├── deploy/publish ──> OnInstall()
        ├── deploy/install ──> OnInstall()
        ├── deploy/start   ──> OnStart()
        ├── deploy/stop    ──> OnStop()
        ├── deploy/restart ──> OnRestart()
        └── deploy/uninstall -> OnUninstall()

4. 安装流程(OnInstall)

OnInstall(deployId, serviceName, appName)
        │
        ▼
PullService() ──[HTTP]──> 服务端 GetDeploy API
        │
        ▼
返回 DeployInfo[]
├── DeployInfo.Service (ServiceInfo)
│   ├── Name: 服务名
│   ├── FileName: 启动文件
│   ├── Arguments: 启动参数
│   ├── WorkingDirectory: 工作目录
│   ├── Mode: 部署模式
│   └── Enable: 是否启用
│
└── DeployInfo
    ├── Id: 部署节点ID
    ├── Name: 应用名
    ├── Version: 版本号
    ├── Url: 下载地址
    └── Hash: 文件哈希
        │
        ▼
Download() ──[HTTP]──> 下载 zip 包到工作目录
        │
        ├── 检查本地文件是否存在
        ├── 比对 Hash 是否一致
        ├── 下载到临时目录
        ├── 校验哈希
        └── 移动到目标位置
        │
        ▼
StopService() ──> 停止旧进程
        │
        ▼
StartService(svc, deploy)
        │
        ▼
ServiceController.Start()
        │
        ▼
DeployStrategyFactory.Create(mode)
        │
        ├── Standard(10) ──> StandardDeployStrategy
        ├── Shadow(11)   ──> ShadowDeployStrategy
        ├── Hosted(12)   ──> HostedStrategy
        └── Task(13)     ──> TaskStrategy
        │
        ▼
strategy.Extract(context)
        │
        ├── 解压 zip 到目标目录
        ├── 查找可执行文件
        └── 设置 context.ExecuteFile
        │
        ▼
strategy.Execute(context)
        │
        ├── 构建 ProcessStartInfo
        ├── 设置环境变量
        ├── 注入星尘监控(可选)
        ├── 启动进程
        └── 返回 Process 实例
        │
        ▼
SetProcess(p) ──> 记录进程信息
        │
        ▼
StartMonitor() ──> 启动文件监控

5. 数据流转

服务端数据                           客户端数据
─────────────                        ─────────────
AppDeploy ────┐
              │
AppDeployNode─┼──[ToServiceInfo()]──> ServiceInfo
              │                            │
              │                            ▼
AppDeployVersion ──[构建 DeployInfo]──> DeployInfo
                                           │
                                           ▼
                                    DeployContext
                                           │
                                           ▼
                                    IDeployStrategy

策略模式实现

StandardDeployStrategy(标准模式)

工作目录结构:
apps/myapp/
├── myapp.zip          # 下载的应用包
├── myapp.exe          # 解压后的可执行文件
├── myapp.dll
├── appsettings.json   # 配置文件
└── logs/              # 日志目录

执行流程:
1. Extract: zip 解压到工作目录
2. Execute: 直接在工作目录运行

ShadowDeployStrategy(影子模式)

目录结构:
apps/myapp/              # 工作目录(配置和数据)
├── myapp.zip
├── appsettings.json
└── data/

shadow/myapp-a1b2c3d4/   # 影子目录(可执行文件)
├── myapp.exe
├── myapp.dll
└── *.dll

执行流程:
1. Extract: zip 解压到影子目录
2. 配置文件拷贝到工作目录(如不存在)
3. Execute: 在影子目录运行,工作目录设为 apps/myapp

HostedStrategy(托管模式)

工作目录结构:
wwwroot/mysite/
├── web.config         # IIS 配置
├── app_offline.htm    # 维护页面(部署时临时创建)
├── *.dll
└── wwwroot/

执行流程:
1. Extract:
   - 创建 app_offline.htm(网站离线)
   - 备份 web.config
   - 解压 zip 到工作目录
   - 恢复 web.config
   - 删除 app_offline.htm(网站上线)
2. Execute: 不启动进程(由 IIS 托管)

TaskStrategy(任务模式)

执行流程:
1. Extract: zip 解压到工作目录(如有)
2. Execute: 运行一次
3. 完成后: 设置 Enable = false,不再守护

守护机制

ServiceManager 通过定时器(30秒)进行健康检查:

DoWork() 定时任务
        │
        ▼
遍历 Services
        │
        ├── 服务已禁用 ──> StopService()
        │
        ├── 配置已改变 ──> Stop + Start
        │
        └── 服务已启用 ──> StartService()
                │
                ▼
        ServiceController.Check()
                │
                ├── 进程存在 ──> 检查内存限制
                │       │
                │       └── 超限 ──> Stop + Start
                │
                ├── 进程不存在但有 ProcessId
                │       │
                │       └── 尝试按 ID 查找并接管
                │
                ├── 进程不存在但有 ProcessName
                │       │
                │       └── 尝试按名称查找并接管
                │
                └── 都找不到 ──> Start() 启动新进程

兼容性设计

新旧模式兼容

系统支持新旧两套部署模式值:

旧版值

旧版名称

新版值

新版名称

0

Default

11

Shadow

1

Extract

12

Hosted

2

ExtractAndRun

10

Standard

3

RunOnce

13

Task

4

Multiple

11

Shadow + AllowMultiple

客户端通过数值范围自动识别:

  • 0-9:旧版模式,按映射表转换
  • 10+:新版模式,直接使用
public static IDeployStrategy Create(DeployMode mode)
{
    var value = (Int32)mode;
    
    // 新版模式 10+
    if (value >= 10)
    {
        return mode switch
        {
            DeployMode.Standard => new StandardDeployStrategy(),
            DeployMode.Shadow => new ShadowDeployStrategy(),
            DeployMode.Hosted => new HostedStrategy(),
            DeployMode.Task => new TaskStrategy(),
            _ => new StandardDeployStrategy(),
        };
    }
    
    // 旧版模式 0-4,映射到新版策略
    return value switch
    {
        0 => new ShadowDeployStrategy(),      // Default -> Shadow
        1 => new HostedStrategy(),            // Extract -> Hosted
        2 => new StandardDeployStrategy(),    // ExtractAndRun -> Standard
        3 => new TaskStrategy(),              // RunOnce -> Task
        4 => new ShadowDeployStrategy(),      // Multiple -> Shadow
        _ => new ShadowDeployStrategy(),
    };
}

服务端兼容

服务端数据库继续使用旧的 ServiceModes 字段存储,在下发时转换为数值。

新版客户端(>=v3.7):接收新版模式值(10+)
旧版客户端(<v3.7):接收旧版模式值(0-4)

配置文件

StarAgentSetting.xml

客户端配置文件中的 Services 节点:

<StarAgentSetting>
  <Services>
    <ServiceInfo Name="myapp" 
                 FileName="myapp.zip" 
                 WorkingDirectory="../apps/myapp"
                 Mode="Standard"
                 Enable="True"
                 AutoStop="False"
                 ReloadOnChange="True"
                 MaxMemory="512" />
  </Services>
</StarAgentSetting>

Mode 属性支持枚举名称(Standard/Shadow/Hosted/Task)或数值(10/11/12/13)。

总结

星尘发布系统通过策略模式实现了灵活的部署方式,支持:

  1. 多种部署模式:标准/影子/托管/任务
  2. 分布式部署:一个应用可部署到多个节点
  3. 版本管理:支持多版本切换和回滚
  4. 进程守护:自动重启崩溃的应用
  5. 热更新:文件变化自动重启
  6. 内存限制:超限自动重启
  7. 兼容性:新旧版本平滑过渡

整体架构清晰,扩展性强,适合中大型分布式系统的应用部署管理。