30.2 GitRepository and HelmRepository Sources
Right, let’s talk about where Flux gets its marching orders from. You’ve told it to deploy your fancy app, but Flux, being the pedantic but brilliant robot it is, refuses to take your word for it. It needs to see things in writing. In Git. This is where GitRepository and HelmRepository come in—they are Flux’s primary sources for truth, the well from which it draws all its manifests and charts.
Think of these resources as Flux’s personal librarians. You point them at a section of the library (a repo, a Helm chart repository), and they go off, fetch the latest editions of the books you asked for, and bring them back to the cluster. Without them, Flux just sits there, useless and unemployed.
The GitRepository: Your Manifest Supermarket
A GitRepository is exactly what it sounds like: it points Flux at a git repository containing your YAML manifests, Kustomize overlays, or even plain JSON. This is the bread and butter of GitOps. You define one by telling it the URL, the branch, and any other fetch instructions. Here’s a basic example that watches the main branch of a repo:
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: my-app-repo
namespace: flux-system
spec:
interval: 1m0s
url: https://github.com/your-org/your-app-manifests
ref:
branch: main
The interval is crucial. This is how often Flux says, “Hey, did anything change over there?” One minute might be aggressive for production; you might use 5m or more. This is your sync loop, the heartbeat of your GitOps process.
But what if your manifests aren’t at the root? Or you only want to watch a specific subdirectory? That’s where the spec.path field comes in. It’s a common “gotcha” to forget this and wonder why Flux is deploying everything in the repo, including the docs folder you used for that one meeting.
spec:
interval: 5m0s
url: https://github.com/your-org/your-monorepo
ref:
branch: staging
path: ./kubernetes/apps/important-service
Authentication: Because Nothing is Free
Unless you’re hosting your repos on a public read-only endpoint (you’re not, are you?), you’ll need to give Flux the keys to the castle. This is where secrets come in. You’ll create a Kubernetes Secret containing an SSH private key or a basic auth token and reference it in the GitRepository. The most common pitfall here is botching the secret format. Flux is picky. For an SSH key, it expects the key to be under the identity key in the secret.
First, create the secret from your private key:
kubectl create secret generic flux-ssh-key \
--namespace=flux-system \
--from-file=identity=./.ssh/id_rsa
Then, tell your GitRepository to use it:
spec:
url: git@github.com:your-org/your-private-repo.git
secretRef:
name: flux-ssh-key
Notice the URL changed to the SSH format. This trips up everyone. If you’re using an HTTPS URL, you need a username and password (usually a token) in your secret, not an SSH key. Choose one and stick with it.
The HelmRepository: Your Chart Warehouse
While a GitRepository fetches raw YAML, a HelmRepository points Flux at a Helm chart repository. This is for when you’ve decided you enjoy templating languages and want to deploy things the way Helm intended. It could be a remote repo like Bitnami’s or a local one you’ve hosted yourself.
Defining one is straightforward. You give it a URL and an interval, just like the Git librarian.
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: bitnami
namespace: flux-system
spec:
interval: 30m0s
url: https://charts.bitnami.com/bitnami
The interval here can usually be longer than for a GitRepository. Your app code might change every hour, but how often is the Redis chart actually updated? Probably not every minute.
The Secret Sauce: Combining Them with HelmReleases
Here’s where the magic—and occasional confusion—happens. These Source resources don’t do anything by themselves. They are sources of truth, not actors. To actually deploy a Helm chart, you need a HelmRelease that references them.
Your HelmRelease says, “Hey, use the charts from that HelmRepository named ‘bitnami’ I defined earlier, and specifically, grab the ‘redis’ chart from it.” This separation of concerns is what makes Flux so powerful and declarative. The chart source is defined once and can be used by countless HelmReleases.
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: my-redis
namespace: apps
spec:
interval: 5m0s
chart:
spec:
chart: redis
version: "17.0.0" # Pro-tip: Pin your versions. Don't be brave.
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
The key field is sourceRef. It’s the formal introduction between your HelmRelease and your HelmRepository. It must match the name and namespace exactly. This linking is a classic point of failure—get the namespace wrong, and Flux will just stare at you blankly, wondering what you’re talking about. It won’t yell, it’ll just sit in silence, its Ready condition forever stuck on False. Always check your references. It’s always the references.