# windows_image_run **Repository Path**: mail_osc/windows_image_run ## Basic Information - **Project Name**: windows_image_run - **Description**: 在windows上运行一个镜像,直接做成exe的运行软件,镜像集成在内,一键运行。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-06 - **Last Updated**: 2026-06-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Windows 一键运行 Docker 化 Web 服务计划 ## 1. 目标 本项目第一阶段做一个面向普通 Windows 用户的便携式启动器。用户解压压缩包后双击启动器,通过内置 HTML UI 点击启动,即可运行随包预置的 Linux Docker Host,并由这个 Docker Host 自动启动便携包内的 Docker 镜像和 `docker-compose.yml`。 第一阶段只追求最小可运行闭环: - Windows 端提供启动器、内置 HTML UI、状态显示、日志和受限控制 API。 - 启动器通过 QEMU 启动随包预置的最小 Linux Docker Host。 - Docker Host 内部会校验便携包内固定目录的 Docker 镜像 tar,首次或镜像包变化时导入镜像,然后执行固定 `docker-compose.yml`。 - 业务形态先按普通 Web 服务处理,不做 Linux 桌面、VNC、noVNC 或远程桌面。 - 发布形态优先做便携压缩包,不优先做安装包。 - 便携包内置固定 WebView2 Runtime,启动器用 Rust 原生窗口承载 UI,不依赖用户系统浏览器才能打开控制界面。 - Docker Host 基础镜像只读,每次运行创建临时 overlay;需要长期保存的业务数据通过 `dataBackups` 按配置同步到 Windows 侧。 - 支持固定 `docker-compose` 项目目录(含 `docker-compose.yml`、`images/`、`volumes/`)、CPU/内存手动配置。 - 同一便携包禁止多实例运行,避免 QEMU、临时 overlay、Docker 数据、volumes 和 `dataBackups` 并发冲突。 ## 2. 第一阶段原则 - 可运行闭环优先,先保证解压、双击、启动、停止、看状态、看日志。 - 用户只需要按约定放入 Docker 镜像 tar 和 `docker-compose.yml`,不需要进入 QEMU 虚拟机内部操作。 - 普通用户权限运行,不默认要求管理员权限。 - 便携包目录移动或重命名后必须继续可用。 - 所有运行时路径都从便携包根目录相对解析,禁止写死绝对路径。 - UI 只能调用后端白名单 API。 - UI 不允许传入任意 QEMU 参数、任意系统命令或任意主机路径。 - 后端只暴露便携包内固定目录给 Docker Host。 - 后端负责所有参数校验和系统操作。 - 不自动添加 Defender 或其他杀软排除项。 - 不做加壳、反调试、内存加载 DLL、自解密等高误报行为。 - 公开发布前再处理标准代码签名、许可证、源码获取说明和第三方组件合规,不把这些作为本地 MVP 跑通的前置条件。 ## 3. 第一阶段 MVP 边界 ### 3.1 系统与发布范围 - 支持 Windows 10 21H2+ x64。 - 支持 Windows 11 x64。 - 不支持 Win7、Win8、32 位 Windows。 - 第一阶段只做便携压缩包。 - 便携包体积不设硬性上限,优先完成可运行闭环。 - 不写系统目录。 - 不修改系统注册表。 - 不要求用户安装 Docker Desktop、WSL、Hyper-V 或额外运行时。 ### 3.2 Linux Docker Host - 基础镜像:随包预置可启动的 Linux Docker Host qcow2。 - 文件位置:`images/base/docker-host.qcow2`。 - 基础镜像职责:启动 Linux、启动 Docker Engine、校验镜像缓存、在镜像包变化时导入容器镜像、自动执行 docker compose。 - 默认使用 QEMU TCG,避免依赖 BIOS 虚拟化开关和管理员权限。 - 使用 user-mode network。 - 基础镜像只读。 - 运行状态写入本次启动创建的 `data/state/qemu-overlays/run-*.qcow2` 临时 overlay;正常停止且最终同步成功后删除,异常退出时保留供人工排查。 - 启动前检查 `data/state/qemu-overlays/` 所在磁盘剩余空间;空间不足会阻止启动,避免 QEMU 写满宿主机磁盘后触发 Docker Host I/O 错误。 - Docker Host 只能访问便携包内固定暴露目录。 ### 3.3 用户提供的业务文件 用户只需要维护根目录下的 `docker-compose/` 业务项目目录,不需要进入 Docker Host: ```text docker-compose/ docker-compose.yml images/ *.tar / *.tar.gz / *.tgz volumes/ mnt/... opt/... ``` 简要规则: - `docker-compose/docker-compose.yml` 是唯一 compose 文件入口,多个服务和多个镜像都写在这一个文件里。 - `docker-compose/images/` 放业务镜像离线包,首次启动或镜像包变化时执行 `docker load`;未变化时复用 Docker Host 内已经导入的镜像。 - `docker-compose/volumes/` 按 Linux 绝对路径镜像配置和初始数据,例如 `docker-compose/volumes/mnt/service/config.properties` 对应 Docker Host 内的 `/mnt/service/config.properties`。 - 启动器会读取 `docker-compose.yml` 中显式发布的 TCP `ports`,并把这些 Docker Host 业务端口按相同端口号镜像到 Windows `127.0.0.1`。 详细放置规则、镜像命名、多个镜像一起启动、volumes 绝对路径映射和更新方式见:[docker-compose/README.md](docker-compose/README.md)。 ### 3.4 UI 与后端 API 第一阶段只做内置 HTML UI,不开放正式自定义 UI。 第一阶段 UI 只提供: - 启动。 - 停止。 - 状态查询和运行日志。 - 打开日志目录。 - 打开 volumes 目录。 - 导出 volumes 数据。 - 查看 SSH 调试连接信息。 Docker Host 的 CPU、内存和 QEMU 加速方式只从 `apps/config.json` 读取,不再通过 UI 或本地 API 运行态保存,避免出现多套配置来源。 第一阶段后端 API 白名单限定为: - `GET /api/preflight` - `GET /api/status` - `GET /api/logs` - `GET /api/ssh-credentials` - `POST /api/start` - `POST /api/stop` - `POST /api/export-volumes-data` - `POST /api/open-logs-dir` - `POST /api/open-volumes-dir` - `POST /api/open-project-page` - `GET /docker-host/getFile?path=`:读取 Docker Host 内指定常规文件内容,用于受控诊断和 UI 展示。返回 JSON:成功时为 `{"result":1,"info":"文件内容"}`;路径缺失、路径不是常规文件或读取失败时为 `{"result":0,"info":"错误原因"}`。例如 `GET http://127.0.0.1:18080/docker-host/getFile?path=/etc/hosts` 可读取 Docker Host 的 `/etc/hosts`,`/no/such/file` 会返回 `{"result":0,"info":"path is not a regular file"}`。 除上面明确列出的 Docker Host 文件诊断接口外,不开放 custom-ui、manifest、远程脚本、任意路径、任意命令或任意 QEMU 参数能力。 ### 3.5 QEMU 参数边界 第一阶段 QEMU 参数必须由后端生成,并保持受控: - `-machine accel=tcg` 作为默认。 - CPU 核心数来自用户配置,但必须校验范围。 - 内存大小来自用户配置,但必须校验范围。 - 使用 user-mode network。 - 使用只读 Docker Host 基础镜像和本次运行专属的可写临时 overlay。 - 固定暴露 `docker-compose/` 项目目录给 Docker Host。 第一阶段不开放显示分辨率、磁盘、网络、共享路径或任意 QEMU 参数配置。 ### 3.6 数据边界 - Docker Host 基础镜像放在 `images/base/`。 - QEMU 临时 overlay 放在 `data/state/qemu-overlays/`,每次启动新建,正常停止后清理,异常退出时保留。 - Docker 镜像 tar 放在 `docker-compose/images/`。 - compose 文件放在 `docker-compose/`。 - 日志放在 `logs/`。 - 配置和状态放在 `data/`。 - volumes 目录固定为 `docker-compose/volumes/`。 - `dataBackups/` 是 Windows 侧用户数据备份仓库,保存 `apps/config.json` 中 `dataBackups.paths` 声明的普通文件快照,以及 `dataBackups.mysql` 导出的 MySQL dump;当前固定保留 `latest/` 和 `previous/` 两份完整备份。 - UI 不提供打开 `data/` 目录的入口,避免普通用户误改内部配置或状态。 ### 3.7 进程与故障策略 - 禁止同一便携包多实例运行。 - 启动前必须获取单实例锁。 - 异常退出后锁必须可恢复,不长期阻塞用户。 - 停止时先请求 Docker Host 优雅关机并让 compose 停止容器,超时后再强制终止 QEMU。 - QEMU 崩溃后仅提示失败并保留日志,不自动重启。 - 再次启动必须由用户主动触发。 ## 4. 第一阶段明确不做 - 不做 Win7/Win8/32 位 Windows 兼容。 - 不优先做安装包。 - 不要求用户安装 Docker Desktop。 - 不调用用户系统 Docker。 - 不做 Linux 桌面、VNC、noVNC 或远程桌面。 - 不做正式自定义 UI 扩展体系。 - 不开放任意 QEMU 参数。 - 不允许 UI 传任意主机路径。 - 不允许 UI 传任意系统命令。 - 不允许同一便携包多实例运行。 - 不打开内部 `data/` 目录给普通用户。 - 不把 overlay 当成用户数据备份介质。 - 不从上一次运行的 overlay 自动恢复用户环境。 - 不做重置环境按钮。 - 不做替换 Docker Host 基础镜像升级。 - 不做 WHPX 硬件加速开关。 - 不自动添加 Defender 或其他杀软排除项。 - 不修改杀软配置。 - 不写系统目录。 - 不修改系统注册表。 - 不默认要求管理员权限。 ## 5. 第一阶段仓库结构 ```text windows_image_run/ apps/ config.json launcher/ ui/ runtime/ webview2/ qemu/ firmware/ images/ base/ docker-host.qcow2 docker-compose/ README.md docker-compose.yml images/ *.tar / *.tar.gz / *.tgz volumes/ data/ config/ state/ qemu-overlays/ dataBackups/ logs/ docs/ requirements_zh.md docker_host_contract_zh.md ``` 说明: - `runtime/`、`images/`、`docker-compose/`、`data/`、`logs/` 都必须按便携包根目录相对路径解析。 - 第一阶段不创建 `backups/` 作为用户功能目录,避免提前引入备份/恢复语义。 - `LICENSES/`、`NOTICE`、`SOURCE-OFFER` 和发布检查清单放到公开发布前再补,不进入第一阶段最小骨架。 ## 6. 执行步骤 1. 固化 Docker Host 方案需求文档。 2. 建立最小目录骨架。 3. 实现便携包相对路径解析和单实例锁。 4. 跑通 Rust 原生 WebView2 控制窗口打开 HTML UI。 5. 跑通 HTML 按钮调用后端启动 QEMU。 6. 接入 Docker Host 基础镜像、临时 overlay、固定 `docker-compose/` 项目目录和 `dataBackups` 恢复/同步流程。 7. 补齐诊断、停止、崩溃处理、日志和第一阶段测试矩阵。 拿到 QEMU、qemu-img、Docker Host 基础镜像、Docker 镜像 tar 和 `docker-compose.yml` 后,可以先运行: ```powershell powershell -ExecutionPolicy Bypass -File scripts/check-runtime-layout.ps1 ``` 该脚本只检查文件位置和 qcow2 基础格式,不会修改运行时目录。 ## 7. 本地启动测试与发布清理 ### 7.1 本地测试启动 启动前先确认运行布局: ```powershell powershell -ExecutionPolicy Bypass -File scripts/check-runtime-layout.ps1 ``` 全部显示 `[OK]` 后再启动。当前仓库开发态可以双击根目录: ```text restart.bat ``` 或在终端运行: ```powershell .\restart.bat ``` `restart.bat` 会先停止当前便携包内已运行的启动器和 QEMU;如果已经启动,双击它就是重启。源码开发目录下只要存在 `apps/launcher/Cargo.toml`,它就会先执行 `cargo build -p windows-image-run-launcher`,再把构建产物复制到根目录启动,避免根目录旧 exe 继续使用已经废弃的目录规则。发布包不包含源码时,则直接启动根目录 `windows-image-run-launcher.exe`。 双击启动器后会先显示启动器内置自检窗口。这个自检页由启动器代码内嵌生成,不读取 `apps/ui` 下的业务 HTML;它会检查 `apps/config.json`、固定 WebView2 Runtime、业务 UI 文件、QEMU、基础镜像、`docker-compose.yml`、离线镜像包和固定端口。自检通过后才进入 `apps/ui/index.html` 业务界面;自检失败时会停留在启动器自检窗口,显示具体失败项和处理建议。 自检还会检查 QEMU 临时 overlay 所在磁盘的剩余空间,最低要求按 `max(10GiB, docker-compose/images 镜像包总大小 * 5 + 2GiB)` 估算。空间不足时不要强行启动,应清理磁盘或把整个便携包移动到空间充足的磁盘。 进入业务界面后点击“启动”。Docker Host 会启动 QEMU,校验 `docker-compose/images/` 下的镜像包缓存,必要时导入镜像,并执行 `docker-compose/docker-compose.yml`。UI 只有在 `apps/config.json` 里配置的健康检查 URL 返回期望状态码时,才把业务判定为已启动成功。 业务 Web 服务按 `docker-compose.yml` 的 host port 从 Windows 访问。例如 compose 写 `8080:8080` 时访问: ```text http://127.0.0.1:8080 ``` 默认健康检查配置示例: ```json { "size": { "width": 960, "height": 720 }, "healthCheck": { "url": "http://127.0.0.1:8080/health.do", "expectedStatus": 200 } } ``` `size` 控制双击启动器后打开的 Rust WebView2 控制窗口初始大小。`healthCheck.url` 只允许本机回环 HTTP 地址,例如 `http://127.0.0.1:8080/health.do`;如果健康检查没有返回 `expectedStatus`,UI 会继续显示启动中或健康检查未通过,而不会把 QEMU 进程启动误报成业务可用。 如果控制窗口没有打开,优先查看 `logs/` 下启动器日志;常见原因是 `runtime/webview2` 中缺少固定 WebView2 Runtime。 ### 7.2 测试数据不会污染基础盘 `images/base/docker-host.qcow2` 是基础盘,不直接写入运行状态。启动器每次启动前都会通过 `qemu-img` 创建本次运行专属的临时 overlay: ```text data/state/qemu-overlays/run-*.qcow2 ``` Docker 加载进去的业务镜像、容器状态、Docker 数据和虚拟机运行状态会写入该临时 overlay。本地测试不会污染 `images/base/docker-host.qcow2`。 正常停止且 `dataBackups` 最终同步成功后,临时 overlay 会被删除;异常退出、停止失败或最终同步失败时,临时 overlay 会保留在 `data/state/qemu-overlays/` 供人工排查,但下次启动不会复用它。需要长期保存的普通文件应配置在 `apps/config.json` 的 `dataBackups.paths` 中;MySQL 应配置在 `dataBackups.mysql` 中通过 `mysqldump` 备份。Windows 侧 `dataBackups/` 仓库保存 `latest/` 和 `previous/` 两份完整备份。 ### 7.3 发布前清理规则 发布给别人前应保留: ```text runtime/qemu/ images/base/docker-host.qcow2 docker-compose/docker-compose.yml docker-compose/images/ docker-compose/volumes/mnt/service/config.properties docker-compose/volumes/mnt/service/domain.json ``` 发布给别人前不要带: ```text data/state/ logs/ dataBackups/ ``` 如果业务不希望带测试数据,还应清空这些运行数据目录,只保留目录本身: ```text docker-compose/volumes/mnt/service/logs/ docker-compose/volumes/mnt/service/cache/ docker-compose/volumes/mnt/service/data/ docker-compose/volumes/mnt/redis/datafile/ ``` 本地测试后想恢复干净状态,可以先停止启动器和 QEMU,然后删除: ```powershell Remove-Item -LiteralPath data/state/qemu-overlays/run-*.qcow2 -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath logs/* -Recurse -Force Remove-Item -LiteralPath data/state/* -Recurse -Force Remove-Item -LiteralPath docker-compose/volumes/mnt/service/logs/* -Recurse -Force Remove-Item -LiteralPath docker-compose/volumes/mnt/service/cache/* -Recurse -Force Remove-Item -LiteralPath docker-compose/volumes/mnt/service/data/* -Recurse -Force Remove-Item -LiteralPath docker-compose/volumes/mnt/redis/datafile/* -Recurse -Force ``` 这些命令只清理运行态文件,不会删除 Docker Host 基础盘和业务镜像包。注意不要在未确认业务数据已不需要时删除 `dataBackups/`。 ## 8. 第一阶段验收标准 - 双击便携包内启动器后能通过 Rust 原生 WebView2 控制窗口先打开启动器自检窗口,自检通过后再进入内置 HTML UI。 - UI 显示启动中、运行中、失败、已停止等状态。 - 点击启动后能启动随包预置的 Docker Host。 - Docker Host 首次或镜像包变化时自动加载 `docker-compose/images/*.tar`。 - Docker Host 自动执行 `docker-compose/docker-compose.yml`。 - 用户不需要进入 QEMU 镜像内部操作。 - Web 服务可通过 compose `ports` 中的 host port 从 Windows `127.0.0.1` 访问。 - 用户可点击停止。 - QEMU 崩溃后 UI 显示失败状态并保留日志,不自动重启。 - 重复双击同一便携包不会启动第二个 QEMU 实例,并显示明确中文提示。 - 用户可输入 CPU 核心数和内存大小。 - 非法 CPU/内存配置会被后端拒绝并显示中文错误。 - QEMU 文件缺失、Docker Host 镜像损坏、compose 缺失、容器镜像缺失、固定 WebView2 Runtime 缺失或损坏、volumes 目录不可用、临时 overlay 目录不可写时,启动器自检窗口或 UI 显示中文错误并写入日志。 - QEMU 临时 overlay 所在磁盘剩余空间不足时,启动器自检窗口或 UI 显示中文错误并阻止启动。 - Docker Host 基础镜像保持只读。 - 临时 overlay 跟随便携包目录保存,异常退出时不会影响下次基于干净基础镜像启动。 - 便携包目录移动或重命名后,启动、Docker Host 镜像、临时 overlay、compose、docker-compose/images、日志、volumes 和 `dataBackups` 目录仍可正常工作。 - 中文路径和空格路径下能正常工作。 - 程序不写系统目录、不修改系统注册表、不默认要求管理员权限。 ## 9. 第一阶段测试矩阵 优先覆盖: - Windows 10 21H2+ x64。 - Windows 11 x64。 - 普通用户权限。 - 中文路径。 - 空格路径。 - 便携包目录移动或重命名。 - 便携包目录可写和不可写。 - 固定 WebView2 Runtime 缺失或损坏。 - QEMU 文件缺失。 - Docker Host 镜像缺失或损坏。 - `docker-compose/docker-compose.yml` 缺失。 - `docker-compose/images/` 没有镜像 tar。 - 临时 overlay 目录缺失、不可写或存在上次异常退出残留文件。 - QEMU 临时 overlay 所在磁盘剩余空间不足。 - `docker-compose/volumes` 目录异常。 - 低内存。 - CPU/内存配置异常。 - 同一便携包多开。 - 停止超时。 - QEMU 异常退出。 - 杀软开启。 ## 10. 风险点 ### R1:Docker Host 镜像维护 Docker Host qcow2 需要预装 Docker Engine、compose 能力和自动启动脚本。它比完整桌面镜像轻,但仍然是需要维护的基础虚拟机镜像。 应对: - Docker Host 只做运行底座,不放业务逻辑。 - 业务逻辑继续由 Docker 镜像 tar 和 compose 文件提供。 - Docker Host 启动脚本只读取固定目录。 ### R2:固定 WebView2 Runtime 增加包体积 固定 WebView2 Runtime 可降低用户环境差异,但会增加发布包体积和维护成本。 应对: - 固定 Microsoft Edge WebView2 Runtime 版本,并把 Fixed Version Runtime 解压到 `runtime/webview2/`。 - 在发布文档中记录 WebView2 Runtime 版本、来源和校验信息。 - 后续再评估安装包模式或系统 WebView2 Runtime 模式。 ### R3:volumes 目录数据安全 可读写共享会扩大数据安全风险。 应对: - 只发布便携包内固定 `docker-compose/volumes` 目录。 - 后端拒绝任意主机路径输入。 - UI 不暴露任意路径选择。 ### R4:Docker 镜像和 compose 兼容性 用户提供的 Docker 镜像和 compose 文件可能依赖特定端口、环境变量、卷或网络行为。 应对: - 第一阶段只支持固定 compose 文件。 - Docker Host 内的启动脚本负责输出 compose 日志。 - Web 服务端口约定写入 compose 文档。 ### R5:便携目录移动导致路径失效 便携包必须支持移动和重命名,不能依赖绝对路径。 应对: - 所有运行时路径从便携包根目录相对解析。 - 配置中避免保存绝对路径。 - 测试矩阵覆盖移动和重命名。 ### R6:多实例导致数据损坏 多个 QEMU 同时使用同一便携包的端口、Docker 数据、volumes 或 `dataBackups` 仓库可能造成数据损坏。 应对: - 启动前获取单实例锁。 - 检测已有实例时显示中文提示。 - 异常锁需要可恢复。 ### R7:杀软误报 QEMU、启动器和固定 WebView2 Runtime 可能被安全软件拦截。 应对: - 避免加壳、反调试、内存加载 DLL、自解密等行为。 - 不自动添加杀软排除项。 - 公开发布前使用标准代码签名。 - 发布说明中提供中文排查指引。 ### R8:开源和镜像合规 QEMU、Linux Docker Host、Docker Engine、Microsoft Edge WebView2 Runtime 和业务镜像涉及许可证、源码提供、商标和再分发义务。 应对: - 公开发布物包含许可证和源码获取说明。 - 记录精确版本、来源和构建配置。 - 主程序与 QEMU 保持进程边界。 - 业务镜像来源和许可由发布说明记录。 ## 11. 后续版本再做 - overlay 备份。 - overlay 恢复。 - 重置环境。 - 替换 Docker Host 基础镜像升级。 - 超过 `latest/previous` 的多版本备份。 - WHPX 硬件加速检测和开关。 - 安装包模式。 - 系统 WebView2 模式。 - 正式自定义 UI 扩展体系。 - Linux 桌面、VNC、noVNC 或远程桌面。 - 任意 compose 文件选择。 - 任意镜像目录选择。 ## 12. 当前运行通道记录 当前便携包不依赖 `virtfs/9p`、QEMU SMB、WHPX、Hyper-V、Docker Desktop 或宿主机 Docker。为了保证通用性,QEMU 固定使用 TCG 软件模拟,宿主和 Docker Host 之间只通过本机回环 TCP 端口通信。 - `127.0.0.1:18080`:启动器 UI/API 端口,用于内置页面和 `/api/status`、`/api/start`、`/api/stop` 等启动器控制接口。 - `127.0.0.1:18081`:启动器提供包文件服务,只给 Docker Host 拉取 `docker-compose/` 项目初始文件。 - `127.0.0.1:18082`:Windows SSH 调试入口,转发到 Docker Host 内的 `22`,用户名固定为 `guanleiming`,密码由启动器首次运行时随机生成并显示在控制界面。 - `127.0.0.1:18083`:Docker Host 导出和诊断服务,启动器可通过它导出 `docker-compose/volumes` 数据,也可读取 Docker/containerd/compose 状态。 - `127.0.0.1:18084`:QEMU monitor 优雅关机控制端口,只由启动器本机访问。 - `docker-compose.yml` 中显式发布的 TCP `ports`:按相同 host port 镜像到 Windows `127.0.0.1`,但不能使用 `18080`、`18081`、`18082`、`18083`、`18084` 这些保留端口。 `docker-compose/` 业务目录的文件放置、镜像包命名、多个镜像一起启动、volumes 绝对路径映射、导出边界和更新方式统一见:[docker-compose/README.md](docker-compose/README.md)。