Thumbnail image

Kubernetes Home Lab in 2025: Part 2 - Automated Dependency Updates

Last time, we set up Cilium and Flux to enable networking and GitOps for our Kubernetes cluster. In this post, we will add automated dependency updates to it.

Dependency Management

Notice, in our Cilium configuration, we referenced the desired version of the Cilium Helm chart using a specific tag.

sourceRef:
    kind: HelmRepository
    name: cilium
version: 1.16.5

Many ecosystems allow you to express version constraints, relying on some sort of structured versioning schema, such as semantic versioning. For example, npm supports ~1.2.3 to allow patch updates, i.e., all updates <1.3.0, or even ^1.2.3 to allow minor updates, i.e., all updates <2.0.0.

This seems like a great quality-of-life improvement, until you debug one issue, then realize a simultaneous dependency update introduced a regression. Therefore, always pin your dependencies to a specific version and introduce upgrades intentionally. This is not only true for reproducible builds, but also for our infrastructure configuration.

Tangent: Branches, Tags and Commit Hashes

Everyone knows that a branch name is a mutable reference, meaning its content changes as the branch is updated. The contract is pretty clear: the branch is expected to change over time, but I get the updates as soon as they are available.

A lesser known fact is that a tag is also a mutable reference. The maintainer of a repository (or a malicious attacker) can delete a tag and create a new one with the same name, effectively changing the content of the release. This mechanism is used a lot in the GitHub Actions ecosystem to enable automatic patch and minor version upgrades, e.g., implemented in the checkout action.

The only way to avoid this is to reference a specific commit or content hash, a true immutable reference. This guarantees that the content will always be the same, even if the tag is deleted. Sadly, this is not fully supported in all ecosystems. An open issue exists in the Flux project to support this, so we have to make do using tags.

Renovate

So stability is great, but I’m not a fan of creating daily pull requests to update dependencies. Thankfully, lots of folks agree and wrote tools that can help us with this.

One such tool is Renovate. It automatically creates pull requests to update the dependencies of a project, and supports a lot of different package managers. Actually, over nine thousa…, okay over ninety, still impressive! Including Flux and Helm.

Installation

Renovate is available as a GitHub App and can be installed directly from the GitHub UI.

After hitting the install button, we need to allow Renovate access to the repositories we want to receive updates for:

Renovate repository access.

Renovate repository access.

Configuration

Renovate is configured using a renovate.json file, checked into the same repository. Let’s take a look at the configuration:

{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "extends": [
      "config:base",
      ":preserveSemverRanges"
    ],
    "addLabels": [
      "dependencies"
    ],
    "includePaths": [
      "k8s/flux/**"
    ],
    "packageRules": [
      {
        "description": "Automerge patch and minor updates for Helm charts",
        "matchDatasources": ["helm"],
        "groupName": "helm-charts"
      }
    ]
  }

Extends enables us to build a configuration by adopting shared config presets. We also add the dependencies label to all pull requests, to make it easier to find them. We restrict Renovate to only update dependencies in the k8s/flux directory, since I have a lot of other stuff in the same repository. Lastly, we group all Helm chart updates together, to reduce the number of pull requests we have to review.

Note
In case Renovate ever fails, e.g., due to a broken configuration, check out the developer dashboard for more details. It includes logs for each backend invocation of Renovate.

Dashboard

Once configured, Renovate will create a dashboard using a persistent GitHub issue to track the status of all discovered dependencies and their updates.

Renovate dashboard.

Renovate dashboard.

Finally, as projects are updated, Renovate will create pull requests to update the dependencies.

Renovate pull request.

Renovate pull request.

Once the pull request is merged, Flux will automatically update the dependencies in the cluster.

$ flux get helmreleases -n kube-system --watch
NAME    REVISION  READY   MESSAGE
cilium  1.16.5    True    Helm upgrade succeeded for release kube-system/cilium.v2 with chart cilium@1.16.5
cilium  1.16.5    False   HelmChart 'kube-system/kube-system-cilium' is not ready: latest generation of object has not been reconciled
cilium  1.16.5    Unknown Running 'upgrade' action with timeout of 5m0s
cilium  1.17.1    True    Helm upgrade succeeded for release kube-system/cilium.v3 with chart cilium@1.17.1

Conclusion

In this post, we added automated dependency updates to our Kubernetes home lab. We use Renovate to automate pull requests to update the dependencies of our projects, and Flux to apply the changes to our cluster.

In the next post, we will deploy a Kubernetes Ingress Controller, to enable external access to our applications.