本文档介绍星尘(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
│ │
└───────────┬───────────┘
▼
StarAgent3. 客户端处理
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/myappHostedStrategy(托管模式)
工作目录结构:
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)。
总结
星尘发布系统通过策略模式实现了灵活的部署方式,支持:
- 多种部署模式:标准/影子/托管/任务
- 分布式部署:一个应用可部署到多个节点
- 版本管理:支持多版本切换和回滚
- 进程守护:自动重启崩溃的应用
- 热更新:文件变化自动重启
- 内存限制:超限自动重启
- 兼容性:新旧版本平滑过渡
整体架构清晰,扩展性强,适合中大型分布式系统的应用部署管理。