Skip to content

Repository files navigation

aca — Aliyun Cloud Assistant CLI

npm node license

简体中文 | English

在 Windows ECS 上自动发布 IIS 站点和 Windows 服务,也能回退、执行 PowerShell、检查和更换 SSL 证书。

  • 服务器上不用另装东西、不用开端口:aca 经阿里云云助手操作服务器,只需 AccessKey 和一个 OSS bucket。
  • 一条命令发完所有服务器:aca 发完一台再发下一台,每台都是停下站点或服务、备份、覆盖、启动、检查,失败就停;配了负载均衡(CLB、ALB、NLB)还先把这台服务器摘出,发完放回。
  • 发布前有预检查:拿错了旧构建、程序集引用发布后才会报错、服务器没装要的 .NET Framework 版本,aca 在停站之前就拦下。
  • .NET Framework 项目的 web.config 以服务器上那份为准:连接串这类按服务器填的值不动,aca 只把绑定重定向这类由构建决定的部分合进去。
  • 发坏了退得回去:aca 每次发布都备份被覆盖的文件,用 aca rollback 一次能退回多次发布。
  • 排查不用登录服务器:用 aca logs、aca events 一次取回一个站点在每台服务器上的 IIS 日志和相关的 Windows 事件,用 aca diff 找出哪台服务器的文件不一样。
  • 查和换 SSL 证书:用 aca certs 查每台服务器握手时实际返回的证书和剩余天数,用 aca certs replace 批量换,aca 换完在服务器本机握手,不对就换回旧证书。
  • 附带 Agent Skill:对 Claude Code、Codex 等 AI Agent 说"把 MyApp 发到测试站",它会先跑 --check 把结果给你看,等你确认了再发;说"给每台服务器做个体检",它能用 aca run 查磁盘被什么占满、数据库有没有在备份、多久没装补丁、哪些端口在监听等。

Caution

云助手以 SYSTEM 身份执行,aca run 能在服务器上执行任意 PowerShell:持有这份 AccessKey 的人和 AI Agent 就是这些服务器的管理员。skill 要求 AI Agent 改动服务器前先让你确认,这是写给 AI Agent 的规则,不是权限控制。

目录

安装

需要 Node 22.12+。

npm install -g @ninesols/aca-cli
aca skill install  # 给 Claude Code、Codex 装上 skill,升级 aca 后再跑一次

其他支持 Agent Skills 开放标准的 AI Agent 用 npx skills add YoungsunLi/aca -g 装,它会问装给哪些 AI Agent;装的是 GitHub 上最新的 skill,不一定和本机 aca 的版本一致。

配置

在 ~/.aca/config.json 写一份配置,或设置环境变量 ACA_CONFIG 指向别的路径。先写好 region 和 oss,再跑 aca discover:aca 列出每台服务器上的站点和服务(装在 Windows、Program Files、ProgramData 目录里的服务不列),最后给出 instances、sites、services 的草稿,照着填。

{
  "region": "cn-hangzhou",
  "oss": { "bucket": "my-deploy-bucket", "prefix": "deploy/" },
  "instances": { "web1": "i-bp1xxxxxxxx", "web2": "i-bp1yyyyyyyy" },
  "sites": {
    "Default Web Site": {
      "instances": ["web1", "web2"],
      "project": "MyApp.Web",
      "publish": "D:\\Publish\\MyApp",
      "exclude": ["web.config", "bin/Res"],
      "stage": "Default Web Site TEST",
      "clb": "lb-bp1zzzzzzzz",
      "note": "正式站"
    },
    "Default Web Site TEST": { "instances": ["web1"], "publish": "D:\\Publish\\MyApp", "exclude": ["web.config", "bin/Res"] }
  },
  "services": {
    "MyApp.Worker": {
      "instances": ["web1", "web2"],
      "publish": "D:\\Publish\\Worker",
      "dir": "D:\\Services\\Worker",
      "exclude": ["MyApp.Worker.exe.config"]
    }
  }
}

