第3章 远程缓存搭建:HTTP 缓存服务器选型与 Docker 部署
3.1 为什么需要远程缓存?
在大型多模块 Gradle 项目中,本地缓存只能加速单机构建。团队协作或 CI/CD 流水线中,每次构建都需要重新下载外部依赖,重复缓存本地构建产物。远程缓存(Remote Build Cache)允许所有开发者及 CI 节点共享编译产物,显著缩短构建时间。核心原理是:Gradle 构建结束后将模块的输出(如 class 文件、jar 包)上传到 HTTP 缓存服务器,其他节点构建时先根据缓存 key 远程拉取,命中则跳过本地编译和测试。
选择适当的 HTTP 缓存服务器是搭建远程缓存的第一步。本章对比三种主流方案,并给出 Docker 部署与 HTTPS 配置的完整实现。
3.2 缓存服务器选型对比
| 特性 | Nginx + 文件系统 | JFrog Artifactory | Gradle Enterprise |
|---|---|---|---|
| 成本 | 开源免费 | 企业版收费(有社区版但限制多) | 商业许可,价格较高 |
| 缓存协议支持 | 纯 HTTP PUT/GET,需手动配置 | 原生支持 Gradle Build Cache(REST API) | 深度集成 Gradle,内建缓存监控 |
| 存储后端 | 本地磁盘 / NFS / S3(需额外配置) | 本地磁盘、S3、GCS 等 | 本地磁盘 + 集群存储 |
| HTTPS 配置 | 快速,Nginx 原生支持 | 需反向代理或自带 HTTPS(企业版) | 内置 HTTPS,支持 mTLS |
| 管理与监控 | 无自带 UI,依赖日志 | Web 平台,缓存分析、清理策略 | 构建扫描、缓存命中率、加速效果展示 |
| 适用场景 | 小团队、偏技术型、预算有限 | 中型/大型团队,需要制品管理 | 大型企业,端到端构建优化 |
选型建议:若团队人数少于 20 且希望零成本快速验证远程缓存效果,优先选择 Nginx。若已有 Artifactory 用于依赖管理,可直接复用其 Gradle 缓存支持。Gradle Enterprise 适合追求极致构建效率和可观测性的组织,但需要商业授权。
3.3 远程缓存架构总览
下图清晰展示了远程缓存系统的基本数据流。Gradle 客户端(本地或 CI)向缓存服务器发送 PUT(缓存存储)和 GET(缓存读取)请求,服务器根据缓存 key 返回文件或 404。缓存 key 由构建输入(源文件哈希、任务类型、JDK 版本等)计算得出。
3.4 Docker 部署(以 Nginx 为例)
Nginx 作为缓存服务器最简单可靠,只需配置 HTTP PUT 和 GET 访问的静态目录作为缓存存储。以下提供完整的 Docker Compose 部署文件。
3.4.1 创建项目目录结构
mkdir -p ~/gradle-cache-nginx/{conf,cache,ssl}
cd ~/gradle-cache-nginx
3.4.2 编写 Nginx 配置文件
文件:conf/nginx.conf
worker_processes auto;
events { worker_connections 1024; }
http {
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server {
listen 80;
server_name cache.example.com;
# 缓存根目录
root /var/cache/nginx;
# 允许 HTTP PUT 上传
location ~ ^/cache/(.+)$ {
# 缓存 key 校验:只允许特定哈希格式
if ($request_method = PUT) {
client_body_in_file_only clean;
client_body_buffer_size 16k;
client_max_body_size 1000m;
dav_methods PUT;
create_full_put_path on;
dav_access user:rw group:rw all:r;
break;
}
if ($request_method = GET) {
try_files /var/cache/nginx/$1 =404;
break;
}
}
# 健康检查
location /health {
return 200 "OK\n";
}
}
}
3.4.3 生成 docker-compose.yml
version: '3.8'
services:
cache:
image: nginx:1.26-alpine
container_name: gradle-cache
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf:ro
- ./cache:/var/cache/nginx
- ./ssl:/etc/nginx/ssl:ro
ports:
- "80:80"
- "443:443"
restart: unless-stopped
3.4.4 启动容器
docker compose up -d
验证部署:执行
curl -X PUT --data-binary @test.jar http://localhost:80/cache/mykey,然后 curl -O http://localhost:80/cache/mykey 应能成功下载相同的文件。
3.5 HTTPS 配置
生产环境必须启用 HTTPS 以保证传输安全。Gradle 默认对远程缓存服务器进行 TLS 校验。下面以自签名证书为例演示,生产环境应使用受信任 CA。
3.5.1 生成自签名证书(仅用于演示)
cd ~/gradle-cache-nginx/ssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cache.key -out cache.crt \
-subj "/CN=cache.example.com"
3.5.2 修改 Nginx 配置,启用 HTTPS
在 conf/nginx.conf 中添加 server 块:
server {
listen 443 ssl http2;
server_name cache.example.com;
ssl_certificate /etc/nginx/ssl/cache.crt;
ssl_certificate_key /etc/nginx/ssl/cache.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 复用之前的缓存 location 配置
location ~ ^/cache/(.+)$ {
if ($request_method = PUT) {
client_body_in_file_only clean;
client_body_buffer_size 16k;
client_max_body_size 1000m;
dav_methods PUT;
create_full_put_path on;
dav_access user:rw group:rw all:r;
break;
}
if ($request_method = GET) {
try_files /var/cache/nginx/$1 =404;
break;
}
}
location /health { return 200 "OK\n"; }
}
3.5.3 重启 Nginx 容器
docker compose restart
3.5.4 客户端 Gradle 端配置
在 gradle.properties 或 build.gradle 中启用远程缓存:
# gradle.properties
org.gradle.caching=true
org.gradle.caching.http.url=https://cache.example.com/cache/
如果使用自签名证书,还需要将证书导入 Gradle 的信任库:
keytool -import -trustcacerts -keystore $JAVA_HOME/lib/security/cacerts \
-storepass changeit -alias gradle-cache -file ssl/cache.crt
3.6 调试与常见错误
3.6.1 调试命令
- 查看缓存服务器日志:
docker compose logs -f cache - 测试 PUT:
curl -k -X PUT --data-binary @dummy.jar https://localhost:443/cache/abc123 - 测试 GET:
curl -k -o /dev/null https://localhost:443/cache/abc123 -w "%{http_code}" - 检查 Nginx 访问日志:
docker exec -it gradle-cache cat /var/log/nginx/access.log
3.6.2 常见错误及解决方案
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
Gradle 报 Cannot resolve cache key: 403 Forbidden | Nginx 的 dav_methods 未正确启用 | 确认 location 块中写入了 dav_methods PUT,且目录权限可写 |
| HTTPS 连接被拒绝 | 证书 / 端口映射未生效 | 检查 docker-compose.yml 的 ports 是否包含 443:443;证书路径是否正确 |
| 缓存文件上传后下载为 404 | 文件存储路径与 try_files 路径不一致 | 确保 client_body_in_file_only 写入的路径与 try_files 路径一致 |
| Gradle 构建速度没有提升 | 缓存未命中或 key 不匹配 | 确认构建输入一致(JDK 版本、任务配置、源文件哈希) |
3.7 性能优化与运维建议
- 缓存清理策略:Nginx 自带
proxy_cache_path但没有原生的 LRU 清理。建议编写 cron 脚本定期删除超过 N 天的文件:find /var/cache/nginx -type f -mtime +30 -delete。 - 高并发:调整
worker_processes auto和worker_connections 2048,启用 sendfile 和 tcp_nopush。 - 后端存储:若缓存量大,将
/var/cache/nginx挂载到 SSD 或 NFS;切勿使用跨地域的远程文件系统。 - 监控:通过
/health端点配合 Prometheus + Grafana 监控。 - 测试环境:先用
curl -s -w "@%{http_code}" -o /dev/null测试每秒请求量,确保满足团队 CI 峰值。