
BuildKit 中的 GitHub Actions Cache 服务 API 详解认证、查询与保存的完整协议指南【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkit导读GitHub Actions 的缓存服务Actions Cache为工作流提供了跨任务、跨运行复用的依赖缓存能力。本文以 buildkit 仓库内置的go-actions-cache客户端库位于 vendor/github.com/tonistiigi/go-actions-cache为蓝本完整解析该服务的 HTTP API 协议从ACTIONS_CACHE_URL/ACTIONS_RUNTIME_TOKEN的认证模型到GET /cache查询、POST /caches保留键、PATCH /caches/[cacheID]分片上传、POST /caches/[cacheID]提交落地的完整链路。读完本文你将掌握这套 API 的每个端点、参数语义、响应格式与底层实现细节可直接用于构建自定义缓存客户端或理解 buildkit 的缓存接入原理。说明本文协议描述以api.md文档vendor/github.com/tonistiigi/go-actions-cache/api.md为主体骨架并辅以同目录下 Go 源码的实现细节进行印证与扩充。一、协议概述与背景GitHub Actions Cache 服务是 GitHub 官方提供的依赖缓存服务用户文档位于官方 Actions 指南缓存依赖以加速工作流。go-actions-cache库的 API 定义基于官方actions/toolkit仓库中packages/cache部分捕获整理因此本文描述的是该服务在实践中的真实行为——包括一些文档中未明说的细节如 version 参数的真实语义、already exists 错误行为等。buildkit 通过 go.mod 引入github.com/tonistiigi/go-actions-cache将其作为 vendor 依赖内置当前版本v0.0.0-20260120203934-54bc28c26fd2使构建过程能够与 GitHub Actions 缓存服务交互。该库同时支持v1 与 v2 两套 API版本端点风格存储后端启用方式v1/_apis/artifactcache/...Azure DevOps 风格自管 blob 分片上传默认或ACTIONS_CACHE_API_FORCE_VERSIONv1v2/twirp/github.actions.results.api.v1.CacheService/...Twirp RPC 风格Azure Blob 直传ACTIONS_CACHE_SERVICE_V2true或ACTIONS_CACHE_API_FORCE_VERSIONv2从源码看v1 与 v2 的选择逻辑位于 cache.go 的TryEnv优先读取ACTIONS_CACHE_SERVICE_V2若为布尔真值则启用 v2ACTIONS_CACHE_API_FORCE_VERSION可显式强制v1或v2传入其他值会直接报错。两套协议在业务语义上等价查询、保留、上传、提交仅传输层与存储方式不同。二、认证模型环境变量与 JWT 令牌2.1 两个关键环境变量Actions 运行时向任务注入两个特殊环境变量所有缓存 API 请求的认证都基于它们ACTIONS_CACHE_URL缓存服务的基地址完整的缓存 API 基址为$ACTIONS_CACHE_URL/_apis/artifactcache/v1 协议v2 协议则使用ACTIONS_RESULTS_URL作为基址。ACTIONS_RUNTIME_TOKENJWTJSON Web Token令牌有效期 6 小时用于所有请求的 Bearer 认证。需要注意工作流中的内联脚本步骤inline step scripts看不到这两个变量如需在自定义脚本中直接使用缓存 API可以通过crazy-max/ghaction-github-runtimev1这类 action 将运行时环境暴露出来api.md 中明确给出了这一变通方案。2.2 令牌结构与作用域ACTIONS_RUNTIME_TOKEN不是普通的不透明字符串而是携带访问控制声明的 JWT。从 cache.go 的New函数可以看到客户端在构造Cache时会解析并校验令牌用jwt.Parser.ParseUnverified解析令牌载荷读取ac声明它是 JSON 序列化的作用域数组[]Scope每个作用域由Scope仓库/分支范围与Permission读/写权限组成权限用位标志表示PermissionRead1与PermissionWrite2见 cache.go读取exp过期时间与nbf生效时间并做时间窗校验当前时间晚于exp报 cache token expired早于nbf报 invalid token with future issue time。作用域规则的核心语义令牌与仓库作用域绑定权限可能是readwrite或readonly。典型场景是PR 对自己的作用域拥有写权限但对目标分支作用域只有只读权限——这意味着 PR 可以保存缓存到自己的作用域却只能读取不能覆盖目标分支的缓存。这正是多 PR 并发构建时缓存隔离与复用的安全基础。2.3 认证请求头所有 API 请求无论 v1 还是 v2都必须携带Authorization: Bearer $ACTIONS_RUNTIME_TOKEN从 cache.go 的newRequest可以看出客户端还会附加Accept: application/json;api-version6.0-preview.1与自定义User-Agent默认go-actions-cache/1.0。2.4 令牌的其他来源与测试支持除标准环境变量外TryEnv还支持通过GHCACHE_TOKEN_ENC/GHCACHE_TOKEN_PW传入加密令牌用 openssl AES-256-CBC 解密decryptToken实现见 cache.go主要用于测试环境。若两个来源都没有令牌TryEnv返回nil, nil调用方应据此优雅降级禁用缓存。三、查询缓存GET /cache3.1 请求参数查询缓存对应GET $ACTIONS_CACHE_URL/_apis/artifactcache/cache携带两个查询参数参数说明keys逗号分隔的键列表。支持前缀匹配无需精确匹配返回与某个前缀匹配的最新记录。version提供命名空间的唯一值。保存缓存时必须使用相同的值api.md 特别注明实际值本身似乎并不重要即服务端只做相等性比对不解析其含义。从 cache.go 的loadV1可以看到具体实现客户端把keys以逗号连接后设置为keys参数version则由version(keys[0])计算得出——即以第一个键为输入做 SHA-256 哈希并十六进制编码version函数见 cache.go哈希输入为固定字符串|go-actionscache-1.0注释说明上游用路径做 version而这里没有可用的唯一路径故采用固定盐值哈希。这意味着同一客户端查询与保存会自动保持 version 一致这正是协议要求保存与查询使用相同 version的工程化落地。3.2 响应格式成功时返回 JSON 对象包含三个属性属性说明cacheKey保存时使用的完整缓存键注意不是请求中用的前缀scope缓存对象所属的作用域archiveLocation下载 blob 的 URL已自带认证无需再附加令牌对应源码中的Entry结构cache.gotype Entry struct { Key string json:cacheKey Scope string json:scope URL string json:archiveLocation IsAzureBlob bool json:isAzureBlob }查询未命中时服务端可能返回空响应体客户端在 loadV1 中会先限制读取 32 KiB 响应体若为空或Key为空字符串则返回nil, nil表示未命中而非错误。命中后返回的Entry可通过Download方法拉取 blobv1 下载基于 HTTP Range 请求cache.go从任意偏移发起GET并校验Content-Range响应头该下载接口被封装为ReaderAtCloserreaderat.go支持随机读语义方便上层以流式方式消费。3.3 v2 查询v2 协议cache_v2.go将查询改为POST /twirp/github.actions.results.api.v1.CacheService/GetCacheEntryDownloadURL请求体为 JSON{ key: 主键, restore_keys: [回退键列表], version: version(主键) }响应为{ ok: bool, signed_download_url: string, matched_key: string }。命中时返回带签名的下载 URL 与匹配的完整键okfalse表示未命中。下载走 Azure Blob SDKblockblob.DownloadStream并内置了URL 过期自动重载机制若下载时遇到 401/403签名 URL 过期会回调ce.reload重新查询换取新 URL 后重试。四、保存缓存三阶段写入协议保存缓存并非一次上传完成而是分为**保留Reserve→ 分片上传Upload→ 提交Commit**三个阶段。整体入口为 cache.go 的Save方法func (c *Cache) Save(ctx context.Context, key string, b Blob) error { id, url, err : c.reserve(ctx, key) // 阶段1保留键 if err ! nil { return err } if err : c.upload(ctx, url, b); err ! nil { // 阶段2上传数据 return err } return c.commit(ctx, id, b.Size()) // 阶段3提交声明总大小 }4.1 阶段一保留键POST /cachesPOST $ACTIONS_CACHE_URL/_apis/artifactcache/caches请求 JSON字段说明key要保留的键。该键的前缀会被用于后续查询匹配。version命名空间需与查询缓存时的 version 一致。响应 JSON字段说明cacheID数值型唯一 ID用于后续的上传与提交请求。源码对应ReserveCacheReq/ReserveCacheRespcache.go实现于reserveV1cache.go。关键行为约束api.md 明确强调一旦某个键被保留该键上就无法再保存任何其他数据——之后使用相同 key/version 的请求会收到 already exists 错误错误处理上似乎没有提供丢弃部分写入abort的接口若上传中途崩溃已保留的键可能被锁死这正是SaveMutable见下文 4.4存在的原因之一。服务端的 already exists 错误通过GithubAPIError表达客户端将其映射为os.ErrExistcache.go上层可用errors.Is(err, os.ErrExist)判断键冲突。4.2 阶段二分片上传PATCH /caches/[cacheID]PATCH $ACTIONS_CACHE_URL/_apis/artifactcache/caches/[cacheID]请求体application/octet-stream原始二进制数据通过Content-Range请求头声明本次上传的数据区间例如Content-Range: bytes 0-33554431/*成功响应体为空。源码uploadChunkcache.go展示了分片细节req.headers[Content-Type] application/octet-stream req.headers[Content-Range] fmt.Sprintf(bytes %d-%d/*, off, offn-1)分片策略由两个包级变量控制cache.goUploadConcurrency 4并发上传的分片数UploadChunkSize 32 * 1024 * 1024单分片大小 32 MiB。uploadV1cache.go用errgroup启动 4 个 goroutine在互斥锁保护下按 32 MiB 步进切分 blob各分片独立并发上传全部成功后才进入提交阶段。客户端上传的数据源是Blob接口io.ReaderAt io.Closer Size()见 cache.go内存字节可直接通过NewBlob包装。v2 差异v2 协议上传走 Azure Blob 直传CreateCacheEntry返回signed_upload_url客户端用blockblob.NewClientWithNoCredential配合UploadStream一次性流式上传cache_v2.goAzure SDK 内部配置了最多 10 次重试、最长 2 分钟重试间隔的健壮性参数。4.3 阶段三提交POST /caches/[cacheID]所有分片上传完成后调用POST $ACTIONS_CACHE_URL/_apis/artifactcache/caches/[cacheID]收尾字段说明size对象的总大小必须与已上传的数据量一致。成功响应体为空。调用之后缓存数据对查询GET /cache变为可见。源码commitV1cache.go将CommitCacheReq{Size: size}以 JSON 形式 POST 出去并校验响应。v2 的commitV2cache_v2.go则调用FinalizeCacheEntryUpload请求体携带key、size_bytes、version三字段响应含ok与entry_id。4.4 可变键保存SaveMutable由于键一旦保留即锁定、且无丢弃接口直接对已存在的键重复Save会失败。为此库提供了SaveMutablecache.go实现覆盖式更新语义先Load(key#)读取旧值若存在把旧值传给回调f(old)生成新 blob再次Load校验索引未在读取期间变化乐观并发控制解析旧键中的序号key#N形式递增后reserve(key#N1)新键若新键也被占用并发冲突则等待 2 秒重试若被阻塞时间超过forceTimeout则跳过被锁键继续递增序号上传并提交新键查询时始终命中最新序号。该方法通过版本号键规避了键锁定限制是处理崩溃恢复与并发更新的重要工具其注释明确说明崩溃时键可能残留锁定forceTimeout用于在这种情况下强制推进但不保证读取到的旧值是最新的。五、重试、限流与错误处理缓存 API 的健壮性依赖一套完整的重试与退避机制核心在 retry.goBackoffPool进程级共享的退避池包级默认实例defaultBackoffPool多个并发请求在限流时共享一个退避窗口避免惊群式重试Wait支持上下文取消与最大超时退避参数最小退避minBackoff 1s最大退避maxBackoff 90s每次触发限流后退避时间翻倍见trigger中的b.backoff * 2Retry-After支持收到 429Too Many Requests时优先解析Retry-After响应头支持秒数与 HTTP 时间两种格式parseRetryAfter见 cache.go若存在则按服务端指定时间等待否则走指数退避总超时单次操作的兜底超时由Opt.Timeout控制默认 5 分钟optsWithDefaults见 cache.go超过后报 maximum timeout reached错误解析checkResponsecache.go将非 2xx 响应解析为GithubAPIError含message、typeName、typeKey、errorCode并兼容 v2 风格的{code, message}错误体already_exists会被规范化为ArtifactCacheItemAlreadyExistsException错误统一包装为HTTPError{StatusCode, Err}便于上层判断状态码。六、缓存管理REST API 列键除缓存存取外库还通过RestAPIrest.go提供GitHub REST API 的缓存键枚举能力用于管理场景如清理、盘点缓存端点GET https://api.github.com/repos/{repo}/actions/caches认证头Authorization: Bearer token并携带X-GitHub-Api-Version: 2022-11-28查询参数per_page固定 100、page分页、key前缀过滤、ref分支引用过滤返回结构CacheKeyid、ref、key、version、last_accessed_at、created_at、size_in_bytesListKeysrest.go自动翻页直到total_count被取完Cache.AllKeyscache.go会跨令牌声明的所有作用域并发枚举键并合并去重。该 REST API 与前述 artifactcache API 相互补充前者面向单次构建的读写性能后者面向缓存生命周期管理。七、协议要点速查表操作方法 路径v1关键参数/请求体关键响应查询缓存GET /cachekeys前缀、逗号分隔、version命名空间cacheKey、scope、archiveLocation免认证下载 URL保留键POST /caches{key, version}cacheID数值 ID上传分片PATCH /caches/[cacheID]原始字节流 Content-Range头空提交POST /caches/[cacheID]{size}总大小需与上传量一致空列键管理GET /repos/{repo}/actions/cachesper_page、page、key、refactions_caches[]含key、size_in_bytes等实践要点归纳所有请求都必须带Authorization: Bearer $ACTIONS_RUNTIME_TOKEN令牌有效期 6 小时、绑定仓库作用域readwrite / readonly查询键支持前缀匹配返回最新记录响应的cacheKey是完整键而非请求前缀version是纯命名空间标识保存与查询必须一致go-actions-cache客户端用首键的 SHA-256 哈希自动生成保证一致性键一旦保留即锁定重复保存返回 already exists且无丢弃接口——需要覆盖更新时使用SaveMutable的版本号键机制上传按 32 MiB 分片、4 路并发配合 429 退避1s→90s 指数增长与 5 分钟总超时构建了面对服务端限流的健壮性。八、延伸阅读协议文档原始出处vendor/github.com/tonistiigi/go-actions-cache/api.mdv1 协议完整实现认证、查询、保留、上传、提交、错误映射vendor/github.com/tonistiigi/go-actions-cache/cache.gov2 Twirp Azure Blob 实现vendor/github.com/tonistiigi/go-actions-cache/cache_v2.go退避重试与限流控制vendor/github.com/tonistiigi/go-actions-cache/retry.go缓存键枚举 REST APIvendor/github.com/tonistiigi/go-actions-cache/rest.go依赖声明go.mod【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考