sites 的 key 是 IIS 站点名,站点下的应用程序写成 站点名/路径(见站点下的应用程序);带站点或服务名的命令只认这里登记的站点和下面 services 里登记的服务。除 instances 外的字段都可选:

字段 说明
instances 跑这个站点的服务器(别名或实例 ID),顺序即发布顺序
publish 本机的发布目录,deploy 省略路径时用它
exclude 包里不发布的路径(目录或文件):服务器上自己维护的密钥、环境配置列在这里,发布就不会覆盖它们
overwriteConfig 设为 true 时,包里的环境配置当普通文件整份发(默认要列进 exclude,否则 aca 报错):适合环境值不放在这份文件里的项目
stage 指向预发布站:本站只发预发布站验过的包,即预发布站每台服务器发布记录的最后一条都是它的成功发布,--skip-stage 跳过这项要求。用 --from-stage 直接发那个包;给本机路径时 aca 比对要上传的 zip,重新构建过,或者一边给目录一边给 zip,都算不同的包
keep 每台服务器上保留的备份份数,默认 5,rollback 最多撤得掉最近这么多次发布,更早的版本只能重新发旧构建
clb
alb
nlb
站点的请求走的负载均衡服务器组,三个最多配一个:aca 发布、回退、重启每台服务器前先把它摘出这个组,见负载均衡。clb 写传统型负载均衡的实例 ID(lb-,指它的默认服务器组)或虚拟服务器组 ID(rsp-);alb、nlb 写应用型、网络型负载均衡的服务器组 ID(sgp-)
project
note
只在 aca sites、aca services 里显示,方便认出是哪个站点或服务

services 的 key 是 Windows 服务名(sc query 列出的那个,不是显示名),字段和站点相同,但没有 stage 和负载均衡的三个字段,另外必填 dir:服务器上的安装目录。有别的服务依赖它、而且在跑时,停它会连带停掉那些服务,aca 不发,只能手工发。

站点下的应用程序

IIS 里挂在站点下的应用程序(IIS 管理器里"添加应用程序"建的)写成 站点名/路径,如 Default Web Site/api,登记在 sites 里,字段和站点相同。和站点不一样的地方:

  • 停的只是应用自己的应用池,站点和别的应用照常运行;应用池和站点或别的应用共用时,预检查会列出跟着一起中断的那些。
  • 应用目录在站点目录(或同站点别的应用、虚拟目录的目录)里时,aca 的备份、发布记录和锁文件放在最外层目录旁的 <最外层目录>.aca-apps\ 下,免得被 IIS 对外提供。站点本身也要发布时,把应用目录列进站点的 exclude,aca diff 比站点时就不会把应用的文件也比进去。

凭证和权限

凭证按阿里云 SDK 的默认凭证链查找,和阿里云 CLI 共用:aliyun configure 配过就不用再配,也可以设环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID、ALIBABA_CLOUD_ACCESS_KEY_SECRET,两处都配了时环境变量优先。

RAM 权限:

产品 权限
ECS ecs:DescribeInstances、ecs:DescribeCloudAssistantStatus(没有它 aca instances 看不到云助手客户端的状态)、ecs:RunCommand、ecs:DescribeInvocationResults
OSS oss:PutObject、oss:GetObject、oss:ListObjects、oss:GetBucketPolicyStatus、oss:DeleteObject;bucket 开了版本控制时,run -o、pull、push、logs、events、diff 和 certs replace 删 OSS 上中转的文件要 oss:DeleteObjectVersion
CLB 站点配了 clb 时要:slb:DescribeLoadBalancerListeners、slb:DescribeHealthStatus;配的是实例 ID 时另要 slb:DescribeLoadBalancerAttribute、slb:SetBackendServers,是虚拟服务器组 ID 时另要 slb:DescribeVServerGroupAttribute、slb:SetVServerGroupAttribute、slb:DescribeRules
ALB 站点配了 alb 时要:alb:ListServerGroupServers、alb:UpdateServerGroupServersAttribute、alb:ListServerGroups、alb:ListListeners、alb:GetListenerHealthStatus
NLB 站点配了 nlb 时要:nlb:ListServerGroupServers、nlb:UpdateServerGroupServersAttribute、nlb:ListServerGroups、nlb:ListLoadBalancers、nlb:ListListeners、nlb:GetListenerHealthStatus
数字证书管理服务 取云端证书时要:yundun-cert:ListUserCertificateOrder、yundun-cert:GetUserCertificateDetail;这个服务只支持操作级授权,资源只能写 *

