feat(update): 发布双链路更新进度与线上验收审计

This commit is contained in:
2026-10-02 19:46:39 +08:00
parent 89cc554c04
commit eebc6d1453
52 changed files with 13799 additions and 21 deletions
+13 -13
View File
@@ -1,37 +1,37 @@
{
"schemaVersion": 1,
"channel": "stable",
"releaseId": "managed-update-20260927",
"productVersion": "3.18.0.20260927",
"releaseId": "online-update-progress-20261002",
"productVersion": "3.22.0.20261002.2",
"platform": "linux/amd64",
"publishedAt": "2026-09-27T11:15:00+08:00",
"publishedAt": "2026-10-02T19:00:00+08:00",
"managedUpdateAllowed": true,
"scheduledUpdateAllowed": true,
"rollbackSafe": true,
"minimumUpdaterVersion": "1.0.0",
"minimumUpdaterVersion": "1.1.0",
"minimumDeploymentSchemaVersion": 2,
"requiredFreeBytes": 8589934592,
"components": [
{
"key": "server-main",
"image": "registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server",
"digest": "sha256:38cbe3fdb151b54dd729071e1368ad0670710a5b0160aa5fdbc486737bf5b2ef",
"imageSizeBytes": 2723428239,
"buildId": "db43ef28"
"digest": "sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491",
"buildId": "e3f12240",
"imageSizeBytes": 2734540568
},
{
"key": "ws-gateway",
"image": "registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway",
"digest": "sha256:661eb2dc5ca6e458e00b8c2e2f068c2a1773694a3017982ecb1aa42de677468e",
"imageSizeBytes": 1982899440,
"buildId": "db43ef28"
"digest": "sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25",
"buildId": "retained-formal-image",
"imageSizeBytes": 1982472178
},
{
"key": "web",
"image": "registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai",
"digest": "sha256:bc82b10e08886904b2ef4a5c2fe7727b1dac9114c7493b4f2acc0b1a8ef5e29c",
"imageSizeBytes": 1038564864,
"buildId": "188b0ee9"
"digest": "sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0",
"buildId": "56e51ea5",
"imageSizeBytes": 1034496829
}
]
}
@@ -0,0 +1,171 @@
{
"status": "released",
"productVersion": "3.22.0.20261002.2",
"source": {
"backend": "e3f12240c4a186a55ed2bc9a5afcb71902004a55",
"backendBaseline": "179d4dae8c9400a773f7f9d92a397039c39ef572",
"web": "56e51ea55dcc281ade91bd0e6438c5fc6a617c25",
"webBaseline": "340c47f820a039d409ffcc4f464829acc973a171"
},
"images": {
"server-main": "sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491",
"watchtower": "sha256:6afd62a208687bb4840b3b8131e1461dee7033989e14e28b6d69082839eaf410",
"updater": "sha256:bbaddb598618ceaaf6696f6c5fe19daf564d983039b70d36a4196cc4aaca385a",
"web": "sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0",
"ws-gateway": "sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25"
},
"watchtowerVersion": "1.22.3",
"acceptance": {
"oldWatchtower": {
"status": "passed",
"beforeVersion": "3.22.0.20261002.1",
"afterVersion": "3.22.0.20261002.2",
"uiElapsedSeconds": 61,
"details": [
"old backend jobApi=false",
"real browser confirmation",
"elapsed32s and restart message screenshot",
"refresh resumes original update",
"core images and health verified"
],
"evidenceDirectory": "online-update-progress-20261002/acceptance"
},
"newWatchtower": {
"status": "passed",
"beforeVersion": "3.22.0.20261002.1",
"afterVersion": "3.22.0.20261002.2",
"uiElapsedSeconds": 43,
"jobId": "wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"details": [
"POST async update accepted and scan started",
"SSE endpoint observed through public browser",
"Mongo job stages persisted",
"history confirms completion after main restart",
"refresh resumes original task",
"core images and health verified"
],
"evidenceDirectory": "online-update-progress-20261002/acceptance"
},
"managedUpdater": {
"status": "passed",
"beforeVersion": "3.22.0.20261002.1",
"afterVersion": "3.22.0.20261002.2",
"uiElapsedSeconds": 53,
"jobId": "154b6781-dd24-434d-94a5-4bf59122c0bb",
"failureRecoveryJobId": "d0f02915-1cbe-4063-94c6-e9d749aaf2d7",
"failureRecoveryUiElapsedSeconds": 154,
"details": [
"all six stages persisted with timestamps",
"real browser confirmation and refresh recovery",
"main service restart queries recover",
"updater restart during intentional HTTP503 health failure resumes same task",
"failed candidate rolled back to A image ids and A version",
"new job then updates real formal B digests and healthy services"
],
"evidenceDirectory": "online-update-progress-20261002/acceptance",
"failureFixtureDigest": "sha256:deddc80bee5a4123dc62d1598a34660ad4f54b8f50f3968fbf4b1844b058e11f"
}
},
"production": {
"host": "101.200.186.210",
"mode": "legacy_watchtower",
"status": "passed",
"beforeVersion": "3.22.0.20260930.3",
"afterVersion": "3.22.0.20261002.2",
"backupPath": "/home/admin/easyai/data/deployment-backups/online-update-progress-20261002",
"iceConfigUnchangedSha256": "1427d181c5d405278e7b9b099379679a91d408108b6737c6cff2ed978f88acc1",
"health": {
"main": "ok",
"web": "ok",
"gateway": "ok",
"watchtower": "ok",
"coreRestarts": 0
},
"interfaces": {
"eventsWithUpdateToken": 401,
"eventsWithIndependentToken": 200,
"history": 200,
"statusBeforeFirstScan": 204,
"livez": 200,
"readyz": 200,
"startupz": 200,
"hostPortPublished": false
},
"publicLoginPage": "passed",
"updaterInstalled": false
},
"testBackup": "/root/easyai/update-backups/online-update-progress-20261002",
"validation": [
{
"check": "frontend real mounted components and full 30s HTTP regression",
"passed": true,
"durationSeconds": 49.42
},
{
"check": "MongoDB 4.4 and real HTTP/SSE task integration plus existing backend tests",
"passed": true,
"durationSeconds": 2.21
},
{
"check": "backend production compile",
"passed": true,
"durationSeconds": 21.02
},
{
"check": "frontend production build",
"passed": true,
"durationSeconds": 441.82
},
{
"check": "Bash and PowerShell security initialization and migration",
"passed": true
},
{
"check": "bash scripts/test-security-env.sh",
"exitCode": 0,
"durationSeconds": 0.54
},
{
"check": "bash scripts/test-update-env-migrations.sh",
"exitCode": 0,
"durationSeconds": 0.41
},
{
"check": "bash scripts/test-deployment-public-url.sh",
"exitCode": 0,
"durationSeconds": 2.03
},
{
"check": "pwsh -NoProfile -File scripts/Test-SecurityEnv.ps1",
"exitCode": 0,
"durationSeconds": 0.57
},
{
"check": "python3 scripts/test-start-ps1-env.py",
"exitCode": 0,
"durationSeconds": 0.02
}
],
"rollback": "Restore recorded immutable core image digests and Compose backup, preserve business volumes and data/update-state; synchronize Watchtower token configuration before restoring its image. Do not re-submit unresolved update jobs.",
"latestPromotion": {
"status": "passed",
"allDigestsMatchCandidate": true
},
"testRestore": {
"status": "passed",
"configFilesUnchanged": true,
"version": "3.22.0.20260930.3",
"businessVolumesAndUpdateStatePreserved": true
},
"runtimeBase": {
"server-main": "registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server@sha256:8493e5a4c82f6564d86925f4ab37061f6e6e3d9a6bb88db5fe5d25d3a7b7835b",
"dependenciesMatchFormalBaseline": true
},
"versionCatalog": {
"defaultAddress": "https://openapi.51easyai.com",
"observedVersion": "3.22.0.20260930.3",
"status": "awaiting_user_scope_confirmation",
"reason": "Version service is on a different production host from the explicitly requested 101.200.186.210"
},
"releasedAt": "2026-10-02T19:45:00+08:00"
}
@@ -0,0 +1,40 @@
# 在线更新发布审计:2026-10-02
发布版本:`3.22.0.20261002.2`;Watchtower:`1.22.3`;updater:`1.1.0`。
完整源码提交、不可变镜像摘要、验证耗时和部署状态见上级 `online-update-progress-20261002.json`。前后端只追加本次更新改造,发布基线分别为 backend `179d4dae`、web `340c47f8`;现有 Workbench 工作区未参与镜像构建。
## 原始问题证据
用户原更新请求于 16:55:28 被 Watchtower 接收,前端在 16:55:58 收到旧接口的 30 秒超时包装失败,实际更新在 16:57:12 完成。旧界面因此误报“更新请求未成功提交”。修复前使用未修改的旧后端请求链路复现 30 秒超时,修复后的真实 HTTP 和组件挂载用例覆盖同一边界。
## 浏览器实际更新验收
| 链路 | 版本变化 | 页面耗时 | 结果 |
| --- | --- | --- | --- |
| 旧 Watchtower,无 updater,旧后端接口 | `.1` → `.2` | 61 秒 | 32 秒时仍计时并提示重启;刷新恢复并核对目标版本 |
| Watchtower 1.22.3,无 updater | `.1` → `.2` | 43 秒 | 异步接收、开始事件、SSE、持久任务及重启后的历史确认 |
| updater 1.1.0 | `.1` → `.2` | 53 秒 | 六个阶段完成时间、主服务重启及刷新后继续查询 |
| updater 健康故障与重启恢复 | `.1` → 故障候选 → `.1` | 154 秒 | 实际 HTTP 503、updater 重启恢复同一任务、回退原镜像并恢复健康 |
每项均从实际浏览器确认按钮开始,后端、前端镜像发生实际替换,最终版本及核心服务健康均核对。`acceptance/` 包含截图、任务、事件时间线和镜像证据。首次故障镜像仅改入口命令,因 updater 保留原启动配置而未触发失败;最终 `fault-fixture/` 通过替换应用启动文件真实返回 503,此镜像未提升为正式标签。
测试站配置文件与备份逐字节一致,已恢复原版本 `3.22.0.20260930.3` 和原镜像;业务数据、`data/update-state` 及新增任务记录保留。测试专用 Compose 使用明确的 updater 与版本检测服务地址,避免动态地址占用业务服务预留地址。
## 生产部署
`101.200.186.210` 已部署正式候选的同一摘要,保留 `legacy_watchtower` 模式且未安装 updater。公网版本接口确认 `.2`,登录页面实际渲染,后端、前端、网关和 Watchtower 健康,核心服务重启次数为 0。事件与更新令牌独立,事件接口使用更新令牌返回 401,正确事件令牌返回 200;Watchtower 不映射主机端口。
原端口、业务卷和 `docker-compose.ice-v1.yml` 保留,ICE 文件 SHA256 为 `1427d181c5d405278e7b9b099379679a91d408108b6737c6cff2ed978f88acc1`。线上没有 Docker 登录配置文件,因此省略该配置的绑定挂载。只合并 Watchtower 配置及核心健康检查;部署脚本与迁移在本仓库正式发布。
生产备份:`/home/admin/easyai/data/deployment-backups/online-update-progress-20261002`,配置和容器完整检查结果只在服务器以权限 600 保存。公开审计省略认证信息。
正式版本检测仍使用 `https://openapi.51easyai.com`,此服务在另一台服务器,当前仍报告旧版本;同步其版本信息正在等待用户确认范围。指定的生产主机已完成部署,未通过测试版本检测地址覆盖正式配置。
## 回退
先恢复备份 `.env` 和 `docker-compose.yml`,保持 ICE 文件、业务卷和更新状态目录;按 JSON 中生产前快照的不可变摘要恢复 main、web、Watchtower(网关摘要未变化)。先同步 Watchtower 与后端使用的令牌,再按原 Compose 配置重建上述服务。不得重复提交结果尚待确认的更新任务。`configure-production.py` 保留了本次配置合并方法,不含令牌实际值。
## 验证范围
Node `22.22.0`、Yarn `1.22.22` 定向验证:真实组件挂载与 30 秒 HTTP 回归 49.42 秒;后端 31 个接口用例和 4 个 MongoDB 4.4 / HTTP / SSE 用例 2.21 秒;后端生产编译 21.02 秒;前端生产构建 441.82 秒;updater 8 个行为用例及构建通过。Bash 与真实 PowerShell 初始化、迁移、部署配置检查通过,逐项耗时见 JSON。未运行全量质量门禁,未用定向通过宣称其他业务功能全部验证。
@@ -0,0 +1,3 @@
FROM registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25
LABEL easyai.acceptance="intentional gateway health failure for rollback verification 20261002"
COPY pm2.config.js acceptance-health-failure.cjs /app/
@@ -0,0 +1 @@
require('node:http').createServer((q,s)=>{s.statusCode=503;s.end('acceptance-health-failure')}).listen(3012,'0.0.0.0');
@@ -0,0 +1 @@
module.exports={apps:[{name:'acceptance-health-failure',script:'./acceptance-health-failure.cjs'}]};
@@ -0,0 +1,6 @@
/easyai-server sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea healthy
/easyai-web sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 healthy
sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea ["registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server@sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491"]
sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f ["registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai@sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0"]
sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 ["registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

@@ -0,0 +1,4 @@
/easyai-server sha256:d70bb954db8e6dea13ae2ae295bd274df6bcfbdaf690fe2599698d449af86773 2026-10-02T11:22:03.534661056Z healthy
/easyai-web sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07 2026-10-02T11:22:04.002902303Z healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 2026-09-29T07:22:22.307885848Z healthy
/easyai-watchtower-1 sha256:04f6afca616ae63c48c860250212b7406ba917b712f4b2ebff5d43ef45578b87 2026-10-02T11:19:18.087853796Z healthy
@@ -0,0 +1,138 @@
[
{
"time": "2026-10-02T11:15:34.439Z",
"path": "/api/app/update-jobs",
"status": 200,
"value": {
"status": "success",
"data": [],
"message": "success"
}
},
{
"time": "2026-10-02T11:22:54.730Z",
"path": "/api/app/update-jobs",
"status": 500,
"value": {
"statusCode": 500,
"timestamp": "2026-10-02T11:22:54.644Z",
"path": "/app/update-jobs?active=true&limit=1",
"message": "getaddrinfo EAI_AGAIN easyai-updater",
"traceId": "yGyuK8eBkaXeNsMy",
"appVersion": "3.22.0.20261002.1",
"diagnosticCode": "RequestError"
}
},
{
"time": "2026-10-02T11:23:20.074Z",
"path": "/api/app/update-capabilities",
"status": 200,
"value": {
"status": "success",
"data": {
"mode": "legacy_watchtower",
"jobApi": false,
"executorReachable": false
},
"message": "success"
}
},
{
"time": "2026-10-02T11:23:26.733Z",
"path": "/api/app/update",
"status": 502
},
{
"time": "2026-10-02T11:23:28.856Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:30.935Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:33.033Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:35.153Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:37.254Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:39.392Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:41.490Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:43.622Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:45.733Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:47.824Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:49.905Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:51.995Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:54.094Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:56.194Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:58.414Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:24:20.993Z",
"path": "/api/health/update-ready",
"status": 200,
"value": {
"status": "ok",
"service": "easyai-server-main",
"version": "3.22.0.20261002.2",
"buildId": "3.22.0.20261002.2",
"timestamp": "2026-10-02T11:24:20.920Z",
"uptime": 42.086032874,
"dependencies": {
"mongo": "ok",
"redis": "ok",
"rabbitmq": "ok"
}
}
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

@@ -0,0 +1,36 @@
Update event timeline. Container configuration and authentication details omitted.
time="2026-10-02T11:23:20Z" level=debug msg="Log entry sent immediately (not batching)" fields.level=info legacy_template=true message="Received HTTP API update request" notify=no
time="2026-10-02T11:23:20Z" level=debug msg="Generated notification message" message="Received HTTP API update request | method=GETpath=/v1/update" notify=no
time="2026-10-02T11:23:20Z" level=debug msg="Preparing to send entries" error="<nil>" message="Received HTTP API update request | method=GETpath=/v1/update" notify=no
time="2026-10-02T11:23:20Z" level=info msg="Received HTTP API update request" method=GET path=/v1/update
time="2026-10-02T11:23:20Z" level=debug msg="Handler: trying to acquire lock"
time="2026-10-02T11:23:20Z" level=debug msg="Handler: acquired lock"
time="2026-10-02T11:23:20Z" level=debug msg="Handler: executing update function"
time="2026-10-02T11:23:20Z" level=debug msg="Starting container update check"
time="2026-10-02T11:23:20Z" level=debug msg="Sending notification" message="Received HTTP API update request | method=GETpath=/v1/update" notify=no
time="2026-10-02T11:23:22Z" level=debug msg="Log entry queued for batching" entries_count=1 fields.level=info legacy_template=true message="Found new image" notify=no
time="2026-10-02T11:23:22Z" level=info msg="Found new image" container=easyai-web image="registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002" new_id=4161c653ff66
time="2026-10-02T11:23:23Z" level=debug msg="Log entry queued for batching" entries_count=2 fields.level=info legacy_template=true message="Found new image" notify=no
time="2026-10-02T11:23:23Z" level=info msg="Found new image" container=easyai-server image="registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002" new_id=72ec514ed221
time="2026-10-02T11:23:24Z" level=debug msg="Stopping container for restart" container=easyai-web image="registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002"
time="2026-10-02T11:23:24Z" level=debug msg="Log entry queued for batching" entries_count=3 fields.level=info legacy_template=true message="Stopping container" notify=no
time="2026-10-02T11:23:24Z" level=info msg="Stopping container" container=easyai-web id=877447f1cc84 signal=SIGTERM timeout=30s
time="2026-10-02T11:23:25Z" level=debug msg="Stopping container for restart" container=easyai-server image="registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002"
time="2026-10-02T11:23:25Z" level=debug msg="Log entry queued for batching" entries_count=4 fields.level=info legacy_template=true message="Stopping container" notify=no
time="2026-10-02T11:23:25Z" level=info msg="Stopping container" container=easyai-server id=5aadf9dad929 signal=SIGTERM timeout=30s
time="2026-10-02T11:23:27Z" level=debug msg="Starting container after update/restart" container=easyai-server image="registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002"
time="2026-10-02T11:23:28Z" level=debug msg="Log entry queued for batching" entries_count=5 fields.level=info legacy_template=true message="Started new container" notify=no
time="2026-10-02T11:23:28Z" level=info msg="Started new container" container=easyai-server id=5aadf9dad929 new_id=f2706ffec607
time="2026-10-02T11:23:28Z" level=debug msg="Started new container" container=easyai-server image="registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002" new_id=f2706ffec607
time="2026-10-02T11:23:28Z" level=debug msg="Restarted container" container=easyai-server image="registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002"
time="2026-10-02T11:23:28Z" level=debug msg="Starting container after update/restart" container=easyai-web image="registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002"
time="2026-10-02T11:23:30Z" level=debug msg="Log entry queued for batching" entries_count=6 fields.level=info legacy_template=true message="Started new container" notify=no
time="2026-10-02T11:23:30Z" level=info msg="Started new container" container=easyai-web id=877447f1cc84 new_id=67052e84930b
time="2026-10-02T11:23:30Z" level=debug msg="Started new container" container=easyai-web image="registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002" new_id=67052e84930b
time="2026-10-02T11:23:30Z" level=debug msg="Restarted container" container=easyai-web image="registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002"
time="2026-10-02T11:23:30Z" level=debug msg="Generated notification message" message="Found new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002 (4161c653ff66)\nFound new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002 (72ec514ed221)\nStopped stale container: easyai-web (877447f1cc84)\nStopped stale container: easyai-server (5aadf9dad929)\nStarted new container: easyai-server (f2706ffec607)\nStarted new container: easyai-web (67052e84930b)" notify=no
time="2026-10-02T11:23:30Z" level=debug msg="Preparing to send entries" error="<nil>" message="Found new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002 (4161c653ff66)\nFound new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002 (72ec514ed221)\nStopped stale container: easyai-web (877447f1cc84)\nStopped stale container: easyai-server (5aadf9dad929)\nStarted new container: easyai-server (f2706ffec607)\nStarted new container: easyai-web (67052e84930b)" notify=no
time="2026-10-02T11:23:30Z" level=info msg="Update session completed" failed=0 notify=no scanned=3 updated=2
time="2026-10-02T11:23:30Z" level=debug msg="Handler: update function completed"
time="2026-10-02T11:23:30Z" level=debug msg="Handler: releasing lock"
time="2026-10-02T11:23:30Z" level=debug msg="Sending notification" message="Found new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002 (4161c653ff66)\nFound new image: registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002 (72ec514ed221)\nStopped stale container: easyai-web (877447f1cc84)\nStopped stale container: easyai-server (5aadf9dad929)\nStarted new container: easyai-server (f2706ffec607)\nStarted new container: easyai-web (67052e84930b)" notify=no
@@ -0,0 +1,6 @@
/easyai-server sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea healthy
/easyai-web sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 healthy
sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea ["registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server@sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491"]
sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f ["registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai@sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0"]
sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 ["registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25"]
@@ -0,0 +1,252 @@
[
{
"id": "154b6781-dd24-434d-94a5-4bf59122c0bb",
"idempotencyKey": "c00a35c9-6e10-4ab1-9915-5e44f58e2daf",
"action": "update",
"source": "manual",
"status": "succeeded",
"phase": "finished",
"message": "更新完成,所有核心服务均已通过检查",
"createdAt": "2026-10-02T11:37:32.825Z",
"updatedAt": "2026-10-02T11:38:26.397Z",
"previousVersion": "3.22.0.20261002.1",
"components": [
{
"key": "server-main",
"containerName": "easyai-server",
"status": "succeeded",
"targetImageId": "sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea",
"previousImageId": "sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.21.0.6",
"ipv6Address": ""
},
"easyai_sandbox-network": {
"networkId": "b2daf0ea06fc85a171ed60f0a3fb7a58e7ca56fad15490fb2e589ad05e0ffffc",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.20.0.2",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
},
{
"key": "ws-gateway",
"containerName": "easyai-wsgateway",
"status": "succeeded",
"targetImageId": "sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5"
},
{
"key": "web",
"containerName": "easyai-web",
"status": "succeeded",
"targetImageId": "sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f",
"previousImageId": "sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-web",
"easyai-web"
],
"links": null,
"ipv4Address": "172.21.0.8",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
}
],
"executor": "updater",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:37:32.825Z",
"finishedAt": "2026-10-02T11:37:32.827Z"
},
{
"id": "prechecking",
"title": "检查环境",
"status": "completed",
"startedAt": "2026-10-02T11:37:32.827Z",
"finishedAt": "2026-10-02T11:37:32.829Z"
},
{
"id": "pulling",
"title": "下载更新",
"status": "completed",
"startedAt": "2026-10-02T11:37:32.829Z",
"finishedAt": "2026-10-02T11:37:33.478Z"
},
{
"id": "applying",
"title": "更新服务",
"status": "completed",
"startedAt": "2026-10-02T11:37:33.478Z",
"finishedAt": "2026-10-02T11:38:26.153Z"
},
{
"id": "verifying",
"title": "验证版本",
"status": "completed",
"startedAt": "2026-10-02T11:38:26.153Z",
"finishedAt": "2026-10-02T11:38:26.397Z"
},
{
"id": "finished",
"title": "完成",
"status": "completed",
"finishedAt": "2026-10-02T11:38:26.397Z"
}
],
"startedAt": "2026-10-02T11:37:32.827Z",
"releaseId": "online-update-progress-20261002",
"productVersion": "3.22.0.20261002.2",
"finishedAt": "2026-10-02T11:38:26.397Z"
},
{
"id": "d0f02915-1cbe-4063-94c6-e9d749aaf2d7",
"idempotencyKey": "c05c99af-affd-482b-98e1-eca9dea21c6b",
"action": "update",
"source": "manual",
"status": "rolled_back",
"phase": "finished",
"message": "新版本未能正常启动,已恢复原版本",
"createdAt": "2026-10-02T11:33:41.418Z",
"updatedAt": "2026-10-02T11:36:15.937Z",
"previousVersion": "3.22.0.20261002.1",
"components": [
{
"key": "server-main",
"containerName": "easyai-server",
"status": "rolled_back",
"targetImageId": "sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea",
"previousImageId": "sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.21.0.6",
"ipv6Address": ""
},
"easyai_sandbox-network": {
"networkId": "b2daf0ea06fc85a171ed60f0a3fb7a58e7ca56fad15490fb2e589ad05e0ffffc",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.20.0.2",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
},
{
"key": "ws-gateway",
"containerName": "easyai-wsgateway",
"status": "rolled_back",
"targetImageId": "sha256:4fb8a96a311686f59ab142dd150f7a2df8662a8b9f19233f9b06cfe548c899d6",
"previousImageId": "sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-wsgateway",
"ws-gateway"
],
"links": null,
"ipv4Address": "172.21.0.5",
"ipv6Address": ""
}
}
},
{
"key": "web",
"containerName": "easyai-web",
"status": "rolled_back",
"targetImageId": "sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f",
"previousImageId": "sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-web",
"easyai-web"
],
"links": null,
"ipv4Address": "172.21.0.8",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
}
],
"executor": "updater",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.421Z",
"finishedAt": "2026-10-02T11:33:41.426Z"
},
{
"id": "prechecking",
"title": "检查环境",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.426Z",
"finishedAt": "2026-10-02T11:33:41.432Z"
},
{
"id": "pulling",
"title": "下载更新",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.432Z",
"finishedAt": "2026-10-02T11:33:43.339Z"
},
{
"id": "applying",
"title": "更新服务",
"status": "completed",
"startedAt": "2026-10-02T11:33:43.339Z",
"finishedAt": "2026-10-02T11:35:11.300Z"
},
{
"id": "verifying",
"title": "验证版本",
"status": "failed",
"startedAt": "2026-10-02T11:35:11.300Z",
"finishedAt": "2026-10-02T11:36:15.936Z"
},
{
"id": "finished",
"title": "完成",
"status": "failed",
"finishedAt": "2026-10-02T11:36:15.936Z"
}
],
"startedAt": "2026-10-02T11:33:41.426Z",
"releaseId": "update-rollback-acceptance-20261002",
"productVersion": "3.22.0.20261002.2",
"reasonCode": "healthcheck_failed",
"finishedAt": "2026-10-02T11:36:15.936Z"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

