部署指南:基于 systemd 的按需沙箱后端架构)
Windmill 临时后端管理器Ephemeral Backend Manager部署指南基于 systemd 的按需沙箱后端架构【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill导读本指南围绕 Windmill 仓库中的 ephemeral-backends/DEPLOYMENT.md 展开详细介绍如何将 Windmill 的 Ephemeral Backend Manager临时后端管理器以 systemd 服务形式部署在 Linux 主机上。通过本指南你将掌握该组件的完整部署流程、环境变量配置、HTTP 控制面 API、git worktree 资源池机制以及按需编译、启动、回收后端实例的全生命周期管理方法。该组件是 Windmill 在 CI/CD 与多租户测试场景下动态创建隔离后端的关键基础设施适合负责 Windmill 私有化部署、云端多租户环境或大规模评测/验收基础设施的工程师阅读。什么是 Ephemeral Backend ManagerEphemeral Backend Manager 是 Windmill 仓库中的一个独立子项目位于 ephemeral-backends/ 目录它以常驻服务的形式运行在 Linux 机器上核心职责包括在端口8001上监听 HTTP 请求作为管理控制面为每个请求创建Cloudflare 隧道将本地临时后端暴露到公网把隧道 URL 回写到 GitHub Actions 的 repository secret 中供 CI 工作流消费维护一个git worktree 池复用已检出的代码目录以加速增量编译按需启动临时 Windmill 后端每个实例自带 PostgreSQL 容器、独立端口、独立隧道在收到 SIGINT/SIGTERM 或达到超时后自动回收全部资源。从源码结构看该目录下共 8 个文件构成了一个自洽的 Bun/TypeScript 工程package.json 声明了两个入口spawn.ts与manager.ts其中 manager 作为总控进程spawn 负责单个后端的生命周期worktree-pool 负责代码目录复用logger 负责落盘日志与清理。整个系统不依赖额外数据库纯靠环境变量驱动非常适合作为一个独立的 systemd 单元托管。部署前置条件原文档 DEPLOYMENT.md 明确列出了部署前必须满足的 4 项前提逐条落实可以避免后续安装脚本报错Linux 机器 systemd建议 Ubuntu 20.04 或 Debian 11安装脚本使用apt-get安装依赖因此这两类发行版最顺滑。专用系统用户sandbox服务以该用户身份运行必须预先创建并赋予合适权限。仓库已克隆到固定路径安装脚本硬编码了仓库位置为/home/sandbox/ephemeral-backend/windmill需要以sandbox用户身份把 Windmill 仓库克隆到该路径。必需工具链Gitworktree 池与代码检出的基础Docker用于拉起每个临时后端自带的 PostgreSQL 容器且sandbox用户必须能访问 DockerBun以sandbox用户安装用于运行 manager 与 spawn 脚本Rust/Cargo用于编译 Rust 后端Windmill 后端本体是 Rust 工程Bubblewrap若缺失安装脚本会自动安装用于沙箱化后端进程Cloudflared若缺失安装脚本会自动安装用于创建 trycloudflare 隧道。安装脚本自动化流程仓库提供了 install.sh可以一键完成环境检查、依赖补齐、systemd 单元安装与服务注册。脚本必须以 root 运行会直接exit 1拒绝非 root 执行其完整流程如下用户与目录校验检查sandbox用户是否存在不存在则提示先执行sudo adduser --system --group sandbox、检查仓库目录/home/sandbox/ephemeral-backend/windmill是否存在、检查sandbox用户的 bun 是否可执行。依赖自动补齐bubblewrap 缺失时执行apt-get install -y bubblewrapcloudflared 缺失时按架构下载.deb安装包x86_64下载 amd64 包aarch64下载 arm64 包其他架构直接报错退出Docker 缺失时提示先安装 Docker 后重跑sandbox用户无法执行docker ps时自动执行usermod -aG docker sandbox将其加入 docker 组。环境文件初始化创建/etc/windmill-ephemeral-manager/目录权限 755若不存在/etc/windmill-ephemeral-manager/.env则从仓库内的 .env.template 复制随后将权限收紧为600仅 root 可读写保护其中的密钥。安装 systemd 单元将 windmill-ephemeral-manager.service 复制到/etc/systemd/system/执行systemctl daemon-reload与systemctl enable确保开机自启。环境变量配置详解安装完成后必须编辑/etc/windmill-ephemeral-manager/.env填写真实值。仓库中的 .env.template 定义了 3 个必需变量而 manager.ts 会在启动时逐一校验任何一个缺失都会直接退出变量用途生成/取值建议MANAGER_AUTH_TOKEN保护 manager 全部受保护端点/status、/spawn/*、/logs/*的 Bearer Token用openssl rand -hex 32生成强随机值同时需要把它添加到 GitHub 仓库的 secrets 中供 CI 调用GITHUB_TOKEN具备secrets作用域写权限的 GitHub Personal Access Token用于更新/删除 GitHub Actions secret创建 PAT 时勾选secrets写权限GIT_EE_DEPLOY_KEY_FILE访问windmill-ee-private仓库的只读 SSH deploy key 路径文件属主为sandbox权限 600例如/home/sandbox/.ssh/windmill_ee_deploy_key可选的运行时开关除了模板中的 3 个变量从 manager.ts 和 spawn.ts 的源码还可以确认以下可选环境变量服务启动时不会强制校验SKIP_CLOUDFLARED设置为任意非空值后manager 与后端实例都不再启动 cloudflared 隧道manager 中startCloudflared与updateGitHubSecret均被跳过spawn 中会直接以SKIP_CLOUDFLARED作为隧道 URL 回调适合在局域网内直连调试SKIP_SET_GH_SECRET跳过启动时写入、退出时删除 GitHub Actions secret 的步骤SKIP_BACKEND_BUILD跳过cargo build直接使用 worktree 中已编译好的 release 二进制注意 spawn.ts 的逻辑跳过编译能极大缩短实例拉起时间LICENSE_KEY透传给后端进程的 Windmill 企业版 License见 spawn.ts后端进程的环境变量刻意不继承完整process.env只透传LICENSE_KEY防止敏感信息泄漏。systemd 服务单元剖析安装脚本会把 windmill-ephemeral-manager.service 安装为系统服务其关键配置项如下Unit 段Afternetwork-online.targetWantsnetwork-online.target保证网络就绪后才启动因为启动阶段就要拉隧道、访问 GitHub APIService 段Usersandbox/Groupsandbox以专用低权限用户运行WorkingDirectory/home/sandbox/ephemeral-backend/windmill与脚本中硬编码的仓库路径一致EnvironmentFile/etc/windmill-ephemeral-manager/.env从外部文件注入全部环境变量ExecStartbun run ephemeral-backends/manager启动入口即 manager.tsRestarton-failureRestartSec10s失败后 10 秒自动重启LimitNOFILE65536、LimitNPROC4096放宽文件描述符与进程数上限每个临时后端都会派生 Postgres、cloudflared、bwrap 等多个子进程NoNewPrivilegestrue、PrivateTmptrue加固服务禁止提权并使用私有 /tmpStandardOutputjournal/StandardErrorjournal全部日志进入 journaldInstall 段WantedBymulti-user.target实现开机自启。安装后的初始化步骤install.sh结尾会打印下一步指引完整流程如下# 1. 编辑环境文件并填写真实值 sudo nano /etc/windmill-ephemeral-manager/.env # 2. 生成 MANAGER_AUTH_TOKEN 并写入 .env同时添加到 GitHub 仓库 secrets openssl rand -hex 32 # 3. 确保 SSH deploy key 存在且 sandbox 用户可读600 权限 sudo ls -l /home/sandbox/.ssh/windmill_ee_deploy_key # 4. 启动服务并验证 sudo systemctl start windmill-ephemeral-manager sudo systemctl status windmill-ephemeral-manager # 5. 查看实时日志manager 与各临时后端的日志都会经 journald 输出 sudo journalctl -u windmill-ephemeral-manager -f # 查看最近 100 行日志 sudo journalctl -u windmill-ephemeral-manager -n 100常用的服务管理命令还包括sudo systemctl stop/sudo systemctl restart。由于服务单元配置了Restarton-failure进程异常退出会自动拉起而正常停止则触发 SIGTERM 清理流程逐一回收所有临时后端资源详见下文优雅退出。服务架构与运行原理结合 manager.ts 的启动序列服务启动后依次完成初始化WorktreePool通过git worktree list --porcelain自动发现既有 worktree详见 worktree-pool.ts注册每 6 小时执行一次的日志清理定时器Logger.cleanupOldLogs()删除 /tmp 下超过 24 小时的日志文件用 Bun 内置 HTTP server 在 8001 端口提供控制面 API启动 cloudflared 隧道可通过SKIP_CLOUDFLARED关闭把https://tunnel-url用 libsodium 的crypto_box_seal加密后写入 GitHub 仓库 secretEPHEMERAL_BACKEND_QUEUE_URL详见 manager.ts。控制面 HTTP APImanager 基于 Bun 的Bun.serve实现定义了 4 类端点GET /health免鉴权健康检查返回{status:ok,timestamp:...}GET /status需要Authorization: Bearer MANAGER_AUTH_TOKEN返回所有活跃后端的 commit hash、短 hash、创建/超时时间、剩余存活分钟数、server/db 端口以及 worktree 池的total/inUse/available统计POST /spawn/{commit_hash}需要鉴权请求体必须携带resume_url与cancel_url字符串为指定 commit 拉起一个临时后端同一 commit 已有后端在跑时直接报错already runningGET /logs/{commit_hash}需要鉴权校验 commit hash 为 7~40 位十六进制字符后返回该实例的日志文件内容。同时 manager 对来源为https://app.windmill.dev的跨域请求返回 CORS 头Access-Control-Allow-Origin等并为所有需要鉴权的端点返回WWW-Authenticate: Bearer realmManager API的 401 响应。认证采用常量时间字符串比较authHeader \Bearer ${managerAuthToken}见 manager.ts因此 Token 一旦泄露任何持有者都能控制整台机器的临时后端生命周期务必妥善保管。git worktree 池加速编译的核心worktree-pool.ts 实现了资源复用机制对应原文档中描述的三大收益快速增量编译每个 worktree 独立于主仓库但共享同一份 git 对象库cargo build的target目录在 worktree 间复用后续实例无需从头编译高效资源利用worktree 只标记inUse释放后回到池中待复用避免了反复创建-删除目录的开销重启自动发现initialize()时解析git worktree list --porcelain把位于 base 路径下、形如worktree-id且非主 worktree 的条目重新登记进池子见 worktree-pool.ts。获取 worktree 时acquire(commitHash)优先复用空闲 worktree——执行git reset --hard、git clean -fd、git fetch origin后 checkout 目标 commit若没有空闲项则git worktree add新建。值得注意的是后端成功启动后 worktree 会被立即释放回池中见 spawn.ts因为二进制已编译并运行其他实例可以复用同一代码目录注释明确说明the binary is already compiled and running, so other spawns can reuse this worktree。临时后端的完整生命周期启动流程spawn每个临时后端由 spawn.ts 中的EphemeralBackend.spawn()驱动按顺序执行初始化 Logger以 commit hash 为标识在/tmp/windmill-ephemeral-logs/hash.log写日志路径中非法字符会被替换防止路径穿越见 logger.ts启动 cloudflared为后端创建独立的 trycloudflare 隧道通过正则从 stderr 中提取https://*.trycloudflare.com形式的 URL获取 worktree从池中acquire(commitHash)装配企业版代码读取 worktree 内backend/ee-repo-ref.txt中的 EE commit hash用GIT_EE_DEPLOY_KEY_FILE指定的 SSH key 克隆windmill-ee-private并 checkout 对应 commit随后执行./substitute_ee_code.sh --copy -d ee_path把企业版文件合入见 spawn.ts拉起 PostgreSQLdocker run --rm -p dbPort:5432 -e POSTGRES_PASSWORDchangeme -e POSTGRES_DBwindmill postgres:16并通过pg_isready轮询等待就绪Linux 下从172.17.0.1探测macOS/Windows 用host.docker.internal编译后端可用SKIP_BACKEND_BUILD跳过在 worktree 的backend目录执行cargo build --features 长串特性 --release特性列表包含enterprise、enterprise_saml、stripe、embedding、parquet、prometheus、openidconnect、cloud、jemalloc、agent_worker_server、tantivy、license、http_trigger、zip、oauth2、kafka、sqs_trigger、nats、otel、dind、postgres_trigger、mqtt_trigger、gcp_trigger、websocket、smtp、all_languages、private、mcp以及按平台区分的deno_core/deno_core_mac并设置SQLX_OFFLINEtrue避免联网查询 sqlx 元数据见 spawn.ts沙箱化启动后端用 bubblewrapbwrap以sandbox用户的 UID/GID 启动target/release/windmill绑定/home/sandbox、/tmp、/dev、/proc并--unshare-user隔离用户命名空间环境变量只透传LICENSE_KEY并注入DATABASE_URLpostgres://postgres:changemelocalhost:dbPort/windmill?sslmodedisable与PORTserverPort见 spawn.ts等待就绪并设置管理员密码监听 stdout 中出现 Windmill Enterprise Edition 视为启动成功30 秒超时随后用默认凭据adminwindmill.dev/changeme登录再通过/api/users/setpassword把管理员密码改为随机生成的adminPwdMath.random().toString(36).substring(2, 15)该密码会随resume_url回调上报给请求方上报就绪向请求中的resume_urlPOST{status:ready,timeoutAt:...,commitHash:...,adminPassword:...,tunnelUrl:...}并向 manager 返回 202 与tunnelUrl。端口分配与超时回收manager 为每个后端分配两组端口数据库端口从5433起、server 端口从8002起各扫描 100 个端口寻找未被占用的空闲项见 manager.ts。每个后端的最大存活时间为2 小时BACKEND_TIMEOUT_MS 120 * 60 * 1000到达后 manager 自动执行清理并从活跃表中移除。此外等待隧道 URL 的回调设置了 20 秒超时超时或 spawn 失败都会向resume_url上报{status:error,commitHash:...,error:...}注意源码注释说明此处故意用 resume_url 承载错误通知。优雅退出与资源回收当 systemd 下发 SIGINT/SIGTERM 时manager.ts 的cleanup()会按序回收全部资源且用isCleaningUp标志保证只执行一次停止 6 小时日志清理定时器调用 GitHub API 删除EPHEMERAL_BACKEND_QUEUE_URLsecret404 视为已删除可接受停止 HTTP server向 cloudflared 进程先发 SIGTERM、1 秒后再发 SIGKILL遍历所有活跃后端先清除各自超时定时器再逐个调用EphemeralBackend.cleanup()。单个后端的cleanup()见 spawn.ts则负责SIGTERM→SIGKILL 结束后端进程、结束 cloudflared、结束 PostgreSQL 容器、删除 EE 私有仓库克隆、把 worktree 释放回池不删除供复用。这种进程级回收 目录级复用的设计正是该系统能长时间稳定服务而无需频繁重建目录的原因。运维与排障建议日志双通道每个后端的日志既写入/tmp/windmill-ephemeral-logs/下的文件可通过GET /logs/{commit}拉取也由 manager 同步写回 journald因此sudo journalctl -u windmill-ephemeral-manager -f能看到完整的派生过程日志自动清理manager 每 6 小时调用Logger.cleanupOldLogs()删除超过 24 小时的.log文件避免长期运行后 /tmp 膨胀启动失败自愈单元配置了Restarton-failure但 manager 启动时若缺少GITHUB_TOKEN、MANAGER_AUTH_TOKEN或GIT_EE_DEPLOY_KEY_FILE会直接process.exit(1)排查时应优先检查.env是否存在、权限是否为 600、三个变量是否已填写权限链路sandbox用户需要同时具备 Docker 访问权usermod -aG docker后需重新登录才生效和对 deploy key 的读取权属主 sandbox、权限 600bubblewrap 以 sandbox 的 UID/GID 启动后端进程确保临时后端的进程沙箱边界正确企业版代码装配依赖网络启动阶段会经 SSH 克隆windmill-ee-private需要保证GIT_EE_DEPLOY_KEY_FILE指向的 key 有只读权限且目标主机能访问 GitHub。小结Ephemeral Backend Manager 是 Windmill 为按需、隔离、可回收的临时后端场景设计的完整解决方案它以 Bun 实现的 manager 作为控制面8001 端口 Bearer 鉴权 4 类 REST 端点以 git worktree 池解决多实例代码复用与增量编译问题以 Docker bubblewrap 组合实现数据库隔离与进程沙箱以 cloudflared 隧道打通公网访问并以 GitHub Actions secret 作为与 CI 之间的状态通道。部署时只需按 install.sh 的流程准备sandbox用户、仓库克隆、Bun/Docker/Rust 工具链再填写好 .env.template 中的三个必需变量即可通过 systemd 单元 windmill-ephemeral-manager.service 获得一个开机自启、崩溃自愈、退出即清理的临时后端供给服务。【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考