Warning

ecs:RunCommand 按实例 ID 授权,不要给 *:它授权到哪些实例,这份 AccessKey 就是哪些实例的管理员。

约束

  • 服务器和 OSS bucket 在同一地域,发布包走 OSS 内网下载。
  • 服务器需装有 2.0.0.612 或更新的云助手客户端(2017 年 12 月以来用公共镜像创建的服务器已预装,客户端会自己升级),更早的版本会中止 aca 的命令。
  • 系统区域不是英语(美国)的服务器上,输出里 GBK 以外的字符(如 ä、emoji)会变成问号,中文不受影响。
  • Server 2019 及更早的系统上,aca events 列不出 .NET 应用记在 .NET Runtime 来源下的日志,崩溃那条除外。
  • 站点目录和服务目录必须是本地盘上的普通目录,不能是磁盘根目录或 UNC 路径,也不要嵌套在另一个站点或服务的目录里(站点下的应用程序除外):备份和发布记录放在它旁边。
  • 目录旁的 <目录>.bak-<时间> 备份和 <目录>.aca-* 文件都是 aca 要用的,别手动删:删了最新的备份,rollback 会跳过那次发布,恢复出一个从没发布过的混合版本。
  • 本机和服务器要在同一时区:预检查拿包里的文件时间和服务器上的比,看是不是拿错了旧构建,zip 里存的是本地时间。
  • 发布包(--check 也会上传)按 SHA-256 命名留在 OSS 的 oss.prefix 下,aca 不删,要在 bucket 上配生命周期规则按天清理;--from-stage 从这里取预发布站发过的包,天数要长于从发预发布站到发正式站的间隔。
  • bucket 要私有,防盗链要允许空 Referer(服务器下载包时不带 Referer):发布包不加密,aca 每次发布前确认匿名读不到,否则报错退出。
  • run -o、pull、push、logs、events、diff 和 certs replace 经 OSS 中转文件:aca 用一次性密钥加密、用完就删,但密钥和 PFX 密码留在云助手的执行记录里,看得到执行记录的人也看得到它们。
  • 同一个站点或服务同时只能有一个发布或回退:aca 靠 OSS 上 oss.prefix 下的租约互斥,几个人发同一批站点时要配同一个 bucket 和 oss.prefix,否则挡不住同时发。

命令

每个命令都输出纯文本,失败以非 0 退出码表示,参数见 aca <命令> --help。

服务器和配置

aca instances                                   # 列出当前地域的服务器和上面云助手客户端的版本
aca discover                                    # 列出每台 Windows 服务器上的站点和服务,给出配置草稿
aca discover web1 web2                          # 只看这几台
aca sites                                       # 列出配置里的站点和它们的项目、发布目录、服务器
aca services                                    # 列出配置里的 Windows 服务和它们在服务器上的目录

排查和临时运维

aca run web1 "Get-Website | select name,state"  # 以 SYSTEM 执行任意 PowerShell
aca run web1 --file ./check.ps1                 # 执行文件里的脚本,带 $、引号或换行时用它
aca run web1 --file ./list.ps1 -o list.txt      # 输出存进本机文件,不受云助手输出上限的限制
aca pull web1 "C:\inetpub\logs\LogFiles\W3SVC1\u_ex260919.log"  # 把服务器上的文件拉到本机当前目录
aca push web1 ./rewrite_amd64.msi "C:\Windows\Temp"  # 把本机的文件送到服务器上的目录里
aca logs "Default Web Site"                     # 每台服务器上这个站点最新的 20 行 IIS 日志,时间是 UTC
aca logs "Default Web Site" --since 30m -n 500  # 最近 30 分钟里最新的 500 行
aca logs "Default Web Site" --httperr --since 2h  # 最近 2 小时里这个站点没进到 IIS 的请求
aca events "Default Web Site"                   # 每台服务器上和这个站点有关的最新 20 条 Windows 事件
aca events MyApp.Worker --since 2h              # 最近 2 小时里这个服务的事件
aca diff "Default Web Site"                     # 按内容哈希比对每台服务器上的文件,列出不一样的
aca diff "Default Web Site" bin                 # 只比站点目录下的一个目录
aca reboot web1 web2 --check                    # 不重启,只列出要核对的站点和服务、要摘出的负载均衡
aca reboot web1 web2                            # 重启 web1,站点和服务都起来了再重启 web2

