news 2026/9/13 6:25:48

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 AppRelease Enterprise两条发布流水线提供长期驻留的 macOS 构建能力。读完本文,你将掌握这套栈的选型逻辑、Provision 部署脚本的自动降级策略、CloudFormation 模板的关键参数、Xcode 的引导安装方式,以及通过 AWS Systems Manager 完成 Runner 注册与 launchd 服务化安装的完整链路。

一、为什么需要一台"持久化"的 macOS 发布 Runner

screenpipe 是一个跨平台的本地优先(local-first)录屏 + AI 记忆应用,其桌面端基于 Tauri(Rust + 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 AppRelease Enterprise两条工作流中 macOS 任务的专用自托管 Runner,Windows 与 Linux 任务则继续留在 GitHub 托管 Runner 上。与之平行的方案还有 infra/release-linux-runner 中的 Azure Linux 常驻节点,两者共同构成 screenpipe 的"自有发布农场"。

二、硬件选型与安全模型

2.1 实例选型:性能优先的降级顺序

按 README.md 的说明,该栈选用能在美国区域实际分配到的、最快的非 Ultra Apple 芯片专用宿主机,优先级顺序为:

优先级实例类型芯片
1mac-m4max.metalM4 Max
2mac-m4pro.metalM4 Pro
3mac2-m2pro.metalM2 Pro
4mac-m4.metalM4
5mac2-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 中RunnerSecurityGroupSecurityGroupEgress配置,无任何SecurityGroupIngress);
  • 管理员通过AWS Systems Manager(Session Manager / Run Command)进行连接与远程执行,无需 SSH 端口暴露;
  • 实例 IAM 角色仅挂载AmazonSSMManagedInstanceCore托管策略,配合实例配置文件的 SSM 通道完成一切管理操作。

这一设计使得发布节点虽然位于公网可达的 VPC 子网(用于出站下载依赖与向 GitHub 拉取任务),却几乎不存在可被扫描攻击的入口面。

三、Provision:一条命令完成宿主机分配与建栈

3.1 部署脚本的自动降级逻辑

执行以下命令即可完成 Provision:

./infra/release-mac-runner/deploy.sh

deploy.sh 的核心思路是**"先复用、后新建"**的三段式降级查找,全程使用set -euo pipefail保证失败即中断:

  1. 复用已存在的发布 Mac:按Name=screenpipe-release-mac标签在us-east-2us-east-1us-west-2三个区域中查询pending/running/stopping/stopped状态的实例,命中即直接输出实例信息并退出;
  2. 复用已分配但未使用的专用宿主机:按同样标签查询state=available的 Dedicated Host,命中即记录其HostId供后续使用;
  3. 按性能顺序现场分配:依次遍历上文的 5 种实例类型 × 3 个区域 × 各可用区,调用aws ec2 allocate-hosts尝试分配专用宿主机,首次成功即跳出所有循环。分配时携带--auto-placement off(显式指定部署)、--host-recovery on(宿主机故障自动恢复),并打上Name=screenpipe-release-macWorkload=screenpipe-release两组标签。

如果所有候选组合都无法分配,脚本会输出明确错误并退出:

No permitted EC2 Mac Dedicated Host is currently allocatable in a US region

3.2 可用环境变量覆盖

脚本全程支持显式覆盖,适合在已有宿主机、特定区域或特定实例类型场景下跳过自动查找:

环境变量作用默认行为
AWS_REGION指定区域(如us-east-2us-east-2 → us-east-1 → us-west-2自动探测
INSTANCE_TYPE显式指定实例类型按性能顺序自动尝试
AVAILABILITY_ZONE显式指定可用区取该实例类型在该区域的第一个可用区
EXISTING_HOST_ID复用既有 Dedicated Host为空时自动查找/分配
STACK_NAMECloudFormation 栈名默认screenpipe-release-mac

3.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(包含DedicatedHostIdInstanceIdRunnerNameRunnerLabel),供后续注册脚本使用。

四、CloudFormation 模板拆解:一条龙构建发布节点

template.yml 定义了发布节点所需的全部 AWS 资源,值得逐块拆解:

4.1 参数一览

参数类型默认值说明
AvailabilityZoneAWS::EC2::AvailabilityZone::Name必填提供所选 EC2 Mac 类型的可用区
MacOSImageIdAWS::SSM::Parameter::Value<AWS::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.metal
ExistingHostIdString复用已分配的专用宿主机时传入
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: offHostMaintenance: onHostRecovery: on,并带DeletionPolicy: RetainExceptOnCreate(防止误删);
  • 实例Affinity: host+Tenancy: host绑定专用宿主机,DisableApiTermination: true开启终止保护;
  • 监控:CloudWatch 告警监听StatusCheckFailed指标(周期 60 秒、2 个评估周期),实例状态检查失败即告警。

4.3 启动模板与引导脚本

Launch Template 中,根卷配置为gp3、2048 GiB、16000 IOPS、1000 MB/s 吞吐、加密、DeleteOnTermination: false,保证数据不随实例终止而丢失;同时启用IMDSv2(HttpTokens: required,收紧元数据服务访问。

UserData引导脚本在首次启动时完成大量工作,日志落盘到/var/log/screenpipe-release-runner-bootstrap.log

  1. 建立缓存与 Runner 目录:/Users/ec2-user/screenpipe-cache(持久化工作区/编译缓存)与/Users/ec2-user/actions-runner,并chownec2-user
  2. 导入 AppleDeveloper ID 根证书DeveloperIDCA.cerDeveloperIDG2CA.cer)到系统钥匙串,为后续代码签名铺路;
  3. 通过 Homebrew 安装工具链:aria2 bun cmake ffmpeg gh git-lfs jq node sccache wget,以及xcodesorg/made/xcodes(Xcode 版本管理工具);
  4. 安装 Rust 工具链(rustup默认stable);
  5. 下载 GitHub Actions Runnerv2.336.0(osx-arm64)并解压到actions-runner目录;
  6. 落标记文件/var/db/screenpipe-release-runner-bootstrap-complete,表示引导完成。

4.4 栈输出

栈完成后输出四个关键值:DedicatedHostIdInstanceIdRunnerNamescreenpipe-release-mac)、RunnerLabelscreenpipe-release-macos)。后者正是两条发布工作流通过runs-on请求的自托管标签。

五、安装 Xcode:AMI 之外的必经步骤

AWS 的 macOS AMI只包含 Command Line Tools,不包含完整 Xcode 应用。因此注册 Runner 之前,需要通过 Session Manager 以ec2-user身份连接实例,用引导阶段装好的xcodes安装最新稳定版 Xcode:

xcodes 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:完成首次启动初始化(安装额外组件、注册 SDK);
  • xcodebuild -downloadComponent MetalToolchain:拉取Metal 工具链——screenpipe 的 macOS 录制依赖 Metal 相关的编译与链接能力,缺失会导致链接失败;
  • xcodebuild -version:确认安装结果。

六、注册 Runner:从 SSH 通道到 launchd 守护服务

6.1 前置条件与触发命令

Xcode 就绪后,先完成gh的认证(需要仓库管理员权限,用于申请 Runner 注册令牌),然后执行:

AWS_REGION=us-east-2 ./infra/release-mac-runner/configure-runner.sh

6.2 注册脚本执行流程

configure-runner.sh 内部完成以下工作:

  1. 申请注册令牌:通过gh apirepos/screenpipe/screenpipe/actions/runners/registration-token发起 POST,换取一次性REGISTRATION_TOKEN
  2. 定位实例:优先按Name=screenpipe-release-mac标签查询实例;查询为空时回退到 CloudFormation 栈输出中的InstanceId;仍可用INSTANCE_ID=i-...环境变量显式指定;
  3. SSM 远程执行:以AWS-RunShellScript文档向实例发送一串命令,依次执行:
    • xcodebuild -runFirstLaunchxcodebuild -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:wheelchmod 0644,最后launchctl bootstrap system使其成为开机自启的无头(headless)守护服务
    • 通过plutil为 plist 注入EnvironmentVariables.PATH(包含 Homebrew、Cargo 等路径),确保 launchd 环境下的 PATH 完整;
  4. 等待与校验aws ssm wait command-executed等待命令执行完成,再拉取StandardOutputContent/StandardErrorContent检查结果;
  5. 确认注册:调用gh api repos/screenpipe/screenpipe/actions/runners查询名为screenpipe-release-mac的 Runner,输出其namestatusbusylabels