@@ -0,0 +1,4 @@
/easyai-server sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af healthy
/easyai-web sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07 healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 healthy
{"status":"success","data":{"version":"3.22.0.20261002.1"},"message":"success"}
Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

@@ -0,0 +1,132 @@
{
"id": "d0f02915-1cbe-4063-94c6-e9d749aaf2d7",
"idempotencyKey": "c05c99af-affd-482b-98e1-eca9dea21c6b",
"action": "update",
"source": "manual",
"status": "rolled_back",
"phase": "finished",
"message": "新版本未能正常启动,已恢复原版本",
"createdAt": "2026-10-02T11:33:41.418Z",
"updatedAt": "2026-10-02T11:36:15.937Z",
"previousVersion": "3.22.0.20261002.1",
"components": [
{
"key": "server-main",
"containerName": "easyai-server",
"status": "rolled_back",
"targetImageId": "sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea",
"previousImageId": "sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.21.0.6",
"ipv6Address": ""
},
"easyai_sandbox-network": {
"networkId": "b2daf0ea06fc85a171ed60f0a3fb7a58e7ca56fad15490fb2e589ad05e0ffffc",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.20.0.2",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
},
{
"key": "ws-gateway",
"containerName": "easyai-wsgateway",
"status": "rolled_back",
"targetImageId": "sha256:4fb8a96a311686f59ab142dd150f7a2df8662a8b9f19233f9b06cfe548c899d6",
"previousImageId": "sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-wsgateway",
"ws-gateway"
],
"links": null,
"ipv4Address": "172.21.0.5",
"ipv6Address": ""
}
}
},
{
"key": "web",
"containerName": "easyai-web",
"status": "rolled_back",
"targetImageId": "sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f",
"previousImageId": "sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-web",
"easyai-web"
],
"links": null,
"ipv4Address": "172.21.0.8",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
}
],
"executor": "updater",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.421Z",
"finishedAt": "2026-10-02T11:33:41.426Z"
},
{
"id": "prechecking",
"title": "检查环境",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.426Z",
"finishedAt": "2026-10-02T11:33:41.432Z"
},
{
"id": "pulling",
"title": "下载更新",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.432Z",
"finishedAt": "2026-10-02T11:33:43.339Z"
},
{
"id": "applying",
"title": "更新服务",
"status": "completed",
"startedAt": "2026-10-02T11:33:43.339Z",
"finishedAt": "2026-10-02T11:35:11.300Z"
},
{
"id": "verifying",
"title": "验证版本",
"status": "failed",
"startedAt": "2026-10-02T11:35:11.300Z",
"finishedAt": "2026-10-02T11:36:15.936Z"
},
{
"id": "finished",
"title": "完成",
"status": "failed",
"finishedAt": "2026-10-02T11:36:15.936Z"
}
],
"startedAt": "2026-10-02T11:33:41.426Z",
"releaseId": "update-rollback-acceptance-20261002",
"productVersion": "3.22.0.20261002.2",
"reasonCode": "healthcheck_failed",
"finishedAt": "2026-10-02T11:36:15.936Z"
}
@@ -0,0 +1,128 @@
{
"id": "d0f02915-1cbe-4063-94c6-e9d749aaf2d7",
"idempotencyKey": "c05c99af-affd-482b-98e1-eca9dea21c6b",
"action": "update",
"source": "manual",
"status": "running",
"phase": "applying",
"message": "正在更新网页服务",
"createdAt": "2026-10-02T11:33:41.418Z",
"updatedAt": "2026-10-02T11:35:05.249Z",
"previousVersion": "3.22.0.20261002.1",
"components": [
{
"key": "server-main",
"containerName": "easyai-server",
"status": "succeeded",
"targetImageId": "sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea",
"previousImageId": "sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af",
"backupContainerName": "easyai-update-backup-d0f02915-server-main",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.21.0.6",
"ipv6Address": ""
},
"easyai_sandbox-network": {
"networkId": "b2daf0ea06fc85a171ed60f0a3fb7a58e7ca56fad15490fb2e589ad05e0ffffc",
"aliases": [
"easyai-server",
"easyai-server"
],
"links": null,
"ipv4Address": "172.20.0.2",
"ipv6Address": ""
}
},
"message": "新版本已通过检查"
},
{
"key": "ws-gateway",
"containerName": "easyai-wsgateway",
"status": "succeeded",
"targetImageId": "sha256:4fb8a96a311686f59ab142dd150f7a2df8662a8b9f19233f9b06cfe548c899d6",
"previousImageId": "sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5",
"backupContainerName": "easyai-update-backup-d0f02915-ws-gateway",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-wsgateway",
"ws-gateway"
],
"links": null,
"ipv4Address": "172.21.0.5",
"ipv6Address": ""
}
}
},
{
"key": "web",
"containerName": "easyai-web",
"status": "verifying",
"targetImageId": "sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f",
"previousImageId": "sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07",
"backupContainerName": "easyai-update-backup-d0f02915-web",
"networks": {
"easyai_easyai": {
"networkId": "c4265a68ef2b242f0a7d26e4a059d2d62e8aedf5db7029c27fc3676ea779b170",
"aliases": [
"easyai-web",
"easyai-web"
],
"links": null,
"ipv4Address": "172.21.0.8",
"ipv6Address": ""
}
}
}
],
"executor": "updater",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.421Z",
"finishedAt": "2026-10-02T11:33:41.426Z"
},
{
"id": "prechecking",
"title": "检查环境",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.426Z",
"finishedAt": "2026-10-02T11:33:41.432Z"
},
{
"id": "pulling",
"title": "下载更新",
"status": "completed",
"startedAt": "2026-10-02T11:33:41.432Z",
"finishedAt": "2026-10-02T11:33:43.339Z"
},
{
"id": "applying",
"title": "更新服务",
"status": "running",
"startedAt": "2026-10-02T11:33:43.339Z"
},
{
"id": "verifying",
"title": "验证版本",
"status": "pending"
},
{
"id": "finished",
"title": "完成",
"status": "pending"
}
],
"startedAt": "2026-10-02T11:33:41.426Z",
"releaseId": "update-rollback-acceptance-20261002",
"productVersion": "3.22.0.20261002.2"
}
@@ -0,0 +1,6 @@
/easyai-server sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea healthy
/easyai-web sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 healthy
sha256:72ec514ed221c424422542f7922f3962b03de969a65e3ffec058fa7cd70e1fea ["registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server@sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491"]
sha256:4161c653ff66e92e0f24f0b175bb9b3a447f095c0e55b238f480a12ddce2821f ["registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai@sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0"]
sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 ["registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

@@ -0,0 +1,4 @@
/easyai-server sha256:6a809aacd82dd70c23ef1f3873bab3f46c7daa824a5c3b6196bfb6dadb1718af 2026-10-02T11:25:01.404278562Z healthy
/easyai-web sha256:73689c521bdc5ecb57171c0fc629b6746491769dd2e015b9abb4e0d6091cbc07 2026-10-02T11:25:03.264453447Z healthy
/easyai-wsgateway sha256:821ed6a69be4771c57a7bf67084455a4c0c7e4c9e201b8e7bcb2dedf1fb229f5 2026-09-29T07:22:22.307885848Z healthy
/easyai-watchtower-1 sha256:6ba1e78a0c9ce1ae5389ecf8a78426b82beaf3357c71d52548f7d05fd92eebb7 2026-10-02T11:25:01.394675669Z healthy
@@ -0,0 +1,459 @@
[
{
"time": "2026-10-02T11:15:34.439Z",
"path": "/api/app/update-jobs",
"status": 200,
"value": {
"status": "success",
"data": [],
"message": "success"
}
},
{
"time": "2026-10-02T11:22:54.730Z",
"path": "/api/app/update-jobs",
"status": 500,
"value": {
"statusCode": 500,
"timestamp": "2026-10-02T11:22:54.644Z",
"path": "/app/update-jobs?active=true&limit=1",
"message": "getaddrinfo EAI_AGAIN easyai-updater",
"traceId": "yGyuK8eBkaXeNsMy",
"appVersion": "3.22.0.20261002.1",
"diagnosticCode": "RequestError"
}
},
{
"time": "2026-10-02T11:23:20.074Z",
"path": "/api/app/update-capabilities",
"status": 200,
"value": {
"status": "success",
"data": {
"mode": "legacy_watchtower",
"jobApi": false,
"executorReachable": false
},
"message": "success"
}
},
{
"time": "2026-10-02T11:23:26.733Z",
"path": "/api/app/update",
"status": 502
},
{
"time": "2026-10-02T11:23:28.856Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:30.935Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:33.033Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:35.153Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:37.254Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:39.392Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:41.490Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:43.622Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:45.733Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:47.824Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:49.905Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:51.995Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:54.094Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:56.194Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:23:58.414Z",
"path": "/api/health/update-ready",
"status": 502
},
{
"time": "2026-10-02T11:24:20.993Z",
"path": "/api/health/update-ready",
"status": 200,
"value": {
"status": "ok",
"service": "easyai-server-main",
"version": "3.22.0.20261002.2",
"buildId": "3.22.0.20261002.2",
"timestamp": "2026-10-02T11:24:20.920Z",
"uptime": 42.086032874,
"dependencies": {
"mongo": "ok",
"redis": "ok",
"rabbitmq": "ok"
}
}
},
{
"time": "2026-10-02T11:25:52.477Z",
"path": "/api/app/update-jobs",
"status": 200,
"value": {
"status": "success",
"data": [],
"message": "success"
}
},
{
"time": "2026-10-02T11:25:58.757Z",
"path": "/api/app/update-capabilities",
"status": 200,
"value": {
"status": "success",
"data": {
"mode": "legacy_watchtower",
"executor": "watchtower",
"jobApi": true,
"eventApi": true,
"realtime": true,
"executorReachable": true
},
"message": "success"
}
},
{
"time": "2026-10-02T11:25:58.910Z",
"path": "/api/app/update-jobs",
"status": 201,
"value": {
"status": "success",
"data": {
"id": "wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"idempotencyKey": "9bb11e4f-924a-4fd5-a501-86150a35e147",
"action": "update",
"source": "manual",
"executor": "watchtower",
"status": "queued",
"phase": "queued",
"message": "更新任务已保存,正在提交更新请求",
"previousVersion": "3.22.0.20261002.1",
"productVersion": "3.22.0.20261002.2",
"createdAt": "2026-10-02T11:25:58.856Z",
"updatedAt": "2026-10-02T11:25:58.856Z",
"startedAt": "2026-10-02T11:25:58.856Z",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "running",
"startedAt": "2026-10-02T11:25:58.856Z"
},
{
"id": "applying",
"title": "执行更新",
"status": "pending"
},
{
"id": "verifying",
"title": "等待服务恢复",
"status": "pending"
},
{
"id": "finished",
"title": "确认版本",
"status": "pending"
}
],
"components": []
},
"message": "success"
}
},
{
"time": "2026-10-02T11:25:59.020Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 200
},
{
"time": "2026-10-02T11:26:01.059Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 200,
"value": {
"status": "success",
"data": {
"id": "wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"idempotencyKey": "9bb11e4f-924a-4fd5-a501-86150a35e147",
"action": "update",
"source": "manual",
"executor": "watchtower",
"status": "running",
"phase": "applying",
"message": "更新服务已开始执行,正在检查、下载并更新服务",
"previousVersion": "3.22.0.20261002.1",
"productVersion": "3.22.0.20261002.2",
"createdAt": "2026-10-02T11:25:58.856Z",
"updatedAt": "2026-10-02T11:25:58.893Z",
"startedAt": "2026-10-02T11:25:58.856Z",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:25:58.856Z",
"finishedAt": "2026-10-02T11:25:58.893Z"
},
{
"id": "applying",
"title": "执行更新",
"status": "running",
"startedAt": "2026-10-02T11:25:58.893Z"
},
{
"id": "verifying",
"title": "等待服务恢复",
"status": "pending"
},
{
"id": "finished",
"title": "确认版本",
"status": "pending"
}
],
"components": []
},
"message": "success"
}
},
{
"time": "2026-10-02T11:26:01.259Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 200
},
{
"time": "2026-10-02T11:26:03.159Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:03.288Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:05.239Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:05.338Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:07.353Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:07.462Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:09.548Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:09.746Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:11.619Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:11.842Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:13.722Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:13.978Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:15.817Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:15.916Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:17.930Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:18.136Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:20.053Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:20.233Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:22.159Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:22.331Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:24.287Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:24.428Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:26.401Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:26.647Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:26:28.491Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 502
},
{
"time": "2026-10-02T11:26:28.654Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a/events",
"status": 502
},
{
"time": "2026-10-02T11:27:02.209Z",
"path": "/api/app/update-jobs/wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"status": 200,
"value": {
"status": "success",
"data": {
"id": "wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"idempotencyKey": "9bb11e4f-924a-4fd5-a501-86150a35e147",
"action": "update",
"source": "manual",
"executor": "watchtower",
"status": "succeeded",
"phase": "finished",
"message": "更新完成,目标版本和核心服务均已确认可用",
"previousVersion": "3.22.0.20261002.1",
"productVersion": "3.22.0.20261002.2",
"createdAt": "2026-10-02T11:25:58.856Z",
"updatedAt": "2026-10-02T11:26:41.594Z",
"startedAt": "2026-10-02T11:25:58.856Z",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:25:58.856Z",
"finishedAt": "2026-10-02T11:25:58.893Z"
},
{
"id": "applying",
"title": "执行更新",
"status": "completed",
"startedAt": "2026-10-02T11:25:58.893Z",
"finishedAt": "2026-10-02T11:26:39.560Z"
},
{
"id": "verifying",
"title": "等待服务恢复",
"status": "completed",
"startedAt": "2026-10-02T11:26:39.560Z",
"finishedAt": "2026-10-02T11:26:41.594Z"
},
{
"id": "finished",
"title": "确认版本",
"status": "completed",
"startedAt": "2026-10-02T11:26:41.594Z",
"finishedAt": "2026-10-02T11:26:41.594Z"
}
],
"components": [],
"finishedAt": "2026-10-02T11:26:41.594Z"
},
"message": "success"
}
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

