4. 远程缓存服务搭建:HTTP缓存后端、Nginx配置、认证机制、HTTPS支持
Gradle 远程缓存的核心是将构建产物(缓存条目)存储在一个可由多台机器共享的 HTTP 服务后端上。本章以 Nginx 作为 HTTP 缓存后端载体,从零搭建一套支持 认证机制 和 HTTPS 加密 的生产级远程缓存服务。
- 存储层:文件系统目录,按缓存键(Cache Key)组织目录与文件;
- 代理层:Nginx 反向代理,提供 HTTP PUT/GET 接口;
- 安全层:Basic Auth 或 认证 + TLS/SSL 传输加密;
- 客户端层:Gradle 构建机通过
settings.gradle配置远程缓存地址。
4.1 远程缓存架构原理
Gradle 远程缓存采用 HTTP REST 风格接口。缓存键(Cache Key)对应 URL 路径,缓存体(序列化的构建产物)对应 HTTP 请求体。Nginx 作为反向代理,将 HTTP 请求映射为本地文件系统读写。
| HTTP 方法 | URL 模式 | 语义 | Nginx 处理动作 |
|---|---|---|---|
GET | /cache/<cache-key> | 读取缓存条目 | 检查文件是否存在,存在则返回 200 + 文件内容 |
PUT | /cache/<cache-key> | 存储缓存条目 | 将请求体写入文件,返回 201 |
HEAD | /cache/<cache-key> | 探测缓存是否存在 | 返回 200 或 404,无响应体 |
ab3f8d2c1e...。Nginx 层面可直接将缓存键作为文件名存储,无需二次哈希。
4.2 环境准备与依赖
搭建远程缓存服务需要以下组件:
- 操作系统:Ubuntu 22.04 LTS / CentOS 7+ 或任何支持 Nginx 的 Linux 发行版;
- Nginx:版本 ≥ 1.20,需编译
ngx_http_dav_module(默认已包含)以支持 PUT 方法; - SSL 证书:自签名证书(测试)或 Let's Encrypt 证书(生产);
- htpasswd:用于生成 Basic Auth 密码文件(Apache Utils 或
openssl均可)。
# Ubuntu 安装依赖
sudo apt update
sudo apt install -y nginx apache2-utils openssl
# CentOS / RHEL
sudo yum install -y nginx httpd-tools openssl
4.3 HTTP 缓存后端存储结构
在文件系统上创建一个专用目录作为缓存根目录,Nginx 将以 客户端请求的 URI 路径 为相对路径读写文件。
# 创建缓存存储目录
sudo mkdir -p /var/cache/gradle-remote
sudo chown -R www-data:www-data /var/cache/gradle-remote
sudo chmod 750 /var/cache/gradle-remote
目录结构示例(实际由 Nginx 动态创建):
/var/cache/gradle-remote/
├── a1/
│ └── b2/
│ └── f3d8c2e1... # 缓存键 = a1b2f3d8c2e1...
├── c4/
│ └── d5/
│ └── e6a7b8c9... # Nginx 按需创建子目录
└── ...
/var/cache/gradle-remote 单独挂载磁盘,并设置磁盘配额或定期清理策略。
4.4 Nginx 配置详解
Nginx 配置分为三个关键块:server 块(监听端口)、location 块(路由规则)、dav_methods(启用 PUT/DELETE)。
4.4.1 基础缓存服务器配置(无认证)
# /etc/nginx/sites-available/gradle-cache
server {
listen 8080;
server_name cache.example.com;
# 缓存存储根目录
root /var/cache/gradle-remote;
# 启用 HTTP DAV 方法:PUT、DELETE、MKCOL
dav_methods PUT DELETE MKCOL;
# 自动创建不存在的目录(按 URI 层级)
create_full_put_path on;
# 设置新文件的权限
dav_access user:rw group:rw all:r;
location /cache/ {
# 允许 GET(读取)和 HEAD(探测)
# PUT/DELETE 由 dav_methods 启用
limit_except GET HEAD PUT DELETE {
deny all;
}
# 日志格式(记录缓存键和状态)
access_log /var/log/nginx/gradle-cache-access.log;
error_log /var/log/nginx/gradle-cache-error.log;
}
}
create_full_put_path on—— 允许 Nginx 按 URL 路径自动创建中间子目录,避免手动建目录;dav_access user:rw group:rw all:r—— 写入的缓存文件权限为 664;limit_except GET HEAD PUT DELETE—— 仅允许缓存操作必需的 HTTP 方法,提升安全性。
4.4.2 启用目录哈希(避免单目录文件过多)
当缓存条目数量极大时,将所有文件放在同一目录会导致文件系统性能下降。建议启用 哈希目录层级 将文件分散存储:
# /etc/nginx/sites-available/gradle-cache (优化版)
server {
listen 8080;
server_name cache.example.com;
root /var/cache/gradle-remote;
dav_methods PUT DELETE MKCOL;
create_full_put_path on;
dav_access user:rw group:rw all:r;
location /cache/ {
limit_except GET HEAD PUT DELETE {
deny all;
}
# 使用哈希子目录:按文件名前 2 个字符创建一级子目录
# 注意:此功能需要 ngx_http_sub_module
# 实际可通过 Lua 或 rewrite 实现,此处展示标准方案
access_log /var/log/nginx/gradle-cache-access.log;
# 若使用 Nginx + Lua 模块,可实现动态子目录
# 简化方案:Gradle 缓存键本身已足够分散,可直接存储
}
}
proxy_store 或自定义 Lua 脚本做两级子目录。
4.5 认证机制实现
远程缓存服务必须限制访问权限,防止缓存数据泄漏或被恶意填充。本章实现 HTTP Basic Authentication 和 Bearer 两种方案。
4.5.1 Basic Auth 配置
使用 htpasswd 创建用户密码文件:
# 创建密码文件(首次创建加 -c)
sudo htpasswd -c /etc/nginx/.htpasswd gradle-cache
# 添加更多用户(不加 -c)
sudo htpasswd /etc/nginx/.htpasswd build-agent-1
在 Nginx location 块中启用认证:
location /cache/ {
# 启用 Basic Auth
auth_basic "Gradle Remote Cache - Authentication Required";
auth_basic_user_file /etc/nginx/.htpasswd;
limit_except GET HEAD PUT DELETE {
deny all;
}
dav_methods PUT DELETE MKCOL;
create_full_put_path on;
dav_access user:rw group:rw all:r;
access_log /var/log/nginx/gradle-cache-access.log;
error_log /var/log/nginx/gradle-cache-error.log;
}
4.5.2 Bearer 方案(推荐生产使用)
Basic Auth 每次请求都会传输明文密码(虽经 Base64 编码,但非加密)。推荐使用 Bearer 配合 HTTPS 实现更安全的认证:
# /etc/nginx/sites-available/gradle-cache ( 认证版)
location /cache/ {
# 使用 map 指令从 Authorization 头中提取
# 并在 if 中进行校验(示例为静态 )
set $valid_ "0";
if ($http_authorization ~ "^Bearer gradle-cache--2024$") {
set $valid_ "1";
}
if ($valid_ = "0") {
return 401 "Unauthorized - Invalid or missing ";
}
limit_except GET HEAD PUT DELETE {
deny all;
}
dav_methods PUT DELETE MKCOL;
create_full_put_path on;
dav_access user:rw group:rw all:r;
access_log /var/log/nginx/gradle-cache-access.log;
error_log /var/log/nginx/gradle-cache-error.log;
}
永远不要将硬编码 提交到版本控制系统中。
4.6 HTTPS 支持配置
HTTPS 为缓存传输提供机密性和完整性保护,是生产环境的强制要求。
4.6.1 生成 SSL 证书(自签名测试用)
# 生成私钥(2048 位 RSA)
sudo openssl genrsa -out /etc/nginx/ssl/gradle-cache.key 2048
# 生成自签名证书(有效期 365 天)
sudo openssl req -new -x509 -days 365 \
-key /etc/nginx/ssl/gradle-cache.key \
-out /etc/nginx/ssl/gradle-cache.crt \
-subj "/CN=cache.example.com"
4.6.2 配置 SSL 终止于 Nginx
# /etc/nginx/sites-available/gradle-cache-ssl
server {
listen 443 ssl http2;
server_name cache.example.com;
# SSL 证书路径
ssl_certificate /etc/nginx/ssl/gradle-cache.crt;
ssl_certificate_key /etc/nginx/ssl/gradle-cache.key;
# 安全协议与加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 缓存存储配置
root /var/cache/gradle-remote;
dav_methods PUT DELETE MKCOL;
create_full_put_path on;
dav_access user:rw group:rw all:r;
location /cache/ {
auth_basic "Gradle Remote Cache";
auth_basic_user_file /etc/nginx/.htpasswd;
limit_except GET HEAD PUT DELETE {
deny all;
}
access_log /var/log/nginx/gradle-cache-ssl-access.log;
error_log /var/log/nginx/gradle-cache-ssl-error.log;
}
}
# 可选:HTTP 重定向到 HTTPS
server {
listen 80;
server_name cache.example.com;
return 301 https://$server_name$request_uri;
}
4.6.3 使用 Let's Encrypt 免费证书(生产推荐)
# 安装 certbot
sudo apt install -y certbot python3-certbot-nginx
# 获取并自动配置 SSL 证书
sudo certbot --nginx -d cache.example.com
# 证书自动续期(默认已添加 systemd timer)
sudo certbot renew --dry-run
4.7 客户端配置与验证
Gradle 构建端通过 settings.gradle 或 gradle.properties 配置远程缓存服务地址及凭证。
4.7.1 settings.gradle 配置
// settings.gradle
buildCache {
remote(HttpBuildCache) {
url = 'https://cache.example.com/cache/'
credentials {
username = 'gradle-cache'
password = 'your-password'
}
// 若使用 Bearer :
// header = ['Authorization': 'Bearer gradle-cache--2024']
push = true // 允许本机上传缓存(默认 false)
enabled = true
}
}
4.7.2 gradle.properties 配置(通过系统属性注入)
# gradle.properties
org.gradle.caching=true
org.gradle.caching.http.url=https://cache.example.com/cache/
org.gradle.caching.http.username=gradle-cache
org.gradle.caching.http.password=your-password
# org.gradle.caching.http.header=Authorization: Bearer gradle-cache--2024
4.7.3 验证缓存是否生效
# 构建项目(首次构建,缓存未命中)
./gradlew clean build --build-cache
# 再次构建(应命中远程缓存,任务显示 FROM-CACHE)
./gradlew clean build --build-cache
# 查看 Nginx 访问日志确认
tail -f /var/log/nginx/gradle-cache-ssl-access.log
成功命中时,控制台输出示例:
> Task :compileJava FROM-CACHE
> Task :processResources FROM-CACHE
> Task :classes FROM-CACHE
> Task :jar FROM-CACHE
4.8 调试与常见错误
| 错误现象 | 可能原因 | 排查命令/方法 |
|---|---|---|
客户端收到 401 Unauthorized | 认证凭证错误或缺失 | 检查 credentials {} 或 是否正确;测试: curl -u user:pass -X GET https://cache.example.com/cache/test.txt |
客户端收到 403 Forbidden | IP 白名单限制 / 文件权限不足 | 检查 Nginx allow/deny 指令;检查 /var/cache/gradle-remote 目录权限 |
PUT 请求返回 405 Not Allowed | Nginx 未启用 dav_methods | 确认配置中包含 dav_methods PUT DELETE MKCOL |
| HTTPS 连接失败 / SSL 错误 | 证书过期 / 证书与域名不匹配 | openssl s_client -connect cache.example.com:443 检查证书链 |
| 缓存条目未命中但文件存在 | 缓存键大小写 / 路径编码不一致 | 对比客户端日志中的 URL 和服务器文件路径; 确认 Nginx 没有对 URL 做 lowercase 转换 |
| 磁盘空间不足 | 缓存文件未清理 | du -sh /var/cache/gradle-remote;配置定时清理脚本或设置磁盘配额 |
curl -v 查看完整请求/响应头和状态码,能快速定位认证、TLS 握手或方法权限问题。
# 测试 GET 是否存在
curl -v -u gradle-cache:password \
https://cache.example.com/cache/ab3f8d2c1e...
# 测试 PUT 上传测试文件
echo "test" | curl -v -X PUT \
-u gradle-cache:password \
--data-binary @- \
https://cache.example.com/cache/test-key.txt
4.9 性能与稳定性优化
| 优化方向 | 具体措施 | 预期效果 |
|---|---|---|
| 缓存分层 | Nginx 启用 proxy_cache 将热缓存条目缓存在内存/SSD | 减少磁盘 I/O,提升热门缓存读取速度 3~5x |
| 连接复用 | 客户端启用 HTTP Keep-Alive(Gradle 默认) | 减少 TCP 握手开销,尤其适合大量小缓存条目的读写 |
| 限速与并发控制 | 使用 limit_rate 限制单个客户端带宽;limit_conn 限制并发连接数 | 防止单客户端耗尽服务器资源 |
| 磁盘 IO 优化 | 缓存目录挂载到 SSD 或 tmpfs(小缓存) | 降低写入延迟,提升缓存存储速度 |
| 监控与告警 | 暴露 Nginx stub_status 指标;集成 Prometheus + Grafana | 实时掌握缓存命中率、QPS、磁盘使用量 |
| 自动清理 | 使用 tmpreaper 或自建脚本删除超过 N 天未访问的文件 | 避免磁盘写满导致服务不可用 |
- HTTPS 会话缓存:
ssl_session_cache shared:SSL:10m;提升 TLS 握手性能; - Gzip 压缩:对缓存响应启用
gzip on(需注意缓存条目本身可能已是压缩格式); - 日志轮转:配置
logrotate按天切割访问日志,避免磁盘被日志填满; - 使用
sendfile和tcp_nopush提升静态文件传输效率。
4.10 部署检查清单
将远程缓存服务投入生产前,逐项确认以下要点:
- ✅ Nginx
dav_methods已正确启用,PUT/GET 返回预期状态码; - ✅ 认证机制生效,未授权请求返回
401; - ✅ HTTPS 证书有效,客户端无 TLS 警告;
- ✅ 缓存目录权限为
www-data:www-data,Nginx 工作进程可读写; - ✅ 防火墙仅开放 443 端口(或 8080 用于内部测试);
- ✅ 已配置磁盘空间监控和自动清理策略;
- ✅ 在 Gradle 客户端执行
--build-cache构建验证完整流程:PUT → 201 → GET → 200 → FROM-CACHE。