跳转到内容
use-cases / ci-cache-without-s3 / hero
FILES · 缓存 · 成本优化

不再是 S3 账单条目的 CI 缓存

大多数 CI 流水线把钱烧在缓存流量上——把构建产物推到 S3,下一个 job 再拉回来,付存储费、付出站费,跨区域时再付一次。在 Hoody 上,缓存就是和构建容器跑在同一台裸金属上的一个文件夹。用 curl 把 tar 包推上去,再用 curl 拉下来。字节从不离开服务器。

阅读 Files API
use-cases / ci-cache-without-s3 / mechanism

三条 curl 加一个 cron

整套 CI 缓存就是三条命令加一个清理任务。PUT 写 tar 包,GET 读它,find -atime 清理它。再没有第四块——没有 IAM 策略、没有桶生命周期、没有签名 URL 那套仪式。

WRITE

压缩并 PUT

安装完成后,runner 通过 tar | zstd 把 node_modules 流式管道成一个 tar 包,一次性 PUT 到 /files/cache。Hoody 把请求体作为单个二进制 blob 写到磁盘。无 multipart、无分片上传器、无 SDK。

# yarn install 之后,推送构建产物tar c node_modules | zstd -T0 | curl -T - https://files.containers.hoody.com/cache/$KEY.tar.zst
READ

GET 并解压

下一个 job 的第一步就是一条 curl。请求体以线速从 NVMe 出来,因为缓存就和 runner 跑在同一台物理机上——无出站跳跃、无跨 AZ 拉取、无 CloudFront 边缘。

# 下一个 job:一行 curl 拉下并解压curl -fsS https://files.containers.hoody.com/cache/$KEY.tar.zst | tar x -I zstd
PRUNE

find -atime · 每晚

Hoody Cron 每晚触发一次。find /files/cache -atime +30 -delete 把任何一个月内没有 job 读过的内容扔掉。无保留策略、无 Glacier 分层、无要维护的 lifecycle JSON。

# 每晚 cron —— 30 天没读过的就清掉find /files/cache -atime +30 -delete

PUT 写,GET 读,find 清理。Hoody Files API 同时是缓存服务器、清理引擎和审计日志——全都隐藏在同一个 /files/[path] URL 之下。

use-cases / ci-cache-without-s3 / powers

「缓存即文件夹」的三种力量

把缓存推到一个独立厂商曾经是合理的——那时存储稀缺。在裸金属容器上,这只是多了一个供应商。

经济性

无 GB-月、无出站、无请求费

S3 收三个表:存储、出站、按请求。Hoody Files 随容器附赠——你已经付费的磁盘就是缓存所在的磁盘。字节从不跨越任何计费边界。

延迟

NVMe 而不是跨区域

读取来自跑构建的同一台物理机。无需解析 S3 端点、无需对某个区域做 TLS 握手、无前缀吞吐限速。1.4 GB 的 Rust target 几秒就能解压。

归属

一段供应商关系,而不是两段

你的 runner 和你的缓存住在同一个实例上,在同一份发票上,使用同一个 SSH 会话调试。当你把容器关掉,缓存就是那个磁盘镜像——只要再启动它,缓存随之回来。

use-cases / ci-cache-without-s3 / invoice

账单上消失了什么

一个典型中型 CI 大约每月搬运 1.4 TB 缓存流量。下面是它在 AWS 上构建出的条目,以及它在 Hoody 上构建出的条目。

之前 · S3 发票本月,在 AWS 上
  • 存储 · GB-月$1.0947.2 GB × $0.023
  • 出站 · 出方向 GB$127.801.42 TB × $0.090
  • PUT 请求$2.06412k × $5/M
  • GET 请求$4.5611.4M × $0.40/M
  • CloudFront / NAT−$57.71跨 AZ 拉取
月度合计$78
五条条目 · 五个费率 · 一个桶
之后 · HOODY FILES本月,在 Hoody 上
  • 容器上的磁盘no extra charge已包含在容器套餐内
  • job 之间的出站no extra charge环回 · 不离开服务器
  • PUT / GET 请求no per-request or per-GB meter无按请求计费表
  • 供应商关系no extra chargerunner 和缓存共用一份发票
  • 已用 47.2 GB套餐内余量来自跑容器的同一块磁盘
月度合计included in server price
一块磁盘 · 一份账单 · 零新供应商

当缓存住在跑构建的那台机器上,S3 原本要读的计费表就没东西可读。条目之所以不动,是因为根本没有可计费的交易发生。

use-cases / ci-cache-without-s3 / capacity

Files 端点的承诺

Hoody Files 不是一层薄壳——它是一个真正的持久化后端,带哈希、历史、范围读取和审计日志。CI 缓存只用了它实际暴露能力的一小片。

  1. 一个 URL · 任意构建产物/files/[path]

    PUT 写,GET 读,HEAD 拿 ETag 和 Content-Length,?hash 拿 SHA256,?stat 拿元数据。缓存使用的是同一个端点家族,日志、构建、共享构建产物也都用它。

  2. 时光回溯读取?at · ?revision

    每次写入都进文件日志。按时间戳或按路径修订号拉取昨天的缓存——调试一个 flaky 不再需要单独的快照工具。

  3. 用大了再挂载60+ backends

    如果缓存真的得住进 S3、B2 或 Drive 文件夹,就把它当后端挂上,保持同一个 /files/[path] URL。runner 代码完全不变——缓存只是搬了家。

数字反映的是已发布的 Hoody Files API 表面——`GET/PUT/HEAD/PATCH /api/v1/files/[path]`、`?hash`/`?stat`/`?at`/`?revision`/`?history` 查询参数,以及 `/api/v1/journal` 下的文件日志端点。

use-cases / ci-cache-without-s3 / punchline

你的 CI 缓存不再是一个独立厂商。它是你已经租用的服务器上的一个文件夹。

昨天 · 五个费率今天 · 一块磁盘
旧账单上有什么S3 桶 + 出站 + 请求 + lifecycle五条条目 · 独立 IAM · 独立厂商
现在它是什么PUT /files/cache/$KEY · GET /files/cache/$KEY两条 curl —— 缓存就是 runner 自己的磁盘
阅读 Files 规范
use-cases / ci-cache-without-s3 / replaces

这替换了什么

标准的「拿来就用」缓存后端各自向你收一段供应商关系、一份出站账单或每次构建的费用。/files 一个都不收。

  • AWS S3 桶当缓存存储、出站、请求——为只留两天的 tar 包计三个表
  • GitHub Actions 缓存10 GB 免费,然后按 GB 收费,且 7 天驱逐你无法调
  • BuildJet 缓存按 runner 收费,存的内容却仍然不在 runner 上
  • Bazel 远程缓存服务另一个守护进程加一套缓存协议要照看
  • Turborepo Remote Cache为你 monorepo 已经产出的 tar 包按构建收费
  • Earthly Cloud 缓存为「不过是 curl + tar」的事情托管一个远程后端
use-cases / ci-cache-without-s3 / cta

别再向第二个云租缓存了。把 tar 包写到你已经付过费的磁盘上,再 curl 回来。

阅读 Files API
use-cases / ci-cache-without-s3 / related

阅读其他内容