diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..0f7fc27 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,225 @@ +# gitmirrorcache + +[![Latest release](https://img.shields.io/github/v/tag/0lut/gitmirrorcache?sort=semver&label=release)](https://github.com/0lut/gitmirrorcache/tags) +[![Container image](https://img.shields.io/badge/ghcr.io-0lut%2Fgitmirrorcache-blue?logo=docker)](https://github.com/0lut/gitmirrorcache/pkgs/container/gitmirrorcache) + +一个面向高频克隆自动化场景(CI 运行器、编码代理、构建集群)的只读 Git 获取缓存。它位于允许的 HTTPS 上游(地址格式为 `host/owner/repo`)之前,使客户端从缓存中获取数据,而不是向上游发送数千次相同的克隆请求。兼容 S3 的对象存储是持久化的真相来源;本地磁盘是一个可随时重建的临时热层。 + +它提供了两个接口: + +- 实例化 API (`/v1/materialize`, `/v1/resolve`):用于根据提交 (commit)、分支 (branch) 或默认分支来预热和检查缓存状态。 +- 只读 Git 远程接口 ` /git/{host}/{owner}/{repo}.git`:标准 Git 客户端可以通过 Smart HTTP 进行 clone 和 fetch,支持浅克隆 (shallow) 和无 blob 克隆 (blobless)。拒绝推送 (`git-receive-pack`)。 + +在缓存未命中(冷启动)时,服务器将上游的响应直接代理给客户端,并在后台预热缓存,因此首次克隆的延迟与直接克隆相当。一旦缓存预热完成,Pack 数据将从本地裸仓库提供。引用 (Ref) 广告和分支选择器仍会向上游验证引用,因此客户端永远不会看到过时的 tip。 + +## 快速上手 + +```sh +cargo test --workspace +GIT_CACHE_CONFIG=config/local.example.toml cargo run -p git-cache-api +curl -s http://127.0.0.1:8080/healthz +``` + +本地配置启用了直接的 Git 远程接口,并预期在 `./tmp/upstreams/{host}/{owner}/{repo}.git` 下有模拟的上游裸仓库。详情请参阅 [docs/local-dev.md](docs/local-dev.md)。 + +## 使用缓存 + +像使用任何其他 HTTP 远程仓库一样进行 clone 或 fetch: + +```sh +git clone http://127.0.0.1:8080/git/github.com/org/repo.git +git clone --depth 1 http://127.0.0.1:8080/git/github.com/org/repo.git +git fetch http://127.0.0.1:8080/git/github.com/org/repo.git refs/heads/main +``` + +或者直接调用实例化 API: + +```sh +curl -s http://127.0.0.1:8080/v1/materialize \ + -H 'content-type: application/json' \ + -d '{"repo":"github.com/org/repo","selector":{"branch":"main"}}' + +curl -s http://127.0.0.1:8080/v1/resolve \ + -H 'content-type: application/json' \ + -d '{"repo":"github.com/org/repo","selector":{"default_branch":true}}' +``` + +选择器 (`selector`) 包括 `commit`, `short_commit`, `branch`, 和 `default_branch`。请求体要求严格:仅接受 `repo`, `selector`, 和 `upstream_authorization`。 + +对于私有仓库,请在每次请求时传递凭据。实例化 API 使用特定的缓存头;直接 Git 访问使用标准的 HTTP 认证头: + +```sh +curl -s http://127.0.0.1:8080/v1/materialize \ + -H 'content-type: application/json' \ + -H 'git-cache-upstream-authorization: Basic ' \ + -d '{"repo":"github.com/org/private","selector":{"branch":"main"},"upstream_authorization":"required"}' + +git -c http.extraHeader='Authorization: Basic ' \ + fetch http://127.0.0.1:8080/git/github.com/org/private.git refs/heads/main +``` + +客户端可以通过在请求中添加 `git-cache-use-proxy-on-miss: false` 头部来选择在缓存未命中时不使用代理。 + +## 配置 + +服务器读取 TOML 配置文件(通过 `GIT_CACHE_CONFIG` 设置路径;参见 `config/*.example.toml`)或单个环境变量。当设置了 `GIT_CACHE_CONFIG` 时,文件配置优先,其他配置变量将被忽略。例外情况是 S3 凭据 (`GIT_CACHE_S3_ACCESS_KEY`, `GIT_CACHE_S3_SECRET_KEY`, `GIT_CACHE_S3_SESSION_TOKEN`, `GIT_CACHE_S3_REGION`),它们始终从环境变量读取,而不从文件中读取。 + +### 核心配置 (Core) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_CONFIG` | 未设置 | TOML 配置文件路径。如果设置,除上述 S3 凭据外,其他 `GIT_CACHE_*` 变量将被忽略。 | +| `GIT_CACHE_BIND_ADDR` | `127.0.0.1:8080` | HTTP 服务器监听的地址和端口。 | +| `GIT_CACHE_ROOT` | `./cache` | 本地热缓存目录(裸仓库、临时文件、仓库索引)。 | +| `GIT_CACHE_ALLOWED_UPSTREAM_HOSTS` | `github.com` | 缓存允许访问的上游主机白名单,用逗号分隔(例如 `github.com,gitlab.com,git.internal.example`)。 | +| `GIT_CACHE_UPSTREAM_ROOT` | 未设置 | 可选的本地上游裸仓库目录,用于替代真实的网络上游(主要用于测试和本地开发)。 | +| `GIT_CACHE_RATE_LIMIT_PER_MINUTE` | `120` | 实例化 (materialize) 请求的全局每分钟频率限制。 | + +### 对象存储 (Object store) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_OBJECT_STORE_KIND` | `local` | `local` (文件系统) 或 `s3`。使用 S3 需要在构建时启用 `s3` feature。 | +| `GIT_CACHE_OBJECT_STORE_ROOT` | `./tmp/object-store` | `local` 对象存储的根目录。 | +| `GIT_CACHE_S3_BUCKET` | 未设置 | S3 存储桶名称。当 kind 为 `s3` 时必填。 | +| `GIT_CACHE_S3_PREFIX` | `repos` | 存储桶内的键前缀。会自动追加架构版本后缀(例如 `repos` 存储在 `repos-v3` 下)。 | +| `GIT_CACHE_S3_ENDPOINT` | 未设置 | 兼容存储(如 MinIO, Cloudflare R2 等)的自定义 S3 端点。启用路径风格寻址 (path-style addressing)。 | +| `GIT_CACHE_S3_REGION` | 回退至 `AWS_REGION` / `AWS_DEFAULT_REGION` | 存储桶所在的 AWS 区域。 | +| `GIT_CACHE_S3_ACCESS_KEY` / `GIT_CACHE_S3_SECRET_KEY` | 未设置 | 静态 S3 凭据。如果未设置,将使用标准的 AWS 凭据链(环境变量、配置文件、IAM 角色、工作负载标识)。 | +| `GIT_CACHE_S3_SESSION_TOKEN` | 回退至 `AWS_SESSION_TOKEN` | 临时凭据的会话令牌。 | + +### Git 远程接口 (Git remote) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_GIT_REMOTE_COMMIT_READ_THROUGH` | `true` | 在客户端请求期间,如果提交缺失,则从上游获取而不是直接报错。 | +| `GIT_CACHE_GIT_REMOTE_PROXY_ON_MISS_BY_DEFAULT` | `true` | 缓存未命中时,立即将上游的 upload-pack 响应代理给客户端,并在后台预热缓存。 | +| `GIT_CACHE_GIT_REMOTE_PROXY_TEE_IMPORT` | `true` | 在代理未命中响应时,将响应流同步写入 (tee) 本地缓存,而不是随后重新从上游获取。 | +| `GIT_CACHE_GIT_REMOTE_BACKGROUND_IMPORT_CONCURRENCY` | `1` | 同时运行的后台缓存预热导入数量。 | + +### Git 子进程 (Git subprocess) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_GIT_BINARY` | `git` | `git` 二进制文件的路径。 | +| `GIT_CACHE_GIT_TIMEOUT_SECONDS` | `120` | 单个 Git 子进程调用的超时时间。 | +| `GIT_CACHE_MAX_GIT_OUTPUT_BYTES` | 16 MiB | 捕获的 Git 子进程输出上限。 | +| `GIT_CACHE_MAX_CONCURRENT_GIT_PROCESSES` | `64` | 限制并发 Git 子进程数量的信号量(主要的 CPU/内存控制开关)。 | +| `GIT_CACHE_ASYNC_MATERIALIZE_CONCURRENCY` | `2` | 后台实例化工作的并发数。 | +| `GIT_CACHE_UPSTREAM_AUTH_TOKEN_ENV` | 未设置 | 保存部署级上游令牌的另一个环境变量名称,通过 Git 配置环境注入(绝不通过 argv 或清单文件)。 | + +### 磁盘 (Disk) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_DISK_QUOTA_BYTES` | 10 GiB | 热缓存磁盘配额;通过 LRU 淘汰机制将使用量保持在此值以下。Helm chart 将此值设置为 100 GiB 以匹配其默认的 100Gi PVC。请确保配额小于或等于卷大小。 | +| `GIT_CACHE_DISK_MIN_FREE_BYTES` | 1 GiB | 缓存卷上需保留的最小剩余磁盘空间。 | +| `GIT_CACHE_DISK_ACCESS_FLUSH_SECS` | `60` | 缓冲的仓库访问时间戳刷新到磁盘索引的频率。 | + +### 压缩与关闭 (Compaction and shutdown) + +| 变量 | 默认值 | 功能描述 | +| --- | --- | --- | +| `GIT_CACHE_COMPACTION_CHAIN_DEPTH_THRESHOLD` | `10` | 触发压缩为单个基础 pack 的生成链深度阈值。 | +| `GIT_CACHE_COMPACTION_INLINE` | `false` | 在发布后直接运行压缩,而不是依赖定时任务。 | +| `GIT_CACHE_COMPACTION_RETENTION_SECS` | 24h | 被取代的生成版本在被清理删除前保留的时间。 | +| `GIT_CACHE_SHUTDOWN_READINESS_DELAY_SECONDS` | `5` | 收到 SIGTERM 后,`/healthz` 在停止流量分发前失效的时间,以便负载均衡器停止路由流量。 | +| `GIT_CACHE_SHUTDOWN_DRAIN_TIMEOUT_SECONDS` | `60` | 退出前处理在途请求的最大等待时间。 | + +## 部署 + +### Helm (Kubernetes) + +Helm chart 位于 [`deploy/helm/gitmirrorcache`](deploy/helm/gitmirrorcache)。发布版 chart 作为 OCI 产物与容器镜像一起发布到 GHCR。该 chart 将服务器部署为 StatefulSet,配备用于热缓存的持久卷,并运行一个每小时一次的 CronJob 用于压缩。 + +在仓库根目录下执行: + +```sh +helm install git-cache deploy/helm/gitmirrorcache \ + --set config.objectStore.s3.bucket=my-git-cache-bucket +``` + +AWS 区域将从环境中获取(IRSA 会在 EKS 上自动注入 `AWS_REGION`);仅在没有其他提供方式时才设置 `aws.region`。 + +对于已发布的 chart,将 `CHART_REF` 设置为 OCI chart 引用,将 `CHART_VERSION` 设置为发布版本: + +```sh +helm install git-cache "${CHART_REF}" \ + --version "${CHART_VERSION}" \ + --set config.objectStore.s3.bucket=my-git-cache-bucket +``` + +发布标签 `vX.Y.Z` 对应 chart 版本 `X.Y.Z`。有关凭据、本地 checkout 安装、规模设定和扩容,请参阅 [chart README](deploy/helm/gitmirrorcache/README.md)。 + +### AWS (ECS on EC2) + +维护的 AWS 部署路径是基于 Graviton EC2 的 ECS,使用宿主机挂载的 EBS 作为热缓存,S3 作为持久化存储。随附的包装脚本可完成构建、部署和冒烟测试: + +```sh +AWS_REGION=us-west-2 ENVIRONMENT=dev-arm NAME_PREFIX=gitmirrorcache-arm \ + scripts/aws/deploy-and-smoke.sh +``` + +可以使用 `scripts/aws/deploy-preview.sh` 在共享 ALB 后面为任何分支、标签或提交部署预览栈。详情见 [docs/deployment.md](docs/deployment.md)。 + +生产环境目标会拉取最新的已发布 GHCR 镜像,并跳过本地 Docker/ECR 镜像构建: + +```sh +AWS_REGION=us-west-2 scripts/aws/deploy-prod.sh +``` + +Cloudflare 前端在 `gitcache.sh` 提供落地页,并将 `/git/*` 及其 API 路径代理到生产 ALB,因此公共克隆可以使用顶级域名: + +```sh +AWS_REGION=us-west-2 scripts/cloudflare/deploy-static-site.sh +git clone https://gitcache.sh/git/github.com/org/repo.git +``` + +### Docker + +预构建的多架构镜像在 `v*` 发布标签下发布至 `ghcr.io/0lut/gitmirrorcache`: + +```sh +docker pull ghcr.io/0lut/gitmirrorcache:latest # 最新发布版 +docker pull ghcr.io/0lut/gitmirrorcache:1.2.3 # 固定具体版本 +``` + +多阶段 [`Dockerfile`](Dockerfile) 可从源码构建服务器和 CLI;可以通过上述环境变量进行配置。针对本地 S3 测试,提供了一个 MinIO compose 文件: + +```sh +docker compose -f docker-compose.minio.yml up -d +``` + +### 裸机 (Bare metal) + +它是一个单二进制文件加上 `git` CLI。使用 `cargo build --release -p git-cache-api --features s3` 构建,指定配置文件或环境变量,并在任何进程管理器下运行即可。 + +## CLI + +```sh +cargo run -p git-cache-cli -- config +cargo run -p git-cache-cli -- disk-status +cargo run -p git-cache-cli -- warm github.com/org/repo main +cargo run -p git-cache-cli -- optimize github.com/org/repo +cargo run -p git-cache-cli -- compact --all --dry-run +cargo run -p git-cache-cli -- compact --repo github.com/org/repo +``` + +## 测试 + +```sh +cargo test --workspace +``` + +可选的集成测试仅使用 Python 标准库针对真实的 GitHub 仓库运行: + +```sh +RUN_GITHUB_INTEGRATION=1 python3 -m unittest -v integration_tests.test_astral_uv +RUN_GITHUB_INTEGRATION=1 python3 -m unittest -v integration_tests.test_git_remote_public +``` + +关于 MinIO/S3 变体,请参阅 [integration_tests/README.md](integration_tests/README.md)。S3 适配器受 feature 门控: + +```sh +cargo test -p git-cache-objectstore --features s3 +```