Automating Helm Chart Updates in My Home Lab with Renovate, GitLab CI, and ArgoCD
On this page Table of Contents
Keeping Helm chart dependencies up to date in a home lab can be tedious. You deploy a chart, pin a version, and months later you’re running something outdated without even realizing it. In this post, I’ll walk through how I set up Renovate to automatically detect outdated Helm charts in my GitOps repository and open merge requests on my self-hosted GitLab instance.
The Setup
My home lab runs Kubernetes with ArgoCD managing deployments via a GitOps approach. The repository structure follows an app-of-apps pattern using ArgoCD ApplicationSets:
argo/
├── apps/
│ ├── alloy/
│ │ ├── Chart.yaml
│ │ └── values.yaml
│ ├── beyla/
│ ├── fluentbit/
│ ├── gitlab-agent/
│ ├── gitlab-runner/
│ ├── kube-state-metrics/
│ ├── kubernetes-dashboard/
│ ├── metrics-server/
│ └── openebs/
├── applicationset.yaml
└── renovate.json
Each app directory is a wrapper Helm chart – a minimal Chart.yaml that declares a dependency on an upstream chart from an external repository. For example, here’s what apps/kube-state-metrics/Chart.yaml looks like:
apiVersion: v2
name: kube-state-metrics
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "2.6.0"
dependencies:
- name: kube-state-metrics
version: 4.21.0
repository: https://prometheus-community.github.io/helm-charts
The values.yaml file alongside it contains any configuration overrides for my environment.
An ArgoCD ApplicationSet watches the apps/ directory and automatically creates an Application for each subdirectory:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://git.aganet.gr/georgios/argo.git
revision: master
directories:
- path: apps/*
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://git.aganet.gr/georgios/argo.git
targetRevision: master
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
retry:
limit: 3
backoff:
duration: 30s
maxDuration: 3m
factor: 2
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
This means any change merged to master is automatically synced to the cluster. The missing piece was: who bumps the versions in Chart.yaml?
The Solution: Renovate
Renovate is a universal dependency update tool that supports a wide range of package managers and languages – from npm and pip to Docker, Terraform, and Helm. In our case, it natively understands Helm Chart.yaml files, queries the upstream repositories for newer versions, and opens merge requests with the version bumps.
Step 1: Add the Renovate Configuration
I added a renovate.json to the repository root:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"includePaths": ["apps/**"],
"prHourlyLimit": 20
}
Key settings:
includePaths: Tells Renovate to only scan theapps/directory. I have other directories (apps2/… etc, standalone charts) that I don’t want Renovate to touch.prHourlyLimit: The default is 2 MRs per hour, which is conservative. I bumped it to 20 so all updates are created in a single run.
Step 2: Create the GitLab CI Pipeline
Since I’m running a self-hosted GitLab, I can’t use the Renovate GitHub App. Instead, I run Renovate as a CI job triggered on a schedule.
My GitLab runner uses the shell executor (not Docker), so I use npx to run Renovate directly:
renovate:
stage: build
tags:
- shell-host
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
variables:
RENOVATE_PLATFORM: gitlab
RENOVATE_ENDPOINT: ${CI_API_V4_URL}
RENOVATE_TOKEN: ${RENOVATE_TOKEN}
RENOVATE_REPOSITORIES: ${CI_PROJECT_PATH}
LOG_LEVEL: debug
script:
- npx renovate
A few notes:
- The job only runs on scheduled pipelines, not on every push.
CI_API_V4_URLandCI_PROJECT_PATHare predefined GitLab CI variables – no hardcoding needed.RENOVATE_TOKENis a Personal Access Token withapiscope, stored as a CI/CD variable in the project settings.- I keep
LOG_LEVEL: debugenabled since it’s very useful for troubleshooting.
Step 3: Create a Pipeline Schedule
In GitLab, go to Build > Pipeline schedules and create a new schedule. I run mine daily, but weekly works fine for a home lab.
Step 4: Create the Personal Access Token
This was the trickiest part. To create the token:
- Go to your GitLab profile Edit profile > Access Tokens
- Create a new token with the
apiscope - Add it as a CI/CD variable named
RENOVATE_TOKENin your project settings
The Results
On the first run, Renovate scanned all 9 charts in apps/ and detected updates for almost everything:
| Chart | Current | Available |
|---|---|---|
| alloy | 0.11.0 | 0.12.6 |
| beyla | 1.7.2 | 1.11.0 |
| fluent-bit | 0.50.0 | 0.55.0 |
| gitlab-agent | 2.13.0 | 2.23.0 |
| gitlab-runner | 0.75.0 | 0.85.0 |
| kube-state-metrics | 4.21.0 | 4.32.0 |
| metrics-server | 3.12.2 | 3.13.0 |
| openebs | 4.2.0 | 4.4.0 |
For charts with major version bumps (like alloy and kube-state-metrics), Renovate creates separate MRs for the minor and major updates, giving you the choice to stay on your current major version or upgrade.

Surprise Discovery: kubernetes-dashboard is Dead
Renovate also surfaced something I hadn’t noticed – the kubernetes-dashboard Helm repository is gone:
GET https://kubernetes.github.io/dashboard/index.yaml = 404
Failed to look up helm package kubernetes-dashboard
The kubernetes-dashboard project was archived in January 2026. The Helm repo no longer serves index.yaml, so ArgoCD can’t sync it either. The recommended replacement is Headlamp, now under Kubernetes sig-ui.
This is one of the underrated benefits of Renovate – it doesn’t just find updates, it also alerts you when a dependency is no longer available.
The Full GitOps Loop
With everything in place, the workflow is:
- Renovate runs on schedule via GitLab CI
- It detects outdated Helm chart versions in
apps/ - It opens merge requests with the version bumps
- I review and merge the MR
- ArgoCD detects the change in the git repository
- ArgoCD syncs the updated chart to the cluster
No manual version checking. No forgetting to update. Just merge requests waiting for my review.
Tips and Gotchas
- Hourly PR limit: Renovate defaults to 2 MRs per hour. If you have many charts, bump
prHourlyLimitor you’ll be waiting multiple runs for all MRs to appear. - Debug logging: Keep
LOG_LEVEL: debugenabled, at least initially. The output is verbose but invaluable when something isn’t working as expected. - ServerSideApply: If your Helm charts include large CRDs, add
ServerSideApply=trueto your ArgoCD sync options. This avoids themetadata.annotations too longerror that can happen with standard apply.
Conclusion
Setting up Renovate for a home lab GitOps repository took about an hour, and most of that was debugging the authentication token. The actual configuration is just two files: a renovate.json and a CI job in .gitlab-ci.yml. Now my Helm charts stay current with zero manual effort – exactly the kind of automation a home lab should have.
Comments