ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

screenpipe 持续集成实战:在 AWS EC2 Mac 专用宿主机上搭建持久化 macOS 发布 Runner

screenpipe 持续集成实战:在 AWS EC2 Mac 专用宿主机上搭建持久化 macOS 发布 Runner screenpipe 持续集成实战在 AWS EC2 Mac 专用宿主机上搭建持久化 macOS 发布 Runner【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe本指南围绕 infra/release-mac-runner 目录下的基础设施脚本与说明文档展开完整讲解 screenpipe 项目如何在 AWS 上以非 Ultra 的 Apple Silicon 专用宿主机 macOS Tahoe 自托管 GitHub Actions Runner的形态为Release App与Release Enterprise两条发布流水线提供长期驻留的 macOS 构建能力。读完本文你将掌握这套栈的选型逻辑、Provision 部署脚本的自动降级策略、CloudFormation 模板的关键参数、Xcode 的引导安装方式以及通过 AWS Systems Manager 完成 Runner 注册与 launchd 服务化安装的完整链路。一、为什么需要一台持久化的 macOS 发布 Runnerscreenpipe 是一个跨平台的本地优先local-first录屏 AI 记忆应用其桌面端基于 TauriRust WebView发布产物需要在 macOS、Windows、Linux 三个平台上分别签名、打包、上传。在 .github/workflows/release-app.yml 和 .github/workflows/release-enterprise.yml 两条手动触发的发布工作流中macOS 构建任务对环境的稳定性要求远高于常规 CI构建体积大、耗时长Rust 编译、Tauri 打包、代码签名与公证notarization都是重活单次执行往往需要数十分钟依赖缓存敏感Cargo registry、Rust toolchain、Bun 依赖、原生依赖、编译器缓存等一旦丢失重建成本极高发布节点不可随意波动发布流程从workflow_dispatch手动触发要求节点随叫随到。GitHub 官方托管的macos-latest属于按需分配的临时节点缓存与工具链需要反复预热。因此 screenpipe 在 AWS 上维护了一台常驻 EC2 Mac作为Release App与Release Enterprise两条工作流中 macOS 任务的专用自托管 RunnerWindows 与 Linux 任务则继续留在 GitHub 托管 Runner 上。与之平行的方案还有 infra/release-linux-runner 中的 Azure Linux 常驻节点两者共同构成 screenpipe 的自有发布农场。二、硬件选型与安全模型2.1 实例选型性能优先的降级顺序按 README.md 的说明该栈选用能在美国区域实际分配到的、最快的非 Ultra Apple 芯片专用宿主机优先级顺序为优先级实例类型芯片1mac-m4max.metalM4 Max2mac-m4pro.metalM4 Pro3mac2-m2pro.metalM2 Pro4mac-m4.metalM45mac2-m2.metalM2在 deploy.sh 中这一顺序被实现为候选类型数组for candidate_type in mac-m4max.metal mac-m4pro.metal mac2-m2pro.metal mac-m4.metal mac2-m2.metal; do部署的最终产物是一个带终止保护termination-protected的 macOS Tahoe 实例Tahoe 即 macOS 26搭配2 TiB 高性能 gp3 根卷。Tahoe AMI 的取值来自 AWS 公共参数/aws/service/ec2-macos/tahoe/arm64_mac/latest/image_id保证镜像始终跟随最新的 Tahoe Apple Silicon AMI。2.2 安全模型零入站 SSM 管理该实例的边界非常收敛无任何入站安全组规则安全组只放行出站流量见 template.yml 中RunnerSecurityGroup的SecurityGroupEgress配置无任何SecurityGroupIngress管理员通过AWS Systems ManagerSession Manager / Run Command进行连接与远程执行无需 SSH 端口暴露实例 IAM 角色仅挂载AmazonSSMManagedInstanceCore托管策略配合实例配置文件的 SSM 通道完成一切管理操作。这一设计使得发布节点虽然位于公网可达的 VPC 子网用于出站下载依赖与向 GitHub 拉取任务却几乎不存在可被扫描攻击的入口面。三、Provision一条命令完成宿主机分配与建栈3.1 部署脚本的自动降级逻辑执行以下命令即可完成 Provision./infra/release-mac-runner/deploy.shdeploy.sh 的核心思路是**先复用、后新建**的三段式降级查找全程使用set -euo pipefail保证失败即中断复用已存在的发布 Mac按Namescreenpipe-release-mac标签在us-east-2、us-east-1、us-west-2三个区域中查询pending/running/stopping/stopped状态的实例命中即直接输出实例信息并退出复用已分配但未使用的专用宿主机按同样标签查询stateavailable的 Dedicated Host命中即记录其HostId供后续使用按性能顺序现场分配依次遍历上文的 5 种实例类型 × 3 个区域 × 各可用区调用aws ec2 allocate-hosts尝试分配专用宿主机首次成功即跳出所有循环。分配时携带--auto-placement off显式指定部署、--host-recovery on宿主机故障自动恢复并打上Namescreenpipe-release-mac与Workloadscreenpipe-release两组标签。如果所有候选组合都无法分配脚本会输出明确错误并退出No permitted EC2 Mac Dedicated Host is currently allocatable in a US region3.2 可用环境变量覆盖脚本全程支持显式覆盖适合在已有宿主机、特定区域或特定实例类型场景下跳过自动查找环境变量作用默认行为AWS_REGION指定区域如us-east-2按us-east-2 → us-east-1 → us-west-2自动探测INSTANCE_TYPE显式指定实例类型按性能顺序自动尝试AVAILABILITY_ZONE显式指定可用区取该实例类型在该区域的第一个可用区EXISTING_HOST_ID复用既有 Dedicated Host为空时自动查找/分配STACK_NAMECloudFormation 栈名默认screenpipe-release-mac3.3 CloudFormation 部署宿主机确定后脚本调用 CloudFormation 完成资源编排aws cloudformation deploy \ --region $REGION \ --stack-name $STACK_NAME \ --template-file $(dirname $0)/template.yml \ --capabilities CAPABILITY_NAMED_IAM \ --parameter-overrides \ AvailabilityZone$AVAILABILITY_ZONE \ InstanceType$INSTANCE_TYPE \ ExistingHostId$EXISTING_HOST_ID \ --no-fail-on-empty-changeset部署完成后会输出栈的Outputs包含DedicatedHostId、InstanceId、RunnerName、RunnerLabel供后续注册脚本使用。四、CloudFormation 模板拆解一条龙构建发布节点template.yml 定义了发布节点所需的全部 AWS 资源值得逐块拆解4.1 参数一览参数类型默认值说明AvailabilityZoneAWS::EC2::AvailabilityZone::Name必填提供所选 EC2 Mac 类型的可用区MacOSImageIdAWS::SSM::Parameter::ValueAWS::EC2::Image::Id/aws/service/ec2-macos/tahoe/arm64_mac/latest/image_idTahoe Apple Silicon AMI 公共参数InstanceTypeStringmac-m4pro.metal取值限定在mac-m4max.metal/mac-m4pro.metal/mac-m4.metal/mac2-m2pro.metal/mac2-m2.metalExistingHostIdString空复用已分配的专用宿主机时传入RootVolumeSizeNumber2048最小512EBS 根卷容量GiB承载持久化工作区与编译缓存模板通过条件CreateRunnerHost: !Equals [!Ref ExistingHostId, ]控制是否新建 Dedicated Host——传入已有宿主机 ID 时自动跳过 Host 创建。4.2 网络与实例资源VPC / 子网 / 网关独立 VPC10.74.0.0/24公有子网10.74.0.0/27MapPublicIpOnLaunch: true经 Internet Gateway 默认路由0.0.0.0/0出网安全组仅出站、零入站IAMAmazonSSMManagedInstanceCore托管策略 实例配置文件Dedicated HostAutoPlacement: off、HostMaintenance: on、HostRecovery: on并带DeletionPolicy: RetainExceptOnCreate防止误删实例Affinity: hostTenancy: host绑定专用宿主机DisableApiTermination: true开启终止保护监控CloudWatch 告警监听StatusCheckFailed指标周期 60 秒、2 个评估周期实例状态检查失败即告警。4.3 启动模板与引导脚本Launch Template 中根卷配置为gp3、2048 GiB、16000 IOPS、1000 MB/s 吞吐、加密、DeleteOnTermination: false保证数据不随实例终止而丢失同时启用IMDSv2HttpTokens: required收紧元数据服务访问。UserData引导脚本在首次启动时完成大量工作日志落盘到/var/log/screenpipe-release-runner-bootstrap.log建立缓存与 Runner 目录/Users/ec2-user/screenpipe-cache持久化工作区/编译缓存与/Users/ec2-user/actions-runner并chown给ec2-user导入 AppleDeveloper ID 根证书DeveloperIDCA.cer、DeveloperIDG2CA.cer到系统钥匙串为后续代码签名铺路通过 Homebrew 安装工具链aria2 bun cmake ffmpeg gh git-lfs jq node sccache wget以及xcodesorg/made/xcodesXcode 版本管理工具安装 Rust 工具链rustup默认stable下载 GitHub Actions Runnerv2.336.0osx-arm64并解压到actions-runner目录落标记文件/var/db/screenpipe-release-runner-bootstrap-complete表示引导完成。4.4 栈输出栈完成后输出四个关键值DedicatedHostId、InstanceId、RunnerNamescreenpipe-release-mac、RunnerLabelscreenpipe-release-macos。后者正是两条发布工作流通过runs-on请求的自托管标签。五、安装 XcodeAMI 之外的必经步骤AWS 的 macOS AMI只包含 Command Line Tools不包含完整 Xcode 应用。因此注册 Runner 之前需要通过 Session Manager 以ec2-user身份连接实例用引导阶段装好的xcodes安装最新稳定版 Xcodexcodes install --latest --experimental-unxip sudo xcodebuild -license accept xcodebuild -runFirstLaunch xcodebuild -downloadComponent MetalToolchain xcodebuild -version各命令的作用xcodes install --latest --experimental-unxip下载并安装最新稳定版 Xcode--experimental-unxip启用更快的解包路径sudo xcodebuild -license accept接受 Xcode 许可协议签名流程必需xcodebuild -runFirstLaunch完成首次启动初始化安装额外组件、注册 SDKxcodebuild -downloadComponent MetalToolchain拉取Metal 工具链——screenpipe 的 macOS 录制依赖 Metal 相关的编译与链接能力缺失会导致链接失败xcodebuild -version确认安装结果。六、注册 Runner从 SSH 通道到 launchd 守护服务6.1 前置条件与触发命令Xcode 就绪后先完成gh的认证需要仓库管理员权限用于申请 Runner 注册令牌然后执行AWS_REGIONus-east-2 ./infra/release-mac-runner/configure-runner.sh6.2 注册脚本执行流程configure-runner.sh 内部完成以下工作申请注册令牌通过gh api向repos/screenpipe/screenpipe/actions/runners/registration-token发起 POST换取一次性REGISTRATION_TOKEN定位实例优先按Namescreenpipe-release-mac标签查询实例查询为空时回退到 CloudFormation 栈输出中的InstanceId仍可用INSTANCE_IDi-...环境变量显式指定SSM 远程执行以AWS-RunShellScript文档向实例发送一串命令依次执行xcodebuild -runFirstLaunch与xcodebuild -downloadComponent MetalToolchain确保签名/链接组件就绪以ec2-user身份运行 Runner 配置config.sh --unattended --replace --url https://github.com/screenpipe/screenpipe --token ... --name screenpipe-release-mac --labels screenpipe-release-macos --work /Users/ec2-user/screenpipe-cache/work——注意Runner 名称、标签、工作目录都在此一次性确定./svc.sh install安装 Runner 服务并将生成的 launchd plist 从用户级目录迁移到系统级/Library/LaunchDaemons/chown root:wheel、chmod 0644最后launchctl bootstrap system使其成为开机自启的无头headless守护服务通过plutil为 plist 注入EnvironmentVariables.PATH包含 Homebrew、Cargo 等路径确保 launchd 环境下的 PATH 完整等待与校验aws ssm wait command-executed等待命令执行完成再拉取StandardOutputContent/StandardErrorContent检查结果确认注册调用gh api repos/screenpipe/screenpipe/actions/runners查询名为screenpipe-release-mac的 Runner输出其name、status、busy与labels。6.3 服务化与隔离性Runner 以launchd LaunchDaemon形式常驻而非手动常驻进程具备以下特性系统级服务随实例启动自动拉起无需人工登录screenpipe-release-mac以仓库级repository-levelRunner注册而非组织级天然限制其只能服务本仓库的工作流标签screenpipe-release-macos是唯一被Release App与Release Enterprise两条工作流请求的自托管标签由于 Runner 属于上游仓库私有Fork 无法访问该 Runner从机制上杜绝了 Fork 借用发布节点执行代码的风险。七、与发布工作流的衔接在 release-app.yml 中check_commit作业会根据提交类型动态决定 macOS 构建节点常规路径使用 GitHub 官方macos-latest/macos-26而发布相关提交或手动workflow_dispatch触发则将macos_arm_runner与macos_x64_runner均指向screenpipe-release-macos随后构建矩阵中的 macOS 平台任务即落在自托管节点上- platform: ${{ needs.check_commit.outputs.macos_arm_runner || macos-latest }} - platform: ${{ needs.check_commit.outputs.macos_x64_runner || macos-26 }}从源码结构看这套动态选择 Runner的机制让日常开发使用官方节点、发布时刻切换到自托管节点成为可能既节约成本又保证发布环境的高可用与缓存优势。Release Enterprise工作流复用同一标签与文档中该实例专门服务 macOS 发布任务的描述一致。八、日常运维要点状态查询栈输出与gh api .../actions/runners查询均可确认 Runner 在线状态CloudWatchStatusCheckFailed告警覆盖实例健康实例管理实例带终止保护DisableApiTermination: true且 Host 与实例均采用RetainExceptOnCreate/Retain删除策略普通删除栈操作不会销毁数据卷与宿主机需在确认迁移完成后显式清理缓存持久化/Users/ec2-user/screenpipe-cache位于不随实例终止删除的 gp3 根卷2048 GiB上Runner 的--work目录与各类编译缓存共同复用该卷这是持久化 Runner相比临时节点的核心收益安全边界无入站规则 SSM 管理 IMDSv2 仓库级 Runner 发布类工作流专用标签形成纵深防御Fork 与外部仓库均无法触达该节点区域容量EC2 Mac Dedicated Host 存在区域容量约束部署脚本的三区域降级策略与宿主机复用逻辑正是为应对特定区域暂时无法分配的场景而设计。九、适用前提与限制本套栈面向screenpipe 内部发布基础设施其认证gh仓库管理员权限、区域美国区域、实例类型非 Ultra Apple 芯片均为该项目的特定配置直接复用时需按自身账号容量与合规要求调整EC2 Mac 按 Dedicated Host 计费常驻节点意味着持续成本适合发布频率较高的项目若发布频率低官方托管 Runner 缓存恢复可能是更经济的组合脚本中的 Runner 版本v2.336.0、Xcode 安装方式、AMI 参数均为当前仓库锁定的版本升级时需同步更新 template.yml 与 configure-runner.sh。十、小结screenpipe 的持久化 macOS 发布 Runner 是一套基础设施即代码的完整范式deploy.sh负责在多个美国区域间按性能降级顺序自动完成 Dedicated Host 分配与 CloudFormation 建栈template.yml用一份模板固化网络、安全、存储、IAM、启动引导与监控的全部细节configure-runner.sh则借助 SSM 通道完成 Xcode 就绪检查、Runner 注册与 launchd 服务化。三者配合让Release App与Release Enterprise的 macOS 发布任务始终有一个随叫随到、缓存常热、无入站攻击面的专属节点是自托管 CI 基础设施中颇具参考价值的落地样板。【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进