Gradle build cache on Kubernetes: plain manifests, no Helm chart yet
Run a shared build cache in your cluster with plain manifests: one Deployment, one volume, one Service. There is no Helm chart yet. It has not been through a beta on a production cluster, so treat it that way.
Is there a Helm chart?
Not yet. Today the supported way to deploy on Kubernetes is the plain manifests in the Kubernetes guide: a Secret, a volume claim, a Deployment and a Service. Copy them into one file and apply it with kubectl apply -f.
Run exactly one replica
Do not scale this out. The cache keeps its index in a database file that one process holds a lock on. A second pod on the same volume does not share the cache; it waits on the lock or fails to start. Two pods on different volumes give you two half-filled caches.
replicas: 1.- Update strategy
Recreate, not the default rolling update, so the new pod never starts while the old one holds the lock. - A volume claim with
ReadWriteOnce.
A cache is safe to lose for a moment. If it is down during a rollout, builds miss the cache and run slower, and nothing breaks. High availability across nodes is a paid-tier idea that is not built, so do not improvise it with two replicas.
Size it in Kubernetes terms
- Requests of about 100m CPU and 128Mi memory, and a memory limit of 512Mi.
- No CPU limit, on purpose. A CPU limit throttles instead of killing, and throttling a cache during a burst is the opposite of what you want.
- A node with 1 GB does not have 1 GB for you. The smallest practical node on managed Kubernetes is 2 GB.
- Disk is the real variable. Size the volume from the cache size cap plus some room. See server sizing.
Locked down by default
The manifests run as a non-root user with a read-only root file system, drop all capabilities, forbid privilege escalation, and use the runtime default seccomp profile. There is no privileged mode, no host networking and no host path. They satisfy the Pod Security restricted profile. The volume must be writable by user 65532, which is what the fsGroup setting is for.
Runners in the same cluster
If your CI runners already run in this cluster, including Jenkins agents, GitHub Actions runner controller and GitLab runners, you need no load balancer and no ingress. Point Gradle at the cluster-internal name, for example http://fscache.fscache-ns.svc.cluster.local/, with isAllowInsecureProtocol = true. Gradle requires that for plain http:// addresses. In our test with Gradle 9.8.0, only the literal 127.0.0.1 was let through without it. Here it is reasonable because the traffic never leaves the cluster network. See Jenkins and CI build cache.
Get the manifests
The four manifests (Secret, volume claim, Deployment, Service) and the steps to reach the cache from outside the cluster are in the Kubernetes guide on GitHub. Copy them into one file and apply it.
How we checked
We applied the guide's four manifests to a new kind cluster (Kubernetes in Docker) on a GitHub-hosted Linux machine, with FosterStack Cache 0.2.2. What we saw:
- A namespace that enforces the restricted Pod Security profile accepted all four with no warning, and the pod became ready.
- The running Deployment matched this page: one replica, Recreate, a ReadWriteOnce claim, user 65532, a read-only root file system, and the requests and memory limit above, with no CPU limit.
- It has no privileged mode, no host networking and no host path.
- The
/healthzcheck only says the process is up, not that the disk works. The next two items are what show the volume works. - We stored a key and deleted the pod. After Kubernetes replaced it, the key was still there.
- A Gradle build from outside the cluster, through the guide's
kubectl port-forward, restored from the cache, and the server's hit counter went up. - With two replicas, only one pod became ready. The other failed to start because it could not get the lock on the cache's index file.
- Keep the
FSCACHE_DATA_DIRsetting in the guide's Deployment; it points the cache at the mounted volume. We removed it as a test, and the pod did not become ready: it failed with a read-only file system error.
Not tested: a real cloud cluster, other storage classes, a cluster with more than one node, rollouts, the fsGroup requirement, the guide's load balancer, Gateway and Ingress examples, and the cluster-internal name. This was a test on a throwaway cluster, not a production trial. We used the guide at the v0.2.2 tag. The run and its log are public.