发布和回退

aca deploy "Default Web Site" --check           # 只预检查,列出要覆盖和新增的文件,不停站
aca deploy "Default Web Site" -m "release-2026-09"  # 发配置里 publish 字段的目录;-m 写进发布记录
aca deploy "Default Web Site" ./MyApp.zip -m "release-2026-09"  # 发别的目录或 zip,不用 publish 字段
aca deploy "Default Web Site" --from-stage -m "release-2026-09"  # 直接发预发布站最近一次发布的那个包
aca deploy MyApp.Worker -m "release-2026-09"    # 发 Windows 服务,参数和站点一样
aca deploy "Default Web Site/api" ./api -m "release-2026-09"  # 发站点下的应用程序
aca status "Default Web Site"                   # 每台服务器上的状态、最新的文件时间和最近 5 条发布/回退记录
aca status                                      # 每个站点和服务在每台服务器上一行:状态、最新文件时间、最后一条发布/回退记录
aca rollback "Default Web Site" --check         # 每台服务器上还留着哪几次发布的备份、占多少空间、会撤掉哪几次
aca rollback "Default Web Site"                 # 回退最近一次发布
aca rollback "Default Web Site" 20260918T020100Z  # 连同之后的发布一起回退,退到这次发布之前
aca lb "Default Web Site"                       # 每台服务器在负载均衡服务器组里的权重
aca lb restore "Default Web Site" web1          # 把摘下的 web1 放回负载均衡

证书

aca certs                                       # 每台服务器上运行中站点的 https 绑定实际返回的证书
aca certs replace ./a.pfx --password-file ./pw.txt --check  # 看每台服务器会把哪些 https 绑定换成这张证书
aca certs replace ./a.pfx --password-file ./pw.txt  # 换证书
aca certs cloud                                 # 列出数字证书管理服务里没过期的证书和它们的 ID
aca certs replace --from-cloud 22863954         # 换成云端这张证书,PFX 由 aca 合成

aca run

aca 以 SYSTEM 身份在服务器上执行 PowerShell,脚本以非 0 退出(包括没被捕获的异常)时 aca 用同样的退出码退出。

  • 脚本里有 $、引号或换行时用 --file <文件>:写在命令行上的脚本要先经本机 shell 处理,这些字符可能被悄悄改掉。
  • PowerShell 里出错的命令默认只报错、不中止脚本,退出码仍是 0;要让任何错误都算失败,脚本开头加 $ErrorActionPreference = 'Stop'。
  • Server 2012、2012 R2 上,等待输入的脚本(缺必填参数、Read-Host、确认提示)会一直挂到超时。
  • 脚本以 3010 或 3009 退出时,云助手客户端会接着重启或关掉服务器:安装程序常以 3010 表示需要重启,别把它的退出码原样 exit 出去,装完用 aca reboot 重启。
  • 脚本最多约 18 KB(按纯英文算):云助手限定命令 base64 后 24 KB,aca 还要加上自己的代码;加 -o 时再少 2 到 5 KB。
  • 改站点和服务的文件用 aca deploy:用 aca run、aca push 改的没有备份,aca rollback 管不了。

aca diff

