Fleet, Rancher’s GitOps engine, lets you manage configurations across thousands of Kubernetes clusters from a single source of truth: Git.
Let’s see it in action. Imagine you have a fleet.yaml file in your Git repository that looks like this:
# fleet.yaml
defaults:
image: rancher/fleet-agent:v0.3.8
# Define a bundle of resources to be deployed
bundles:
- name: base-app
artifacts:
- image: my-docker-repo/my-app:latest
name: app.yaml
- image: my-docker-repo/my-db:latest
name: db.yaml
# Define target clusters for the bundles
targets:
- clusterSelector:
matchLabels:
environment: production
bundle: base-app
- clusterSelector:
matchLabels:
environment: staging
bundle: base-app
This fleet.yaml is the core. It declares a defaults section for images, which is super handy. Then, it defines bundles. A bundle is a collection of Kubernetes manifests that Fleet will deploy. Here, base-app includes two artifacts, app.yaml and db.yaml, with specific container images. Finally, targets dictate where these bundles go. The clusterSelector uses Kubernetes labels to pick out clusters. So, any cluster labeled environment: production or environment: staging will get the base-app bundle.
Fleet works by having a fleet-agent running in each managed cluster. This agent constantly watches a Git repository. When it detects changes in the fleet.yaml or the referenced artifact files (like app.yaml), it pulls those changes and applies them to its local Kubernetes cluster. It’s a declarative system: you declare the desired state in Git, and Fleet makes it happen.
The true power comes from scale. You don’t manually update thousands of clusters. You update one Git repo. Fleet handles the distribution. This model is robust because Git is the single source of truth. If a cluster goes down, or you need to spin up a new one, GitOps ensures it will eventually match the desired state defined in your repository.
The clusterSelector is a key lever. You can get granular. Want to deploy a specific version of an app only to clusters in the us-east-1 region? Add a region: us-east-1 label to those clusters and use that in your clusterSelector. You can also use matchExpressions for more complex logic, like NotIn or Exists.
Think about managing secrets. You can use tools like Sealed Secrets or external secret operators. Fleet can deploy the operator, and then you can define a bundle that deploys your sealed secrets, targeting specific clusters. The fleet-agent pulls the sealed secret, and the operator on the cluster decrypts it. This keeps your sensitive data out of plain text in Git, while still leveraging GitOps for deployment.
The fleet-agent itself is managed by Fleet. You define its version in the defaults.image field of your fleet.yaml. When you update this version, Fleet will roll out the new agent image to all managed clusters. This means you can update your entire fleet’s agent version with a single commit.
One thing people often overlook is the reconciliation loop. Fleet doesn’t just "apply" changes once. The fleet-agent continuously monitors the deployed resources against the state defined in Git. If someone manually deletes a resource (like a Deployment) from a managed cluster, Fleet will detect the drift and re-apply the resource from Git. This continuous reconciliation is what makes GitOps resilient.
The next step is understanding how to handle different environments (dev, staging, prod) with Git branches and how to manage complex application dependencies across bundles.