Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -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 <base64-user-colon-token>' \
-d '{"repo":"github.com/org/private","selector":{"branch":"main"},"upstream_authorization":"required"}'

git -c http.extraHeader='Authorization: Basic <base64-user-colon-token>' \
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
```