负载均衡后面几台服务器上的文件不一致时,表现是刷新几次好一次坏一次。用 aca diff 按内容哈希比对每台服务器上的文件,列出服务器之间不一样的。

  • 比的是站点目录(服务是配置里的 dir)下的全部文件,exclude 里的路径除外;上传目录、日志目录也列进 exclude 就不比了。服务只比 .dll、.exe 和 .NET Core 的 *.runtimeconfig.json、*.deps.json。
  • 每台服务器要把目录整个读一遍,几 GB 的目录要几分钟,超过 30 分钟会被云助手强杀。

aca deploy

aca 先在每台服务器上同时下载解压、预检查,每台都通过后,发完一台服务器再发下一台,每台依次:停站点或服务 → 把要覆盖的文件备份到 <目录>.bak-<时间> → 覆盖复制 → 启动 → 检查 → 删掉最近 keep 份以外的旧备份。

  • 发布是增量的:包里有什么就覆盖什么(exclude 的除外),包里已经没有的文件,aca 也不会从服务器上删掉。
  • aca 发布完会启动站点和应用池,即使发布前是手动停掉的;发布前就停着的服务,aca 发布后也不启动:备机上的服务常常是刻意停着的。
  • 启动后的检查:aca 在服务器本机请求站点首页,5xx 或连不上、且和发布前不同,就算这台服务器发布失败;首页跳到别的站点的,只看得到跳转的状态码,看不出应用起没起来。服务没回到发布前的运行状态也算失败。

预检查

任何一台服务器预检查不过,aca 哪台服务器都不发:

  • 包像是源码目录、包根目录里有没列进 exclude 的环境配置、疑似发错了站点或服务、磁盘不够。
  • 包里有比服务器上旧的文件:多半是拿错了旧构建,或者有人在服务器上手改过。
  • 发布后会加载失败的程序集引用:aca 按运行时的规则,经绑定重定向和 GAC 解析 bin 里每个程序集的引用;这次发布让原来找得到的引用找不到了,或者新代码引用的版本和 bin 里的对不上,就拦下,多半是升级了 NuGet 包却没带上绑定重定向。这类问题站点照样能启动,要等用到那段代码才报错,首页检查拦不住。新代码引用的程序集在 bin 和 GAC 里都找不到时只提示。
  • 服务器没装包要的 .NET Framework 版本,或者应用池的位数不对(只核对 .NET Framework 的程序)。

后三种确认没问题,可以加 -f 照发。

环境配置

环境配置指站点的 web.config、服务的 *.exe.config(包根目录下的每个都算)。它们装着连接串这类按服务器填的值,以服务器上那份为准,出现在包根目录时 aca 报错,要列进 exclude,或者配 overwriteConfig 整份发。

  • 包里带着环境配置时,aca 把由构建决定的部分合进服务器上那份:程序集绑定重定向、system.codedom 的编译器、Entity Framework 的 providers、compilation 的 assemblies 按条目合并,startup 整段换,targetFramework 只换值;连接串、appSettings 等其余内容和改动之外的每个字节都保持原样。预检查列出每处改动,aca rollback 会连它一起退回。
  • ASP.NET Core 的 web.config 是发布时生成的,aca 当普通文件整份发:在服务器上那份里加的 environmentVariables 等设置会被覆盖,按服务器区分的值放到 appsettings.<环境>.json(列进 exclude)或服务器的环境变量里。

负载均衡

站点配了负载均衡时,aca 发每台服务器之前先把它在服务器组里的权重调成 0,停站期间负载均衡不再把请求转给它(包括走这个服务器组的其他站点);这台服务器发布成功后调回原值,再发下一台。回退和 aca reboot 也一样。

  • aca 只在组里还有别的服务器接流量时才摘,但健康状态接口比负载均衡实际的判断慢一两分钟:别的服务器刚出故障时 aca 看不出来,照样会摘。
  • 四层监听(CLB 的 TCP/UDP、NLB)上已经建立的连接,停站时会断开,开了连接优雅中断也一样;七层监听按请求转发,不受影响。
  • 停过站又失败的服务器留在负载均衡外:负载均衡的健康检查查的不一定是这个站点,放回去用户可能撞上没起来的站点。
  • aca 处理不了的服务器组:同一台服务器按几个端口进了组、ALB 服务器组或 NLB 实例关了跨可用区、服务器组开了 IP 版本亲和。这些情况下 aca 算不准摘出之后流量怎么走,报错,哪台服务器都不发。

