Gitea Actions 在 Apple 硬件上落地:用 Mac 实现私有 CI/CD 流水线
如果你手上正好有一台 Mac又想把这台机器变成自建代码托管平台里的 CI/CD 执行节点那这篇文章就是写给你看的。很多团队已经有自己的 Gitea 内网仓库但 CI/CD 还在用 GitLab Runner、Jenkins或者干脆依赖 GitHub Actions而当你尝试把 Apple 硬件Mac mini、MacBook Pro、Mac Studio纳入 Gitea 的自动化流水线时会遇到架构差异、runner 模式选择、系统环境隔离等一系列问题。本文要给出一个清晰判断Gitea Actions 完全可以在 Apple 硬件上真正跑起来而且对想构建 iOS/macOS 应用、又想保持私有的团队来说这是目前最轻量的开源方案之一。读完这篇文章你能搞懂三件事Gitea Actions 和 act_runner 的架构关系是什么如何在 Mac 上安装、注册、运行 act_runner如何用一份.gitea/workflows/*.yml文件把构建、测试、打包流程跑在 Apple 硬件上。文中还会给出苹果芯片Apple Silicon和 Intel Mac 的不同处理思路、常见坑和排查方法建议收藏备用。1. 为什么要关注 Gitea Actions on Apple Hardware很多人一开始接触 Gitea是从“替换 GitHub/GitLab”这个角度出发的。Gitea 用 Go 写的单个二进制文件就能跑起来内存占用远低于 GitLab特别适合内网部署、个人 NAS、小型团队。但仅仅是代码托管还不够开发流程里最刚需的是持续集成和持续部署。以前在 Gitea 仓库里想跑 CI最常见的选择是外接 Jenkins 或 GitLab Runner配置复杂不说Jenkins Pipeline 和 Gitea 的结合始终不够原生。Gitea 从 1.19 版本开始正式支持 Gitea Actions它的目标很明确**让你能直接写类似 GitHub Actions 的 workflow 文件由官方提供的 act_runner 来执行。**工作流文件放在仓库的.gitea/workflows/下触发机制、语法结构、上下文对象都和 GitHub Actions 高度兼容。对已经从 GitHub Actions 迁移过来的团队几乎不需要重新学一套技能。但为什么单拎出 Apple Hardware 来说因为常规 CI 服务器都是 Linux x86/ARM 架构而 Apple 生态有特殊性如果你要构建 iOS 或 macOS 应用必须用 Xcode、codesign、altool这些工具它们只存在于 macOS 系统上如果你想避免购买 Mac 云服务或受限于第三方平台用自己手里的 Mac mini 或 MacBook 当 runner是把成本降到最低的方式Apple SiliconM 系列是 arm64 架构和常见的 Linux amd64 环境不同工作流里的容器、依赖、缓存都要考虑架构匹配问题。这不是纯技术炫技而是很多开发团队的真实痛点自己的代码放在内网 Gitea想构建 Apple 应用却买不起 Mac 云主机或者公司政策不允许把代码上传到第三方 CI 平台。于是让 Apple 硬件亲自干活就是一个合理又省钱的选择。2. Gitea Actions 的核心机制与架构在直接上手之前先把 Gitea Actions 的架构讲清楚。否则你在配置 runner 时很可能不理解为什么 job 一直卡在队列里或者为什么 runner 注册成功但工作流不执行。2.1 一个工作流从提交到执行发生了什么Gitea Actions 沿用了 GitHub Actions 的模型仓库里有一个.gitea/workflows/ci.yml文件当 push、PR、tag 等事件发生时Gitea 实例会分析事件对应的 workflowGitea 会把任务放进任务队列一个或多个 act_runner 进程从 Gitea 实例那里拉取任务act_runner 根据工作流定义的runs-on标签匹配自己声明的 label匹配成功后runner 负责创建 job 运行环境执行各个 step。这里的核心角色是act_runner它是 Gitea Actions 的执行器本质上是 GitHub Actions Runner 的一个兼容实现内部基于act项目来执行容器内或宿主机上的步骤。2.2 为什么 runner 要用 label 匹配GitHub Actions 有runs-on: ubuntu-latest这类标签GitLab Runner 有 tagGitea Actions 同样使用 label。act_runner 在注册时可以声明--labels macos-arm64:arm64意思是“这个 runner 能处理声明为macos-arm64的 job并且默认 Job 容器架构是 arm64”。当 workflow 里写runs-on: macos-arm64时这个 runner 才会被选中。很多新手忽略 label导致注册后的 runner 显示在线但任务一直不执行根本原因就是 workflow 里用的 label 和 runner 注册时声明的不一致。2.3 运行模式宿主机执行与容器执行act_runner 支持多种执行方式常见两种宿主机模式runner 直接在当前系统环境执行命令不额外启动容器。这种方式对 Apple 硬件尤其重要因为 Xcode、xcodebuild等工具只存在于 macOS 系统里没法放进 Linux 容器。Docker 模式runner 通过 Docker 启动一个隔离环境来执行 step。优点是干净、依赖隔离缺点是 macOS 上 Docker 本质是虚拟机跑 Linux 容器与宿主机 macOS 之间不能直接访问 Xcode除非你特意将宿主路径挂载进去但这不是干净的方案。因此在 Apple 硬件上跑原生 Apple 应用构建首选宿主机模式或者使用自定义 labels 指向宿主机执行。这就是为什么这篇文章要专门讲 Apple Hardware 的特殊性。2.4 Gitea Actions 与 GitLab Runner、Jenkins 的差异很多搜索词里出现“gitlab和gitea”“jenkins gitea 实现 springboot 打包部署”这里顺便做一个直接对比方案配置文件位置学习成本资源占用Apple 硬件支持Gitea Actions仓库内.gitea/workflows/*.yml低和 GitHub Actions 接近较低act_runner 是单进程需要自行配置 Mac runnerGitLab Runner仓库内.gitlab-ci.yml或项目设置中等中等偏高支持 macOS runner但要 GitLab EE 部分高级功能JenkinsJenkinsfile 或 Web 配置较高高Master/Agent 模式复杂支持 macOS agent但维护成本高Gitea Actions 最舒服的地方是整个 CI 配置跟着仓库走代码审查时能看到 workflow 变更原生支持 Actions 语法不需要额外搭建调度系统。3. 环境准备Apple 硬件 Gitea 实例 基础依赖下面开始实战。先确认你的硬件和软件环境再安装组件。3.1 硬件与系统要求Apple 硬件Mac mini、MacBook、Mac Pro 都行。处理器Apple SiliconM1/M2/M3 等或 Intel。系统建议 macOS 12 及以上具体以你用的 Gitea 和 act_runner 版本支持为准。内存至少 8GB建议 16GB因为 Xcode 本身很吃内存。磁盘至少留 50GB 左右空间Xcode 命令行工具和缓存比较占空间。注意这里不写死版本号。技术演进很快以官方最新 release 和文档为准。如果你只是为了学习可以先在一台配置普通的 MacBook 上跑通如果是团队生产环境建议用固定的 Mac mini 当 runner避免笔记本休眠导致任务中断。3.2 安装 Git 和基础工具macOS 自带 git但版本可能偏旧。推荐用 Homebrew 安装最新的 gitbrew install git git-lfs安装完成后验证git --version如果还没有 Homebrew先去安装 Homebrew。这一步不是必须的但后面安装一些依赖工具会方便很多。3.3 安装并初始化 Gitea 实例如果你想先看 Flow可以用一份现成的 Gitea 实例但为了完整这里给出二进制方式在 macOS 上跑 Gitea 的简要步骤也可以直接用 Docker但如果同一台 Mac 上还要跑 act_runner二进制方式更简单。从 Gitea 官方下载对应架构的二进制。Apple Silicon 用arm64Intel Mac 用amd64。下载后放到 /usr/local/bin 这类目录chmod x gitea sudo mv gitea /usr/local/bin/gitea创建数据目录mkdir -p ~/gitea/{data,log}启动临时启动测试用gitea web --config ~/gitea/app.ini浏览器访问http://localhost:3000完成首次安装配置。数据库可以先选 SQLite简单够用团队规模大了再切 PostgreSQL 或 MySQL。关键是开启 Actions 功能。修改配置文件~/gitea/app.ini在合适位置加上[actions] ENABLED true修改配置后重启 Giteapkill -f gitea web gitea web --config ~/gitea/app.ini如果一切正常在 Gitea 的「站点管理 / 管理面板」里能看到 Actions 已启用。3.4 创建仓库与访问令牌在 Gitea 中新建一个测试仓库比如actions-demo。之后需要在 Gitea 里生成一个 runner token。在 Gitea 管理后台的「站点管理 - Actions - Runner」里可以创建 token。也可以调用 API但更简单的方法是打开管理界面点击创建 Runner把生成的 token 记录下来。安全提醒runner token 等同于给了 runner 拉取并执行任务的权利不要提交到公开仓库也不要泄露到任何日志里。4. 安装并注册 act_runneract_runner 是 Gitea Actions 的执行器你需要在 Apple 硬件上安装它。重点说明建议直接在宿主机上跑二进制而不是放进 Docker 容器。原因前面已经说过——构建 Apple 应用需要访问宿主机 macOS 的 Xcode 环境。4.1 下载 act_runner 二进制去 Gitea 官方仓库的 Releases 页面下载 act_runner。Apple Silicon 选择darwin-arm64Intel Mac 选择darwin-amd64。例如用变量表示以实际下载文件名为准# Apple Silicon 示例 wget https://gitea.com/gitea/act_runner/releases/download/版本/act_runner-版本-darwin-arm64 chmod x act_runner-版本-darwin-arm64 sudo mv act_runner-版本-darwin-arm64 /usr/local/bin/act_runner如果你在下载过程中发现 Gitea 官方仓库访问不便可以先通过镜像或公司内网代理解决本文不再展开。4.2 注册 runner在终端里进入任意目录执行注册命令。需要提供 Gitea 实例地址和之前生成的 tokenact_runner register --instance http://localhost:3000 --token 你的TOKEN --labels macos-arm64:arm64 --no-interactive说明--instanceGitea 实例地址如果 runner 和实例不同机器要写内网可达地址。--token第 3 节生成的 runner token。--labels指定这个 runner 能处理的 label。这里macos-arm64:arm64表示 job 使用macos-arm64标签时容器架构默认是 arm64。--no-interactive非交互注册。对于 Intel Mac可以注册为act_runner register --instance http://localhost:3000 --token 你的TOKEN --labels macos-amd64:amd64 --no-interactive注册成功后当前目录会生成.runner文件。这个文件保存 runner 身份不要删除。之后启动 runneract_runner daemon在终端里会看到类似于“listening on ...”“runner 已就绪”的日志。打开 Gitea 管理后台的 Actions Runner 页面应该能看到这台 runner 在线。4.3 使用配置文件定制 runner.runner文件记录身份真正的运行参数在config.yaml中。可以用默认配置也可以手动生成一份act_runner generate-config config.yaml常用配置片段runner: file: .runner capacity: 1 insecure: false job: timeout: 30m如果要支持并发任务可以调整capacity但 Apple 硬件上通常不建议太大因为构建任务可能很吃资源。4.4 把 runner 注册为 macOS 服务如果希望 runner 开机自动启动可以使用 launchd。下面是一个简单的 plist 模板路径可以用/Library/LaunchDaemons/com.gitea.act-runner.plist?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyLabel/key stringcom.gitea.act-runner/string keyProgramArguments/key array string/usr/local/bin/act_runner/string stringdaemon/string string--config/string string/Users/你的用户名/gitea-runner/config.yaml/string /array keyRunAtLoad/key true/ keyKeepAlive/key true/ keyWorkingDirectory/key string/Users/你的用户名/gitea-runner/string /dict /plist然后加载服务sudo launchctl load /Library/LaunchDaemons/com.gitea.act-runner.plist注意检查 plist 里的路径、用户名必须正确。5. 编写第一个 Gitea Actions 工作流现在执行器和仓库都准备好了开始在仓库里创建 workflow 文件。5.1 最简工作流验证 runner 是否真的在 Apple 硬件上执行在actions-demo仓库中添加文件.gitea/workflows/demo.ymlname: Demo on Apple on: push: branches: - main jobs: build: runs-on: macos-arm64 steps: - name: Checkout code uses: actions/checkoutv4 - name: Show system info run: | uname -a sw_vers uname -m xcodebuild -version 2/dev/null || true解释on.push.branches只在 push 到 main 分支时触发。runs-on: macos-arm64必须和注册 runner 时的--labels macos-arm64匹配。uses: actions/checkoutv4Gitea Actions 兼容 GitHub Actions 生态可以直接使用 checkout 动作。最后几步会在宿主机执行 macOS 命令输出系统版本和处理器架构。如果你用的 Intel Mac把runs-on改成macos-amd64。推送到仓库后在 Gitea 仓库页面的「Actions」标签里能看到运行记录。点进去查看日志如果输出里出现Darwin和arm64或x86_64说明 runner 确实在 Apple 硬件上执行任务。5.2 在容器里跑 Linux 任务的情况Gitea Actions 也可以让你在一个 job 中运行容器用 Docker 模式启动一个 Linux 容器执行步骤。这种场景适合做 Linux 兼容性测试。但注意前面注册 label 时用macos-arm64:arm64这个 label 代表 runner 的默认架构是 arm64如果你在 workflow 里显式指定container:runner 会尝试用 Docker/Podman 去启动对应的容器。jobs: test-on-linux: runs-on: macos-arm64 container: node:20-alpine steps: - run: | node --version uname -m如果 Docker 没有运行或者 Apple Silicon 上无法直接运行某些 amd64 容器未开启 Rosetta这个 job 会失败。建议先保证 Docker Desktop 或 Colima 已启动并开启 arm64 镜像支持。6. Apple 硬件上更实用的场景构建 macOS/iOS 应用当你确认基础 runner 没问题后就能发挥 Apple 硬件的真正价值了。很多公共 CI 服务不提供 macos runner或者排队时间极长。把 Gitea Actions 跑在自己的 Mac 上等于有了一个私有的 macOS 构建机。6.1 构建 macOS 命令行的示例以一个 Swift 包为例workflow 可以这样写name: Swift Build on: pull_request: push: branches: [main] jobs: build: runs-on: macos-arm64 steps: - uses: actions/checkoutv4 - name: Swift version run: swift --version - name: Build run: swift build - name: Test run: swift test如果环境里没有安装 Swift 工具链runner 会报找不到swift命令。macOS 系统通常自带swift但如果你用的 macOS 环境没有命令行工具需要先安装。6.2 构建 iOS 应用需要注意什么iOS 应用比普通 CI 复杂得多核心原因是签名。这里给出一个简化模型不代表生产全部细节。name: iOS Archive on: push: tags: - v* jobs: archive: runs-on: macos-arm64 steps: - uses: actions/checkoutv4 - name: Select Xcode run: | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer xcodebuild -version - name: Archive env: DEVELOPMENT_TEAM: ${{ secrets.TEAM_ID }} run: | xcodebuild archive \ -project YourApp.xcodeproj \ -scheme YourApp \ -configuration Release \ -archivePath build/YourApp.xcarchive \ DEVELOPMENT_TEAM$DEVELOPMENT_TEAM \ CODE_SIGNING_ALLOWEDNO这只是一个演示。生产环境里签名、导出、上传到 TestFlight 等步骤会根据项目强依赖更多配置。这里强烈建议所有证书和描述文件不要直接放仓库使用 Gitea Actions secrets 管理不要把私钥放到工作流日志先用普通项目验证 Xcode 构建链路再加签名上传。如果你用的是 macOS 硬件却只需要跑 Linux 容器那没必要用 Mac直接用一台 Linux 服务器更省成本。Apple 硬件跑 Gitea Actions 的核心收益永远是能在自己家/内网里构建 Apple 生态产物。7. 常见问题与排查思路以下问题都是实际运行中比较容易遇到的按“现象 - 可能原因 - 排查方式 - 解决方案”整理成表方便快速定位。问题现象可能原因排查方式解决方案runner 离线act_runner daemon 没启动、网络不通查看 runner 日志、ping Gitea 实例启动 act_runner确认实例地址可达注册失败token 错误、[actions] ENABLEDfalse检查 Gitea 设置、重新生成 token在配置中开启 Actions重新获得 token 注册任务一直卡在排队workflow 中runs-on标签与 runner 声明不匹配查看 workflow 里的runs-on查看 runner 注册时的--labels统一两边 label或重新注册 runnerJob 执行后立即失败runner 默认执行容器但 Docker 未启动查看日志中的 “docker” 相关错误启动 Docker或者调整为宿主机执行通过 label 定义不需要容器无法访问 Xcodejob 在容器内执行容器是 Linux查看 step 日志xcodebuild不存在使用宿主机模式不要将 iOS 构建步骤放到容器 job 中下载依赖慢网络环境、DNS、代理在 runner 环境测curl配置内网镜像/缓存或修改 runner 的 HTTP 代理构建产物乱跑多个 job 并发时共享环境检查 runner 目录、缓存目录设置capacity: 1或区分不同工作目录Apple Silicon 上拉取 amd64 镜像失败镜像架构不兼容、Docker 未开启 Rosetta查看容器启动日志使用 arm64 镜像或配置 Docker Desktop 的 Rosetta 兼容模式用户 SSH 密钥管理runner 进程用户和开发用户不同检查~/.ssh权限、部署密钥将 Gitea 部署密钥添加到 runner 用户~/.sshrunner 不执行新的 workflow版本过旧、缓存查看 Gitea 和 act_runner 版本升级到最新稳定版清理 runner 临时目录下面单独讲一个高频问题macOS 系统睡眠导致 runner 掉线。MacBook 默认会进入休眠runner 进程可能在休眠后失联。如果你用 MacBook 当 runner建议在系统设置里关闭“在此时间后关闭显示器”相关的节能设置或者用caffeinate命令保持系统唤醒状态。简单方式caffeinate -s act_runner daemon-s参数会阻止系统在连接电源时睡眠。生产环境更推荐用 Mac mini 接电源配合 launchd 常驻。8. 最佳实践与工程化建议跑通最小 demo 只是一个开始把 Gitea Actions on Apple Hardware 用在真实项目里需要从并发、安全、维护性三个维度做工程化规划。8.1 明确 runner 的职责边界不要在一台 Mac 上既跑 Gitea 实例又跑多个 runner还同时处理多个大型 iOS 编译任务。Apple Silicon 性能虽然强但内存带宽、磁盘 IO、每次 Xcode 构建的缓存都会成为瓶颈。建议Gitea 实例放服务器或 NASMac runner 只负责执行构建任务同一个 runner 的capacity默认设置为 1避免多个 iOS 构建同时抢占资源导致超时或失败。8.2 使用 secrets 管理敏感信息Gitea Actions 支持 Secrets。在仓库设置中配置 Secrets然后在 workflow 中通过${{ secrets.XXX }}引用。务必遵循最小权限原则不要在 workflow 文件里写死证书、密码、token不要把 Secrets 打印到日志runner 进程以独立用户运行避免使用管理员 root 权限对 runner 工作目录、缓存目录设置严格权限。8.3 将 workflow 拆成可复用的 composite action如果你有多个仓库需要构建 iOS 包可以把“Checkout - 选择 Xcode - 构建 Archive - 导出 ipa”提取成 composite action放到一个专用仓库或内网可访问的模块里。这样每次修改构建逻辑不需要改动每个业务仓库。8.4 缓存依赖与构建缓存Apple 构建场景里下载依赖和 Xcode 缓存通常非常耗时。act_runner 支持缓存服务具体启用方式可以参考 Gitea 官方 actions 缓存文档。简单思路使用actions/cache或 Gitea 内置缓存配置归档缓存路径如~/Library/Developer/Xcode/DerivedData定期清理过大的 DerivedData避免磁盘占满。8.5 日志与可观测性Gitea Actions 的日志默认托管在 Gitea 中。但生产环境建议把 runner stdout 连接到日志采集工具如 Loki、ELK便于检索多次构建的输出。如果 runner 异常退出至少能看到启动日志。8.6 版本升级策略Gitea 和 act_runner 都在快速迭代。升级前认真阅读 release note特别注意 Gitea Actions 和 act_runner 的兼容性。先在一台测试 Mac 上升级并跑通 demo再逐步替换生产 runner。不要在生产环境直接升级否则可能出现 runner 注册失效、工作流语法不兼容等问题。8.7 考虑多台 Mac 的扩展当团队构建量上去后可以加入多台 Mac runner。每种 runner 声明不同的 label例如macos-arm64-14Apple Silicon macOS 14macos-amd64-13Intel Mac macOS 13ios-build专门处理 iOS 构建的 runner。在 workflow 中精确指定runs-on让任务路由到最合适的设备。这种模式下Gitea Actions 就变成了一个私有的 Apple 硬件 CI 集群比维护 Jenkins 的 Mac agent 简单得多。9. 总结与后续方向把 Gitea Actions 跑在 Apple 硬件上本质上是在做一次“自托管 CI 与 Apple 生态”的桥接。它真正降低的是为构建 iOS/macOS 应用而托管额外 Mac 服务的成本以及把代码交给外部 CI 平台的隐私担忧。如果你身边正好有闲置的 Mac花一个下午按本文步骤跑通基础流程应该就能感受到仓库内 workflow 驱动 macOS 构建的爽快感。下一步可以研究几个方向让这套体系更完善深入 act_runner 的 config.yaml 配置理解 labels、container 选项、缓存机制给 Gitea 实例配置反向代理和 HTTPS保证 runner 与实例之间的通信安全尝试把 iOS 签名、TestFlight 上传集成到 workflow 中形成完整的发布流水线如果有多个 Mac研究如何划分 label、做优雅的任务调度和资源监控。无论如何记住一个原则Apple 硬件上的 Gitea Actions 不能照搬 Linux CI 的思路它更适合把任务直接交给 macOS 宿主机让 Xcode 和原生工具链发挥真正价值。先把最小的苹果构建流水线跑通再逐步扩展复杂逻辑是这个方向最稳的实践路径。