@@ -0,0 +1,47 @@
{
"id": "wt-91612f117537604c18fc41bf214d06a8b0aeaa4956b2c42aad738d657c5f369a",
"idempotencyKey": "9bb11e4f-924a-4fd5-a501-86150a35e147",
"action": "update",
"source": "manual",
"executor": "watchtower",
"status": "succeeded",
"phase": "finished",
"message": "更新完成,目标版本和核心服务均已确认可用",
"previousVersion": "3.22.0.20261002.1",
"productVersion": "3.22.0.20261002.2",
"createdAt": "2026-10-02T11:25:58.856Z",
"updatedAt": "2026-10-02T11:26:41.594Z",
"startedAt": "2026-10-02T11:25:58.856Z",
"steps": [
{
"id": "queued",
"title": "提交请求",
"status": "completed",
"startedAt": "2026-10-02T11:25:58.856Z",
"finishedAt": "2026-10-02T11:25:58.893Z"
},
{
"id": "applying",
"title": "执行更新",
"status": "completed",
"startedAt": "2026-10-02T11:25:58.893Z",
"finishedAt": "2026-10-02T11:26:39.560Z"
},
{
"id": "verifying",
"title": "等待服务恢复",
"status": "completed",
"startedAt": "2026-10-02T11:26:39.560Z",
"finishedAt": "2026-10-02T11:26:41.594Z"
},
{
"id": "finished",
"title": "确认版本",
"status": "completed",
"startedAt": "2026-10-02T11:26:41.594Z",
"finishedAt": "2026-10-02T11:26:41.594Z"
}
],
"components": [],
"finishedAt": "2026-10-02T11:26:41.594Z"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

@@ -0,0 +1,31 @@
Update event timeline. Container configuration and authentication details omitted.
time=2026-10-02T11:25:58Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:25:58Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:25:58Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:25:58Z level=info msg="Received HTTP API update request" method=POST notify=no path=/v1/update
time=2026-10-02T11:25:58Z level=debug msg="Handler: trying to acquire lock" notify=no
time=2026-10-02T11:25:58Z level=debug msg="Handler: acquired lock for full update" notify=no
time=2026-10-02T11:25:58Z level=debug msg="Starting container update check"
time=2026-10-02T11:25:58Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:25:59Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:26:00Z level=info msg="Found new image" container=easyai-web image=registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002 new_id=4161c653ff66
time=2026-10-02T11:26:00Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:26:01Z level=info msg="Found new image" container=easyai-server image=registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002 new_id=72ec514ed221
time=2026-10-02T11:26:01Z level=debug msg="Stopping container for restart" container=easyai-web image=registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002
time=2026-10-02T11:26:01Z level=info msg="Stopping container" container=easyai-web id=41244005ea7a signal=SIGTERM timeout=30000
time=2026-10-02T11:26:01Z level=debug msg="Received HTTP API history request" method=GET notify=no path=/v1/history
time=2026-10-02T11:26:01Z level=debug msg="Stopping container for restart" container=easyai-server image=registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002
time=2026-10-02T11:26:01Z level=info msg="Stopping container" container=easyai-server id=cea3cafc9806 signal=SIGTERM timeout=30000
time=2026-10-02T11:26:03Z level=debug msg="Starting container with updated configuration" container=easyai-server image=registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002
time=2026-10-02T11:26:03Z level=debug msg="Starting container by ID" container_id=62a2a7eea3d6
time=2026-10-02T11:26:05Z level=debug msg="Container started successfully" container_id=62a2a7eea3d6
time=2026-10-02T11:26:05Z level=info msg="Started new container" container=easyai-server image=registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002 new_id=62a2a7eea3d6
time=2026-10-02T11:26:05Z level=debug msg="Restarted container" container=easyai-server image=registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:update-acceptance-20261002
time=2026-10-02T11:26:06Z level=debug msg="Starting container with updated configuration" container=easyai-web image=registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002
time=2026-10-02T11:26:06Z level=debug msg="Starting container by ID" container_id=6b1c321e8352
time=2026-10-02T11:26:07Z level=debug msg="Container started successfully" container_id=6b1c321e8352
time=2026-10-02T11:26:07Z level=info msg="Started new container" container=easyai-web image=registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002 new_id=6b1c321e8352
time=2026-10-02T11:26:07Z level=debug msg="Restarted container" container=easyai-web image=registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:update-acceptance-20261002
time=2026-10-02T11:26:07Z level=info msg="Update session completed" failed=0 notify=no scanned=3 skipped=0 updated=2
time=2026-10-02T11:26:07Z level=debug msg="Handler (async): update function completed" duration=8527.922807 notify=no
time=2026-10-02T11:26:07Z level=debug msg="Handler: releasing lock" notify=no
@@ -0,0 +1,23 @@
import pathlib,re,json,secrets,os,subprocess,hashlib
root=pathlib.Path('/home/admin/easyai');spec={'watchtowerBlock': ' watchtower:\n image: ${WATCHTOWER_IMAGE:-registry.cn-shanghai.aliyuncs.com/comfy-ai/watchtower-aliyun:1.22.3}\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - ${DOCKER_CONFIG_FILE:-/root/.docker/config.json}:/config.json:ro\n # 新安装只负责 easyai-updater 自身;存量环境未配置目标时保持原来的全容器扫描方式。\n command: --debug ${WATCHTOWER_UPDATE_TARGET:-}\n environment:\n - WATCHTOWER_POLL_INTERVAL=${SYSTEM_UPDATER_UPDATE_INTERVAL_SECONDS:-86400}\n - WATCHTOWER_CLEANUP=${WATCHTOWER_CLEANUP:-false}\n - WATCHTOWER_HTTP_API_HOST=0.0.0.0\n - WATCHTOWER_HTTP_API_ENDPOINTS=health,update,metrics,events,history\n - WATCHTOWER_HTTP_API_TOKEN=${WATCHTOWER_API_KEY}\n - WATCHTOWER_HTTP_API_EVENTS_TOKEN=${WATCHTOWER_HTTP_API_EVENTS_TOKEN}\n - WATCHTOWER_HTTP_API_PERIODIC_POLLS=${WATCHTOWER_HTTP_API_PERIODIC_POLLS:-false}\n restart: always\n labels:\n - "com.centurylinklabs.watchtower.enable=false"\n# ports:\n# - "${WATCHTOWER_PORT}:8080"\n read_only: true\n networks:\n easyai:\n ipv4_address: 172.21.0.9\n # 日志大小设置,避免日志文件过大\n logging:\n driver: "json-file"\n options:\n max-size: "100m"\n max-file: "10"\n', 'healthcheckBlocks': {'easyai-server': ' healthcheck:\n test: ["CMD-SHELL", "node -e \\"require(\'http\').get(\'http://127.0.0.1:3001/health/update-ready\', (res) => { res.resume(); process.exit(res.statusCode === 200 ? 0 : 1); }).on(\'error\', () => process.exit(1))\\""]\n interval: 30s\n timeout: 10s\n retries: 3\n start_period: 60s\n', 'easyai-web': ' healthcheck:\n test: ["CMD-SHELL", "node -e \\"require(\'http\').get(\'http://127.0.0.1:3010/health\', (res) => { res.resume(); process.exit(res.statusCode === 200 ? 0 : 1); }).on(\'error\', () => process.exit(1))\\""]\n interval: 10s\n timeout: 5s\n retries: 12\n start_period: 30s\n # 资源限制,防止内存溢出\n'}}
p=root/'.env';original=p.read_text();rows=original.splitlines();env={line.partition('=')[0]:line.partition('=')[2].strip().strip('"').strip("'") for line in rows if '=' in line and not line.lstrip().startswith('#')}
updates={'SYSTEM_UPDATE_MODE':'legacy_watchtower','SYSTEM_UPDATE_DEPLOYMENT_ID':'newfound-101200186210','WATCHTOWER_IMAGE':'registry.cn-shanghai.aliyuncs.com/comfy-ai/watchtower-aliyun:1.22.3','WATCHTOWER_UPDATE_TARGET':'easyai-server easyai-wsgateway easyai-web','WATCHTOWER_HTTP_API_PERIODIC_POLLS':'false','WATCHTOWER_CLEANUP':'false','WATCHTOWER_CORE_UPDATE_ENABLED':'true','WATCHTOWER_API_URL':'http://watchtower:8080'}
for key in ['WATCHTOWER_API_KEY','WATCHTOWER_HTTP_API_EVENTS_TOKEN']:
updates[key]=env[key] if len(env.get(key,''))>=32 else secrets.token_hex(32)
if updates['WATCHTOWER_API_KEY']==updates['WATCHTOWER_HTTP_API_EVENTS_TOKEN']:updates['WATCHTOWER_HTTP_API_EVENTS_TOKEN']=secrets.token_hex(32)
if not env.get('COMPOSE_FILE'):updates['COMPOSE_FILE']='docker-compose.yml:docker-compose.ice-v1.yml'
added=list(updates)
new=[k+'='+updates.pop(k) if k in updates else line for line in rows for k in [line.partition('=')[0]]];new.extend(k+'='+v for k,v in updates.items());stat=p.stat();p.write_text('\n'.join(new)+'\n');p.chmod(0o600);os.chown(p,stat.st_uid,stat.st_gid)
p=root/'docker-compose.yml';s=p.read_text();stat=p.stat()
def bounds(name):
start=s.index(' '+name+':');match=re.search(r'^ [A-Za-z0-9_-]+:',s[start+3:],re.M);return start,start+3+match.start() if match else len(s)
a,b=bounds('watchtower');wt=spec['watchtowerBlock']
if not pathlib.Path('/root/.docker/config.json').is_file():wt='\n'.join(line for line in wt.splitlines() if '/config.json:ro' not in line)+'\n'
s=s[:a]+wt+s[b:]
for name,health in spec['healthcheckBlocks'].items():
a,b=bounds(name);part=s[a:b]
if ' healthcheck:' not in part:s=s[:b]+health+s[b:]
p.write_text(s);os.chown(p,stat.st_uid,stat.st_gid)
backup=root/'data/deployment-backups/online-update-progress-20261002';(backup/'configuration-change.json').write_text(json.dumps({'envKeys':added,'mode':'legacy_watchtower','composeBeforeSha256':hashlib.sha256((backup/'docker-compose.yml').read_bytes()).hexdigest(),'composeAfterSha256':hashlib.sha256(p.read_bytes()).hexdigest(),'iceSha256':hashlib.sha256((root/'docker-compose.ice-v1.yml').read_bytes()).hexdigest()},indent=2));(backup/'configuration-change.json').chmod(0o600)
x=json.loads(subprocess.check_output(['docker','compose','config','--format','json'],cwd=root));assert 'easyai-updater' not in x['services'];assert not x['services']['watchtower'].get('ports');assert x['services']['easyai-server']['environment']['SYSTEM_UPDATE_MODE']=='legacy_watchtower';assert len(x['services']['watchtower']['environment']['WATCHTOWER_HTTP_API_TOKEN'])>=32
print(json.dumps({'configured':True,'mode':'legacy_watchtower','updaterContainerRequested':False,'watchtowerPublishedPorts':[],'changedEnvKeys':added}))
@@ -0,0 +1,55 @@
services:
easyai-server:
image: ${ACCEPT_SERVER_IMAGE}
labels:
com.centurylinklabs.watchtower.enable: "${ACCEPT_CORE_WATCHTOWER}"
environment:
SYSTEM_UPDATE_MODE: ${ACCEPT_UPDATE_MODE}
SYSTEM_UPDATE_DEPLOYMENT_ID: update-acceptance-20261002
WATCHTOWER_API_URL: http://watchtower:8080
WATCHTOWER_API_KEY: ${ACCEPT_WATCHTOWER_TOKEN}
WATCHTOWER_HTTP_API_EVENTS_TOKEN: ${ACCEPT_EVENTS_TOKEN}
APP_VERSION_CHECK_BASE_URL: http://update-version-catalog:18880
SYSTEM_UPDATE_INTERNAL_TOKEN: ${ACCEPT_UPDATER_TOKEN}
SYSTEM_UPDATE_SERVICE_URL: http://easyai-updater:3015
easyai-web:
image: ${ACCEPT_WEB_IMAGE}
labels:
com.centurylinklabs.watchtower.enable: "${ACCEPT_CORE_WATCHTOWER}"
environment:
NUXT_APP_CDN_URL: ""
NUXT_PUBLIC_BASE_APIURL: /api
NUXT_PUBLIC_BASE_SSRURL: http://easyai-server:3001
ws-gateway:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25
labels:
com.centurylinklabs.watchtower.enable: "${ACCEPT_CORE_WATCHTOWER}"
watchtower:
image: ${ACCEPT_WATCHTOWER_IMAGE}
command: ${ACCEPT_WATCHTOWER_COMMAND}
environment:
WATCHTOWER_HTTP_API_TOKEN: ${ACCEPT_WATCHTOWER_TOKEN}
WATCHTOWER_HTTP_API_EVENTS_TOKEN: ${ACCEPT_EVENTS_TOKEN}
WATCHTOWER_HTTP_API_HOST: 0.0.0.0
WATCHTOWER_HTTP_API_ENDPOINTS: health,update,metrics,events,history
WATCHTOWER_HTTP_API_PERIODIC_POLLS: "false"
WATCHTOWER_CLEANUP: "false"
easyai-updater:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/easyai-updater:1.1.0
environment:
SYSTEM_UPDATE_INTERNAL_TOKEN: ${ACCEPT_UPDATER_TOKEN}
UPDATE_MANIFEST_FILE: /var/lib/easyai-updater/release-manifest-20261002.json
UPDATE_HEALTH_TIMEOUT_MS: "60000"
networks:
easyai:
ipv4_address: 172.21.0.31
update-version-catalog:
image: registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:3.22.0.20261002.2
entrypoint: [node, -e]
command: ["require('node:http').createServer((q,s)=>{s.setHeader('content-type','application/json');s.end(JSON.stringify({status:'success',data:{version:'3.22.0.20261002.2'}}))}).listen(18880,'0.0.0.0')"]
labels:
com.centurylinklabs.watchtower.enable: "false"
restart: unless-stopped
networks:
easyai:
ipv4_address: 172.21.0.30
@@ -0,0 +1,7 @@
/easyai-server sha256:6825def1b7bf252eee477b34d3ddc0317e691f0787ea3f300793c4d272a3b491 running 0 healthy {"3001/tcp":[{"HostIp":"","HostPort":"3001"}]}
/easyai-web sha256:a287db622d13a706725520d3a9864f986b8854630d198fce3373a8e7f1cfe3b0 running 0 healthy {"3010/tcp":[{"HostIp":"","HostPort":"3010"}]}
/easyai-wsgateway sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25 running 0 {"3002/tcp":[{"HostIp":"","HostPort":"3002"}]}
/easyai-watchtower-1 sha256:6afd62a208687bb4840b3b8131e1461dee7033989e14e28b6d69082839eaf410 running 0 healthy {}
WARNING: Error parsing config file (/root/.docker/config.json): read /root/.docker/config.json: is a directory
WARNING: Error parsing config file (/root/.docker/config.json): read /root/.docker/config.json: is a directory
{"status":"ok","service":"easyai-server-main","version":"3.22.0.20261002.2","buildId":"3.22.0.20261002.2","timestamp":"2026-10-02T11:42:39.968Z","uptime":35.4169154,"dependencies":{"mongo":"ok","redis":"ok","rabbitmq":"ok"}}
@@ -0,0 +1,7 @@
history 200 {"api_version":"v1","count":0,"entries":[],"timestamp":"2026-10-02T11:43:51Z"}
status 204
events-with-update-token 401
events-with-event-token 200 text/event-stream
gateway-health 200
mode legacy_watchtower deployment newfound-101200186210 independentTokens true
registry.cn-shanghai.aliyuncs.com/comfy-ai/watchtower-aliyun:1.22.3 healthy {}
Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

@@ -0,0 +1,4 @@
{
"url": "https://newfound.top/api/app/version",
"text": "{\"status\":\"success\",\"data\":{\"version\":\"3.22.0.20261002.2\"},\"message\":\"success\"}"
}
@@ -0,0 +1,71 @@
[
{
"container": "easyai-server",
"imageId": "sha256:8493e5a4c82f6564d86925f4ab37061f6e6e3d9a6bb88db5fe5d25d3a7b7835b",
"imageRef": "registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server:latest",
"repoDigests": [
"registry.cn-shanghai.aliyuncs.com/comfy-ai/comfy-server@sha256:8493e5a4c82f6564d86925f4ab37061f6e6e3d9a6bb88db5fe5d25d3a7b7835b"
],
"startedAt": "2026-10-02T08:57:10.888579571Z",
"restartCount": 0,
"health": null,
"ports": {
"3001/tcp": [
{
"HostIp": "",
"HostPort": "3001"
}
]
}
},
{
"container": "easyai-web",
"imageId": "sha256:de461512c2937f39010454b7aa30f8dfdc3d6bf5521f31722c756715d34d83ee",
"imageRef": "registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:latest",
"repoDigests": [
"registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai@sha256:de461512c2937f39010454b7aa30f8dfdc3d6bf5521f31722c756715d34d83ee"
],
"startedAt": "2026-10-02T08:57:10.477953596Z",
"restartCount": 0,
"health": null,
"ports": {
"3010/tcp": [
{
"HostIp": "",
"HostPort": "3010"
}
]
}
},
{
"container": "easyai-wsgateway",
"imageId": "sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25",
"imageRef": "registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway:latest",
"repoDigests": [
"registry.cn-shanghai.aliyuncs.com/easyaigc/wsgateway@sha256:a2b5fb67384c7f0eca7c7a768b5deacb4c0d2195dfbeb6e16ef40d6dc097bf25"
],
"startedAt": "2026-09-28T07:22:48.994346059Z",
"restartCount": 0,
"health": null,
"ports": {
"3002/tcp": [
{
"HostIp": "",
"HostPort": "3002"
}
]
}
},
{
"container": "easyai-watchtower-1",
"imageId": "sha256:48700ed275baeedac5b6852b6ba8fbe6196dc8fd73fffdf89a5d19b59df10056",
"imageRef": "registry.cn-shanghai.aliyuncs.com/comfy-ai/watchtower-aliyun:latest",
"repoDigests": [
"registry.cn-shanghai.aliyuncs.com/comfy-ai/watchtower-aliyun@sha256:48700ed275baeedac5b6852b6ba8fbe6196dc8fd73fffdf89a5d19b59df10056"
],
"startedAt": "2026-04-16T01:35:39.204197353Z",
"restartCount": 0,
"health": "healthy",
"ports": {}
}
]
@@ -0,0 +1,3 @@
livez 200 OK
readyz 200 OK
startupz 200 OK
@@ -0,0 +1 @@
{"status":"success","data":{"version":"3.22.0.20260930.3"},"message":"success"}