6.3 服务化与隔离性

Runner 以launchd LaunchDaemon形式常驻(而非手动常驻进程),具备以下特性:

  • 系统级服务随实例启动自动拉起,无需人工登录;
  • screenpipe-release-mac仓库级(repository-level)Runner注册,而非组织级,天然限制其只能服务本仓库的工作流;
  • 标签screenpipe-release-macos唯一Release AppRelease Enterprise两条工作流请求的自托管标签;由于 Runner 属于上游仓库私有,Fork 无法访问该 Runner,从机制上杜绝了 Fork 借用发布节点执行代码的风险。

七、与发布工作流的衔接

在 release-app.yml 中,check_commit作业会根据提交类型动态决定 macOS 构建节点:常规路径使用 GitHub 官方macos-latest/macos-26,而发布相关提交(或手动workflow_dispatch触发)则将macos_arm_runnermacos_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 发布任务"的描述一致。

八、日常运维要点

  1. 状态查询:栈输出与gh api .../actions/runners查询均可确认 Runner 在线状态;CloudWatchStatusCheckFailed告警覆盖实例健康;
  2. 实例管理:实例带终止保护(DisableApiTermination: true),且 Host 与实例均采用RetainExceptOnCreate/Retain删除策略,普通删除栈操作不会销毁数据卷与宿主机,需在确认迁移完成后显式清理;
  3. 缓存持久化/Users/ec2-user/screenpipe-cache位于不随实例终止删除的 gp3 根卷(2048 GiB)上,Runner 的--work目录与各类编译缓存共同复用该卷,这是"持久化 Runner"相比临时节点的核心收益;
  4. 安全边界:无入站规则 + SSM 管理 + IMDSv2 + 仓库级 Runner + 发布类工作流专用标签,形成纵深防御;Fork 与外部仓库均无法触达该节点;
  5. 区域容量: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 AppRelease 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 6:24:17

继续教育AI写作工具测评与学术论文效率提升指南

1. 继续教育场景下的AI写作需求解析 在继续教育领域&#xff0c;论文写作是每个学习者必须跨越的门槛。无论是职称评定、学历提升还是专业认证&#xff0c;学术论文的质量往往直接关系到最终成果的认可度。但现实情况是&#xff0c;大多数继续教育学员都面临着工作与学习的时间…

作者头像 李华
网站建设 2026/9/13 6:22:54

软件端与PLC通信协议及优化实践详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 6:22:41

51单片机四路模拟量报警器设计:基于ADC0832的数据采集与阈值控制

简介&#xff1a;面向污水处理厂气体检测的电子鼻系统硬件设计方案&#xff0c;以STC89C51单片机为核心&#xff0c;搭配ADC0832扩展4路模拟量输入&#xff0c;完成硫化氢、氨气、甲烷、一氧化碳浓度采集与超限报警。适合单片机课程设计、电子竞赛或工程实训&#xff0c;帮助掌…

作者头像 李华
网站建设 2026/9/13 6:22:40

二叉树路径查找算法与实现详解

1. 二叉树路径问题概述在计算机科学中&#xff0c;二叉树是一种基础且重要的数据结构&#xff0c;它由节点组成&#xff0c;每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。二叉树路径问题是指从根节点到某个叶子节点的所有节点序列&#xff0c;这类问题在算…

作者头像 李华
网站建设 2026/9/13 6:21:29

深度学习模型部署实战:PyTorch+FastAPI构建服务端与客户端完整案例

深度学习模型的部署、web框架、服务端与客户端案例——光看标题你可能觉得这又是一篇“环境配置Hello World”的教程&#xff0c;但实际把这条路完整走一遍之后&#xff0c;我最大的感受是&#xff1a;训练一个模型可能只要几天&#xff0c;但把一个模型稳定地交给别人用&#…

作者头像 李华
网站建设 2026/9/13 6:20:30

SpringAI集成DeepSeek构建企业级智能问答系统

1. SpringAI与DeepSeek技术融合概述在当今企业级应用开发领域&#xff0c;AI能力的集成已成为提升产品竞争力的关键要素。SpringAI作为Spring生态中的AI集成框架&#xff0c;与国产大模型DeepSeek的结合&#xff0c;为开发者提供了全新的智能问答解决方案。这种技术组合特别适合…

作者头像 李华