All checks were successful
Update README with ADR Index / update-readme (push) Successful in 6s
- ADR-0056: custom voice support in tts-module (VoiceRegistry) - ADR-0057: shared Renovate preset rollout to all app repos - Update ADR-0013: add tts-module and stt-module to CI table - Update ADR-0036: cross-reference ADR-0057
9.0 KiB
9.0 KiB
Automated Dependency Updates with Renovate
- Status: accepted
- Date: 2026-02-05
- Deciders: Billy
- Technical Story: Automate dependency updates across all homelab repositories
Context and Problem Statement
The homelab consists of 20+ repositories containing:
- Kubernetes manifests with container image references
- Helm chart versions
- Python/Go dependencies
- GitHub Actions / Gitea Actions workflow versions
Manually tracking and updating dependencies is:
- Time-consuming
- Error-prone
- Often neglected until security issues arise
How do we automate dependency updates while maintaining control over what gets updated?
Decision Drivers
- Automated detection of outdated dependencies
- PR-based update workflow for review
- Support for Kubernetes manifests, Helm, Python, Go, Docker
- Self-hosted on existing infrastructure
- Configurable grouping and scheduling
- Security update prioritization
Considered Options
- Renovate (self-hosted)
- Dependabot (GitHub-native)
- Manual updates with version scripts
- Flux image automation
Decision Outcome
Chosen option: Option 1 - Renovate (self-hosted)
Renovate runs as a CronJob in the cluster, scanning all repositories in the Gitea organization and creating PRs for outdated dependencies. It supports more package managers than Dependabot and works with Gitea.
Positive Consequences
- Comprehensive manager support (40+ package managers)
- Works with self-hosted Gitea
- Configurable grouping (batch minor updates)
- Auto-merge for patch/minor updates
- Dashboard for update overview
- Reusable preset configurations
Negative Consequences
- Additional CronJob to maintain
- Configuration complexity
- API token management for Gitea access
Architecture
┌───────────────────────────────────────────────────────────────────┐
│ Renovate CronJob │
│ (ci-cd namespace) │
│ │
│ Schedule: Every 8 hours (0 */8 * * *) │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Renovate Container │ │
│ │ │ │
│ │ 1. Fetch repositories from Gitea org │ │
│ │ 2. Scan each repo for dependencies │ │
│ │ 3. Compare versions with upstream registries │ │
│ │ 4. Create/update PRs for outdated deps │ │
│ │ 5. Auto-merge approved patches │ │
│ └────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────┐
│ Gitea │
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ homelab-k8s2 │ │ chat-handler │ │ kuberay-images│ │
│ │ │ │ │ │ │ │
│ │ PR: Update │ │ PR: Update │ │ PR: Update │ │
│ │ flux to 2.5.0 │ │ httpx to 0.28 │ │ ROCm to 6.4 │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└───────────────────────────────────────────────────────────────────┘
Configuration
CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: renovate
namespace: ci-cd
spec:
schedule: "0 */8 * * *" # Every 8 hours
jobTemplate:
spec:
template:
spec:
containers:
- name: renovate
image: renovate/renovate:39
env:
- name: RENOVATE_PLATFORM
value: "gitea"
- name: RENOVATE_ENDPOINT
value: "https://git.daviestechlabs.io/api/v1"
- name: RENOVATE_TOKEN
valueFrom:
secretKeyRef:
name: renovate-github-token
key: token
- name: RENOVATE_AUTODISCOVER
value: "true"
- name: RENOVATE_AUTODISCOVER_FILTER
value: "daviestechlabs/*"
restartPolicy: OnFailure
Repository Config (renovate.json)
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"group:allNonMajor",
":automergeMinor",
":automergePatch"
],
"kubernetes": {
"fileMatch": ["\\.ya?ml$"]
},
"packageRules": [
{
"matchManagers": ["helm-values", "helmv3"],
"groupName": "helm charts"
},
{
"matchPackagePatterns": ["^ghcr.io/"],
"groupName": "GHCR images"
},
{
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["major-update"]
}
],
"schedule": ["before 6am on monday"]
}
Supported Package Managers
| Manager | File Patterns | Examples |
|---|---|---|
| kubernetes | *.yaml, *.yml |
Container images in Deployments |
| helm | Chart.yaml, values.yaml |
Helm chart dependencies |
| helmv3 | HelmRelease CRDs | Flux HelmReleases |
| flux | Flux CRDs | GitRepository, OCIRepository |
| pip | requirements.txt, pyproject.toml |
Python packages |
| gomod | go.mod |
Go modules |
| dockerfile | Dockerfile* |
Base images |
| github-actions | .github/workflows/*.yml |
Action versions |
| gitea-actions | .gitea/workflows/*.yml |
Action versions |
Update Strategy
Auto-merge Enabled
| Update Type | Auto-merge | Delay |
|---|---|---|
| Patch (x.x.1 → x.x.2) | ✅ Yes | Immediate |
| Minor (x.1.x → x.2.x) | ✅ Yes | 3 days stabilization |
| Major (1.x.x → 2.x.x) | ❌ No | Manual review |
Grouping Strategy
| Group | Contents | Frequency |
|---|---|---|
all-non-major |
All patch + minor updates | Weekly (Monday) |
helm-charts |
All Helm chart updates | Weekly |
container-images |
Docker image updates | Weekly |
security |
CVE fixes | Immediate |
Security Updates
Renovate prioritizes security updates:
{
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
},
"packageRules": [
{
"matchCategories": ["security"],
"automerge": true,
"schedule": ["at any time"],
"prPriority": 10
}
]
}
Dashboard
Renovate creates a "Dependency Dashboard" issue in each repository:
## Dependency Dashboard
### Open PRs
- [ ] Update httpx to 0.28.1 (#42)
- [x] Update pillow to 11.0.0 (#41) - merged
### Pending Approval
- [ ] Major: Update pydantic to v2 (#40)
### Rate Limited
- fastapi (waiting for next schedule window)
Secrets
| Secret | Source | Purpose |
|---|---|---|
renovate-github-token |
Vault | Gitea API access |
renovate-dockerhub |
Vault | Docker Hub rate limits |
Monitoring
# Renovate job success rate
sum(kube_job_status_succeeded{job_name=~"renovate-.*"})
/
sum(kube_job_status_succeeded{job_name=~"renovate-.*"} + kube_job_status_failed{job_name=~"renovate-.*"})
Links
- Renovate Documentation
- Renovate Presets
- Gitea Platform Support
- Related: ADR-0013 - Gitea Actions for CI
- Related: ADR-0031 - Gitea CI/CD Strategy
- Extended by: ADR-0057 - Per-Repository Renovate Configurations