拓冰建站拓冰建站
首页 / 资讯中心 / 正文

vcpkg macOS CI 机器池维护指南:从 KVM 虚拟机创建到 Azure Pipelines Agent 注册

vcpkg macOS CI 机器池维护指南从 KVM 虚拟机创建到 Azure Pipelines Agent 注册【免费下载链接】vcpkgC Library Manager for Windows, Linux, and MacOS项目地址: https://gitcode.com/GitHub_Trending/vc/vcpkg本指南完整讲解 vcpkg 项目如何在自有 macOS 硬件M4/Apple Silicon上借助 KVM 虚拟化、macosvm 工具、AzCopy 与 Azure DevOps 自托管 Agent维护一套用于 CI 的 macOS 机器池。内容覆盖基础环境准备、全新基础镜像base image的制作与上传、镜像在机器池中的部署与 Agent 注册三个完整阶段并逐条对照仓库中的实际脚本给出实现细节读者可据此在自己的 Azure DevOps 环境中复刻同类机器池。机器池维护的整体思路与安全边界vcpkg 的 macOS CI 机器池并非直接跑在物理机上而是在每台物理主机host内部通过 KVM 运行一个 macOS 虚拟机guestAzure Pipelines 的自托管 Agent 安装在虚拟机内部。这样做既保留了 macOS 构建环境的完整性又便于用镜像归档.aar的形式批量克隆构建环境。文档明确了几条重要的安全与操作边界主机不接受入站 SSH 连接所有主机侧操作都必须在通过 KVM 打开的终端里完成远程工作站只通过 SSH 连接主机 → 客户机这条链路而不是直接连主机。凭据通过 KVM 剪贴板传递文档反复强调使用 KVM 软件的 paste from clipboard 功能把命令和短期凭据粘贴到主机终端避免在主机上保留长时间有效的敏感信息。工作分支不占用origin每台主机上保留一份microsoft/vcpkg的克隆作为origin操作者的 fork 以独立 remote 形式添加并检出到工作修订版本供维护脚本使用git clone https://github.com/microsoft/vcpkg ~/vcpkg git -C ~/vcpkg remote add WORKING-REMOTE https://github.com/GITHUB-USER/vcpkg git -C ~/vcpkg fetch WORKING-REMOTE WORKING-BRANCH git -C ~/vcpkg checkout --detach FETCH_HEAD例如 BillyONeal 的 fork 以 remote 名BillyONeal、URLhttps://github.com/BillyONeal/vcpkg添加。除非改动已经合入microsoft/vcpkg否则不要把工作分支放在origin上工作分支更新后需要在每台主机上重新执行上面的fetch与分离头checkout。阶段一准备主机与基础工作环境更新 Azure Agent URI发布虚拟机更新前必须先更新 guest-prepare.sh 里的 Azure Agent 下载地址使其指向当前版本。获取方式进入 Agent Pool 页面选择 New agent选择 macOS复制下载链接例如https://download.agent.dev.azure.com/agent/5.277.0/vsts-agent-osx-arm64-5.277.0.tar.gz在 guest-prepare.sh 中这一 URI 出现在带有# NOTE: update this URI when publishing a VM update注释的位置脚本第 17 行该注释与 README 的提醒一一对应是发布流程的强制检查点。安装并启用 Homebrew在克隆 vcpkg 之前需要在每台主机上安装并启用 Homebrew/bin/bash -c $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) eval $(/opt/homebrew/bin/brew shellenv)/opt/homebrew路径表明这是 Apple SiliconARM64机器上的 Homebrew 默认前缀。后续的 host-prepare.sh 会再次检查/opt/homebrew/bin/brew是否可执行并把eval $(/opt/homebrew/bin/brew shellenv)写入~/.zprofile保证每次登录 shell 都能找到 Homebrew 环境。阶段二创建新的基础镜像ARM64创建新基础镜像的目标是把一个干净的 macOS 安装 Xcode 构建依赖 Azure Agent的虚拟机打包成可上传、可复制的镜像归档。整个过程分为前置准备、虚拟机安装、客户机准备、归档上传四步。前置条件与目标系统匹配的macOS IPSW、Xcode 26.6.xip和Xcode 26.6 Command Line Tools.dmg均已上传到vcpkgimageminting存储账户的assets容器中。一台安装了PowerShell 7.x、Azure CLI并完成az login使用微软 corp 凭据的工作站用于为存储账户生成 SAS 令牌。从队列中移除空闲 Agent 并准备主机在https://dev.azure.com/vcpkg/public/_settings/agentqueues页面选择当前 osx 队列删除一个空闲 Agent然后在 KVM 中找到该机器密码保存在 CPP_GITHUB\vcpkg\vcpkgmm-passwords 密钥保管库的机密中。更新主机后运行~/vcpkg/scripts/azure-pipelines/osx/host-prepare.shhost-prepare.sh 的实际逻辑为确认 Homebrew 已安装 → 启用 Homebrew 环境并写入~/.zprofile→brew install azcopy→ 若~/macosvm不存在则从 GitHub 下载macosvm-0.2-3-darwin21.tar.gz并解压到主目录。也就是说该脚本一次性完成三件事启用 Homebrew、安装 AzCopy、把macosvm工具安装到~。用 SAS 生成资产下载命令在具备az login的工作站上用下面的 PowerShell 函数为assets容器中的三个资产各生成一条带短期、仅限 blob 作用域凭据的下载命令function Get-AssetDownloadCommand { Param([Parameter(Mandatory$true)][ValidateNotNullOrEmpty()][string]$FileName) $accountName vcpkgimageminting $containerName assets $uNow (Get-Date).ToUniversalTime() $start $uNow.ToString(s) Z $expiry $uNow.AddHours(1).ToString(s) Z $sas az storage blob generate-sas --as-user --auth-mode login --account-name $accountName --container-name $containerName --name $FileName --permissions r --start $start --expiry $expiry --https-only --output tsv return azcopy copy https://vcpkgimageminting.blob.core.windows.net/assets/$($FileName)?$($sas) $FileName } Get-AssetDownloadCommand -FileName UniversalMac_26.6.1_25G76_Restore.ipsw Get-AssetDownloadCommand -FileName Xcode_26.6_Apple_silicon.xip Get-AssetDownloadCommand -FileName Command_Line_Tools_26.6_Apple_silicon.dmg要点说明这里生成的是用户委托 SASuser-delegation SAS权限为只读r、仅 HTTPS、有效期 1 小时。SAS 不是单次使用到期前可重复使用因此下载完成后不要保留生成的命令。如果容器中还没有匹配的 IPSW需要先定位并上传Apple Silicon 的 IPSW 固件信息可参考 M4 Apple Silicon IPSW 固件数据库。在主机 KVM 终端下载资产并创建虚拟机在主机 KVM 终端进入~通过 KVM 的 paste from clipboard 逐条粘贴并运行上面生成的三个 azcopy 命令。然后确定虚拟机目录名命名格式为vcpkg-osx-YYYY-MM-DD-arm64例如vcpkg-osx-2026-08-07-arm64。创建虚拟机必须在 KVM 中进行因为该流程使用 GUImkdir -p ~/vcpkg-osx-YYYY-MM-DD-arm64 cd ~/vcpkg-osx-YYYY-MM-DD-arm64 ~/macosvm --disk disk.img,size500g,syncnone,cachecached --aux aux.img -c 10 -r 18g --restore ~/UniversalMac_26.6.1_25G76_Restore.ipsw ./vm.json ~/macosvm -g ./vm.json参数含义--disk指定 500G 磁盘镜像及其 I/O 缓存策略-c 10分配 10 个 vCPU-r 18g分配 18G 内存--restore使用下载的 IPSW 执行恢复安装./vm.json是该虚拟机的配置描述文件后续启动~/macosvm ./vm.json和临时模式启动~/macosvm --ephemeral ./vm.json都复用它。虚拟机首次安装选项按真实硬件安装的方式跟随提示完成设置设置为新机器Set up as new账户名builduser使用非常相近的密码不允许用 Apple Account 重置计算机账户密码Apple ID选择 Set Up Later / Skip不启用定位服务发送崩溃报告Yes屏幕使用时间稍后设置仅自动下载更新Only download updates automatically安装完成后还有三项收尾设置从 设置 → 墙纸 将桌面壁纸设为固定颜色方便 KVM 使用禁用自动更新设置 → 通用 → 自动更新全部关闭启用远程登录设置 → 通用 → 共享 → 远程登录从主机安装 Xcode 到客户机使用主机 vcpkg 克隆中的脚本安装 Xcode。该脚本会提示输入客户机密码用于安装 SSH 密钥并启用免密 sudo然后传输并展开 Xcodecd ~/vcpkg/scripts/azure-pipelines/osx ./host-install-xcode.sh对照 host-install-xcode.sh 的实现整个流程是在主目录下扫描vcpkg-osx-*目录确定虚拟机目录 → 在$HOME/.ssh生成客户机专用 SSH 密钥对id_guest/id_guest.pub→ 用ssh-copy-id把公钥安装到builduserbuildusers-Virtual-Machine.local→ 通过 SSH 写入/etc/sudoers.d/builduser启用NOPASSWD免密 sudo → 用scp把Xcode_26.6_Apple_silicon.xip传到客户机 → 在客户机内执行sudo mdutil -ad、xip --expand Xcode.xip、把Xcode.app移动到/Applications并删除.xip源文件。接着在客户机 GUI 的 Applications 中打开 Xcode取消勾选 code completion model接受 EULA。运行客户机准备脚本Xcode GUI 步骤完成后运行客户机准备脚本它负责安装 Command Line Tools、构建依赖和 Azure Pipelines Agentcd ~/vcpkg/scripts/azure-pipelines/osx ./host-prepare-guest.sh对照 guest-prepare.sh它执行的操作链为挂载clt.dmg并静默安装 Command Line Tools →xcode-select -s /Applications/Xcode.app指向 Xcode → 安装 HomebrewNONINTERACTIVE1并把brew shellenv追加到~/.zprofile→ 用brew install安装一批构建依赖autoconf-archive autoconf automake azcopy azure-cli bison cmake gettext gfortran gnu-sed gperf libtool meson nasm ninja pkg-config powershell随后创建$HOME/Data目录下载前面更新过的 URI 指向的Azure DevOps agent 压缩包并解压到$HOME/myagent最后删除本脚本自身rm guest-prepare.sh。注意脚本里# NOTE: update this URI when publishing a VM update的注释与 README 开头的发布前更新 URI要求相呼应——若 URI 未更新新镜像将携带过期的 Agent 版本。关机、清理临时资产并打包归档干净地关闭虚拟机。从主机删除临时安装资产rm ~/UniversalMac_26.6.1_25G76_Restore.ipsw \ ~/Xcode_26.6_Apple_silicon.xip \ ~/Command_Line_Tools_26.6_Apple_silicon.dmg在主机 KVM 终端把虚拟机打包为归档cd ~ aa archive -d vcpkg-osx-YYYY-MM-DD-arm64 -o vcpkg-osx-YYYY-MM-DD-arm64.aar -enable-holesaa是 Apple Archive 工具-enable-holes用于保留稀疏文件的空洞从而减小归档体积。生成上传命令并上传归档在工作站 PowerShell 中生成 AzCopy 上传命令写权限cw1 小时有效期仅 HTTPSfunction Get-AzCopyWriteCommand { Param([Parameter(Mandatory$true)][ValidateNotNullOrEmpty()][string]$FileName) $accountName vcpkgimageminting $containerName pvms $uNow (Get-Date).ToUniversalTime() $start $uNow.ToString(s) Z $expiry $uNow.AddHours(1).ToString(s) Z $sas az storage blob generate-sas --as-user --auth-mode login --account-name $accountName --container-name $containerName --name $FileName --permissions cw --start $start --expiry $expiry --https-only --output tsv return azcopy copy --check-lengthfalse $($FileName) https://vcpkgimageminting.blob.core.windows.net/pvms/$($FileName)?$($sas) } Get-AzCopyWriteCommand -FileName vcpkg-osx-YYYY-MM-DD-arm64.aar在主机 KVM 终端粘贴并运行生成的 AzCopy 命令。注意下载与上传使用两个不同的容器assets存放 IPSW/Xcode/CLT 等安装源资产pvms存放制作完成的虚拟机镜像归档。创建新的 Agent Pool上传完成后在https://dev.azure.com/vcpkg/public/_settings/agentqueues创建新的自托管 Agent Pool命名为PrOsx-YYYY-MM-DD-arm64并授予microsoft.vcpkg.ci与microsoft.vcpkg.pr访问权限。随后按部署镜像阶段为机器池中的每台机器执行部署步骤。这一命名约定与 azure-pipelines.yml 中pool.name: PrOsx-2026-08-07-arm64以及 host-register-guest.sh 中PrOsx-YYYY-MM-DD-arm64的池名解析规则一致。阶段三部署镜像到机器池运行虚拟机对机器池中的每台机器执行以下步骤若某台机器刚用来制作镜像可跳过其中已隐式完成的步骤若该机器此前使用过先从https://dev.azure.com/vcpkg/public/_settings/agentqueues中它所属的池删除该机器。通过 KVM 登录机器。在 macOS 系统设置中检查软件更新。确保主机上的 vcpkg 克隆处于已发布的工作修订版本然后准备主机git -C ~/vcpkg fetch WORKING-REMOTE WORKING-BRANCH git -C ~/vcpkg checkout --detach FETCH_HEAD ~/vcpkg/scripts/azure-pipelines/osx/host-prepare.sh若本机不是制镜像的机器在工作站 PowerShell 中铸造 SAS 并生成下载命令function Get-AzCopyReadCommand { Param([Parameter(Mandatory$true)][ValidateNotNullOrEmpty()][string]$FileName) $accountName vcpkgimageminting $containerName pvms $uNow (Get-Date).ToUniversalTime() $start $uNow.ToString(s) Z $expiry $uNow.AddHours(1).ToString(s) Z $sas az storage blob generate-sas --as-user --auth-mode login --account-name $accountName --container-name $containerName --name $FileName --permissions r --start $start --expiry $expiry --https-only --output tsv return azcopy copy https://vcpkgimageminting.blob.core.windows.net/pvms/$($FileName)?$($sas) $($FileName) } Get-AzCopyReadCommand -FileName vcpkg-osx-YYYY-MM-DD-arm64.aar在主机 KVM 终端粘贴运行生成的命令然后解包归档# (The azcopy command line generated above) aa extract -d vcpkg-osx-YYYY-MM-DD-arm64 -i ./vcpkg-osx-YYYY-MM-DD-arm64.aar -enable-holes在主机上另开一个终端窗口启动虚拟机cd ~/vcpkg-osx-YYYY-MM-DD-arm64 ~/macosvm ./vm.json生成短期访问令牌并注册 Agent在工作站 PowerShell 中生成一个短期访问令牌用于把 Agent 加入池az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken --output tsv在主机 KVM 终端把短期访问令牌粘贴到 vcpkg 克隆中的客户机部署命令中~/vcpkg/scripts/azure-pipelines/osx/host-register-guest.sh TOKEN-GOES-HERE对照 host-register-guest.sh 的实现脚本只接受一个参数token否则打印Usage: $0 token并退出。它读取主机名转为大写并去掉域名部分校验是否符合VCPKG-M4-NNN格式大小写不敏感不匹配则报错退出这也是 README 所说的主机名无法唯一确定时即报错停止的底层逻辑。池名通过~/vcpkg-osx-*-arm64/目录名解析得到PrOsx-YYYY-MM-DD-arm64同样有格式校验无法唯一确定池时会失败。在 arm64 上客户机可通过 DNS 访问因此固定使用builduserbuildusers-Virtual-Machine.local作为 SSH 目标即SSH_COOKIE。通过 SSH 在客户机内执行$HOME/myagent/config.sh --unattended --url https://dev.azure.com/vcpkg --work $HOME/Data/work --auth pat --token token --pool POOL --agent VCPKG-M4-NNN --replace --acceptTeeEula完成 Agent 注册。注册成功后脚本通过 SSH 执行sudo shutdown -h now干净地关闭虚拟机注册失败则虚拟机保持运行便于诊断。注册成功后在 KVM 终端以临时ephemeral模式重新启动虚拟机~/macosvm --ephemeral ./vm.json--ephemeral意味着客户机磁盘改动在关机后不会保留每次任务运行都从干净快照开始这是自托管 CI 机器保证构建环境可复现的关键手段。在主机上打开终端窗口SSH 进入客户机并启动 Agentssh -i ~/vcpkg-osx-*-arm64/id_guest builduserbuildusers-Virtual-Machine.local ~/myagent/run.sh确认机器出现在池中然后锁定主机当前用户账户并锁定主机屏幕。更新 vcpkg Macs 电子表格中该机器的记录填入新的池名。机器池在 CI 中的实际用途制作好的PrOsx-YYYY-MM-DD-arm64池会被 scripts/azure-pipelines/osx/azure-pipelines.yml 这类流水线消费。该流水线演示了这些 macOS 机器上跑的典型任务pool.name: PrOsx-2026-08-07-arm64、工作区清理策略clean: resources、2 天超时步骤包括创建~/Data/downloads目录、bootstrap-vcpkg.sh引导 vcpkg或按需用bootstrap-from-source.sh从指定 SHA 构建、通过AzureCLI2铸造资产缓存与二进制缓存的 SAS 并调用test-modified-ports.ps1测试改动的 ports、发布失败日志与文件清单、发布 xUnit 测试结果。从这里可以看到本文维护的机器池最终服务于 vcpkg 在 macOSarm64上的 ports 回归测试。仓库中 scripts/azure-pipelines/test-modified-ports.ps1 是该流水线的核心调用目标也是机器池存在的直接理由——只有稳定、可复现的 macOS 构建机才能持续对 vcpkg 每个改动的 port 做交叉编译与运行验证。小结与关键检查点维护一套 macOS CI 机器池的完整闭环是准备主机Homebrew AzCopy macosvm→ 制作基础镜像IPSW 恢复安装 → Xcode → 依赖 → Agent → 归档上传→ 创建 Agent Pool → 在每台机器上部署镜像 → 注册 Agent → 以 ephemeral 模式投入 CI。贯穿全程的三条纪律是所有敏感凭据SAS、PAT均短期有效、仅 HTTPS并通过 KVM 剪贴板传递用后即弃所有主机侧操作在 KVM 终端完成SSH 只存在于主机 → 客户机方向发布前必须更新 guest-prepare.sh 中的 Azure Agent URI否则新镜像会携带过期 Agent。本文涉及的所有可执行脚本host-prepare.sh、guest-prepare.sh、host-install-xcode.sh、host-register-guest.sh均位于scripts/azure-pipelines/osx/目录下与本 README 一一对应可作为复刻整套流程的直接参考。【免费下载链接】vcpkgC Library Manager for Windows, Linux, and MacOS项目地址: https://gitcode.com/GitHub_Trending/vc/vcpkg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门