发布失败后

一台服务器发布失败时,aca 不再发后面的服务器,已经覆盖的文件都不会自动回退。不论是撤销这次发布还是修好重发,都先跑 aca rollback <站点> --check:标 undo 的是这次发布(发布 ID 是开始时的 UTC 时间)就先回退;标的是更早的发布,说明哪台服务器都没发上,不用回退。

Warning

发上了这次的服务器不先回退就重发,会把这次的版本当作备份,之后回退一次只能退到这次,退不回发布前的版本。

  • aca 报 Polling Cloud Assistant results failed、Timed out waiting for Cloud Assistant results,或者被强杀、中途 Ctrl+C 时,服务器上的脚本可能还在跑(发布最长 30 分钟):先用 aca status 看发布记录,再决定要不要回退。

  • 脚本跑满 30 分钟被云助手强杀时,站点或服务可能停着、文件可能只覆盖了一半,也没有发布记录。aca rollback <站点> --check 显示这台服务器要撤的是这次发布就回退,否则文件没动过,手动启起来:

    aca run <实例> "Start-WebAppPool (Get-Website '<站点>').applicationPool; Start-Website '<站点>'"
    aca run <实例> "Start-Service '<服务名>'"   # 发的是服务
  • 配了负载均衡的,以上情况下正在处理的服务器都留在负载均衡外:确认它上面的站点正常后,用 aca lb restore <站点> <实例> 放回。

aca reboot

装完 .NET Framework、Windows 更新这类要重启的东西后,用 aca reboot <实例...> 重启服务器。aca 按给出的顺序重启,一台服务器恢复了才重启下一台:

  • 这台服务器上有站点在配置里配了负载均衡时,aca 先把服务器摘出这些服务器组,恢复后放回;配置里没有的站点走的负载均衡,aca 不知道,也就不摘。
  • 配置里的站点首页没有新出现 5xx 或连不上、重启前在跑的服务又跑起来了、Windows 装完更新,才算恢复(装完累积更新,Windows 第一次开机后还会自己再重启一次);15 分钟还没恢复,aca 报错停下,摘出过负载均衡的留在外面。
  • 装更新的那次重启,关机前、开机时都在装更新,可能要几十分钟,aca 最多等 60 分钟。

aca certs

aca 在配置里站点所在的每台服务器上,按每个运行中站点(没登记的也算)的 https 绑定在服务器本机握手,列出实际返回的证书和剩余天数。证书过期、30 天内到期、不含绑定的域名或握手失败时以非 0 退出,可以放进计划任务定期跑。

aca certs replace

aca 在同一批服务器上,把正在用同名证书(按证书使用者名称,如 *.a.com)的 https 绑定全部换成这张证书,没登记的站点也换,旧证书留在服务器上。

  • 换的单位是 HTTP.sys 的绑定条目而不是站点:不带 SNI 的绑定共用一个 IP:端口 条目,换其中一个站点就是全换,--check 会列出每个条目上的站点。
  • 要换的条目里有 IIS 默认值以外的 HTTP.sys 设置时(客户端证书协商、吊销检查等),aca 报错,这台服务器一条都不换,后面的服务器也不再处理,--check 也一样:换证书会把这些设置丢掉,这种条目要手工换。
  • Windows Server 2016 及更早的系统打不开 AES 加密的 PFX(OpenSSL 3 默认就是),报的却是密码不正确,用 openssl pkcs12 -export -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1 重新导出。

免责声明

Caution

aca 会停止并覆盖生产站点,也会重启服务器。请先在测试站跑通、每次发布前用 --check、保管好 AccessKey。

本软件按 MIT 协议"按原样"提供,不附带任何担保,详见 LICENSE。

About

通过阿里云云助手在 Windows ECS 上自动发布 IIS 站点和 Windows 服务,也能回退、执行 PowerShell、检查和更换 SSL 证书,附带 Agent Skill 供 Claude Code、Codex 等 AI Agent 调用

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages