feat: Add regex managers for Docker container versioning in Terraform
Some checks failed
Code Quality & Security Scan / TFLint (push) Successful in 26s
Code Quality & Security Scan / Terraform Destroy (push) Has been skipped
Code Quality & Security Scan / Tfsec Security Scan (push) Successful in 33s
Code Quality & Security Scan / Checkov Security Scan (push) Successful in 39s
Code Quality & Security Scan / Terraform Validate (push) Failing after 32s
Code Quality & Security Scan / SonarQube Scan (push) Has been skipped
Code Quality & Security Scan / Terraform Plan (push) Has been skipped
Code Quality & Security Scan / Terraform Apply (push) Has been skipped

Add support for Renovate to detect and update Docker image versions
defined in Terraform files using annotation comments.

Changes:
- Add 3 regex managers to config.js.tpl for different annotation patterns:
  - Basic: # renovate: datasource=docker
  - With versioning: # renovate: datasource=docker versioning=semver
  - Separate variable: # renovate: datasource=docker depName=redis
- Update README.md with comprehensive Docker container annotation docs
- Update QUICKSTART.md with Terraform Docker container examples
- Add example-annotated-containers.tf with usage patterns

This enables Renovate to automatically create PRs when Docker images
used in Terraform container definitions have updates available.
This commit is contained in:
Patrick de Ruiter 2025-11-28 04:09:14 +01:00
parent 77e6102b0c
commit 16bb56c454
Signed by: pderuiter
GPG Key ID: 5EBA7F21CF583321
4 changed files with 411 additions and 0 deletions

View File

@ -302,6 +302,37 @@ Add this to `renovate.json`:
} }
``` ```
### Terraform with Docker Containers
If you deploy Docker containers via Terraform and define image versions in your `.tf` files, Renovate can track those too!
**Add annotations to your Terraform code:**
```hcl
locals {
containers = {
redis = {
# renovate: datasource=docker
image = "redis:8.0.0"
# ... other settings
}
grafana = {
# renovate: datasource=docker
image = "grafana/grafana:11.2.0"
# ... other settings
}
}
}
```
The `# renovate: datasource=docker` comment tells Renovate to:
1. Parse the `image` value on the next line
2. Extract the image name and version
3. Create PRs when updates are available
**See README.md** for more annotation patterns and examples.
## Useful Commands ## Useful Commands
```bash ```bash

113
README.md
View File

@ -370,6 +370,119 @@ For repositories with Terraform code:
} }
``` ```
### Docker Container Versioning in Terraform
This Renovate deployment includes **regex managers** that can detect and update Docker image versions defined in Terraform files. This is useful when you deploy Docker containers via Terraform and want Renovate to keep those images up to date.
#### How It Works
Add a special comment annotation above your `image` definition in your Terraform code. Renovate will then detect the Docker image and create PRs when updates are available.
#### Annotation Format
**Basic annotation** (combined image:tag format):
```hcl
locals {
containers = {
redis = {
# renovate: datasource=docker
image = "docker.io/library/redis:8"
# ... other settings
}
traefik = {
# renovate: datasource=docker
image = "traefik:3.1.2"
ports = [80, 443]
}
grafana = {
# renovate: datasource=docker
image = "grafana/grafana:11.2.0"
# ... other settings
}
}
}
```
**With explicit versioning scheme** (for non-standard versioning):
```hcl
vault = {
# renovate: datasource=docker versioning=semver
image = "hashicorp/vault:1.17.3"
}
minio = {
# renovate: datasource=docker versioning=regex
image = "minio/minio:RELEASE.2024-08-29T01-40-52Z"
}
```
**Separate version variable**:
```hcl
# renovate: datasource=docker depName=redis
variable "redis_version" {
type = string
default = "8.0.0"
}
```
#### Supported Patterns
| Pattern | Example | Use Case |
|---------|---------|----------|
| Combined image:tag | `image = "nginx:1.25.0"` | Most common - image and version in one string |
| With registry prefix | `image = "docker.io/library/redis:8"` | Official images with full path |
| Custom versioning | `versioning=semver` | Images with non-standard version formats |
| Separate variable | `depName=redis` + `version = "8.0.0"` | When image and version are split |
#### Example: Complete Container Definition
```hcl
# Paperless-NGX with Redis broker
locals {
services = {
paperless-broker = {
# renovate: datasource=docker
image = "docker.io/library/redis:8"
healthcheck = {
test = ["CMD", "redis-cli", "ping"]
interval = "30s"
timeout = "5s"
retries = 3
}
volumes = {
"paperless-redisdata" = "/data"
}
networks = ["paperless-backend-network"]
container_ports = ["6379"]
}
paperless-webserver = {
# renovate: datasource=docker
image = "ghcr.io/paperless-ngx/paperless-ngx:2.12.1"
networks = ["paperless-backend-network", "traefik_network"]
use_traefik = true
container_ports = ["8000"]
}
}
}
```
When Renovate scans this repository, it will:
1. Detect `redis:8` and create PRs for Redis updates
2. Detect `paperless-ngx:2.12.1` and create PRs for Paperless-NGX updates
3. Continue to update Terraform providers and modules as usual
An example annotated container file is provided in `files/example-annotated-containers.tf`.
## Variables ## Variables
### Terraform Variables ### Terraform Variables

View File

@ -25,5 +25,46 @@ module.exports = {
// Additional recommended settings for Gitea // Additional recommended settings for Gitea
requireConfig: 'optional', requireConfig: 'optional',
// Regex managers for custom version detection
// This enables Renovate to detect Docker image versions in Terraform files
// when annotated with: # renovate: datasource=docker
regexManagers: [
{
// Match Docker image versions in Terraform files (.tf and .tfvars)
// Requires annotation comment above the image line
// Example:
// # renovate: datasource=docker
// image = "nginx:1.25.0"
fileMatch: ['\\.tf$', '\\.tfvars$'],
matchStrings: [
'#\\s*renovate:\\s*datasource=docker\\s*\\n\\s*image\\s*=\\s*"(?<depName>[^:"]+):(?<currentValue>[^"]+)"'
],
datasourceTemplate: 'docker'
},
{
// Match Docker image versions with explicit versioning scheme
// Example:
// # renovate: datasource=docker versioning=semver
// image = "hashicorp/vault:1.17.3"
fileMatch: ['\\.tf$', '\\.tfvars$'],
matchStrings: [
'#\\s*renovate:\\s*datasource=docker\\s+versioning=(?<versioning>\\S+)\\s*\\n\\s*image\\s*=\\s*"(?<depName>[^:"]+):(?<currentValue>[^"]+)"'
],
datasourceTemplate: 'docker',
versioningTemplate: '{{versioning}}'
},
{
// Match separate image and version/tag variables
// Example:
// # renovate: datasource=docker depName=redis
// version = "8.0.0"
fileMatch: ['\\.tf$', '\\.tfvars$'],
matchStrings: [
'#\\s*renovate:\\s*datasource=(?<datasource>\\S+)\\s+depName=(?<depName>\\S+)\\s*\\n.*?(?:version|tag)\\s*=\\s*"(?<currentValue>[^"]+)"'
],
datasourceTemplate: '{{datasource}}'
}
],
// Repository-level settings can be overridden in renovate.json files // Repository-level settings can be overridden in renovate.json files
}; };

View File

@ -0,0 +1,226 @@
# Example: Annotated Container Definitions for Renovate
#
# This file demonstrates how to annotate Docker container definitions
# in Terraform so that Renovate can detect and update image versions.
#
# Add the comment "# renovate: datasource=docker" above the image line
# to enable automatic version detection and updates.
# =============================================================================
# Basic Pattern: Combined image:tag format
# =============================================================================
# This is the most common pattern where image name and tag are in one string.
locals {
services = {
# Basic Redis container
redis = {
# renovate: datasource=docker
image = "redis:8.0.0"
container_ports = ["6379"]
networks = ["backend-network"]
}
# Container with full registry path
postgres = {
# renovate: datasource=docker
image = "docker.io/library/postgres:16.4-alpine"
container_ports = ["5432"]
networks = ["backend-network"]
volumes = {
"postgres-data" = "/var/lib/postgresql/data"
}
}
# Third-party image from Docker Hub
grafana = {
# renovate: datasource=docker
image = "grafana/grafana:11.2.0"
container_ports = ["3000"]
networks = ["traefik_network", "monitoring-network"]
use_traefik = true
}
# Image from GitHub Container Registry
paperless = {
# renovate: datasource=docker
image = "ghcr.io/paperless-ngx/paperless-ngx:2.12.1"
container_ports = ["8000"]
networks = ["traefik_network"]
use_traefik = true
}
}
}
# =============================================================================
# Advanced Pattern: With explicit versioning scheme
# =============================================================================
# Use this when the image has a non-standard version format.
locals {
advanced_services = {
# HashiCorp images use semver
vault = {
# renovate: datasource=docker versioning=semver
image = "hashicorp/vault:1.17.3"
container_ports = ["8200"]
networks = ["traefik_network"]
}
# MinIO uses date-based releases
minio = {
# renovate: datasource=docker versioning=regex:^RELEASE\.(?<major>\d{4})-(?<minor>\d{2})-(?<patch>\d{2})T\d{2}-\d{2}-\d{2}Z$
image = "minio/minio:RELEASE.2024-08-29T01-40-52Z"
container_ports = ["9000", "9001"]
networks = ["traefik_network"]
}
}
}
# =============================================================================
# Alternative Pattern: Separate version variable
# =============================================================================
# Use this when you prefer to define versions as separate variables.
# renovate: datasource=docker depName=traefik
variable "traefik_version" {
description = "Version of Traefik to deploy"
type = string
default = "3.1.2"
}
# renovate: datasource=docker depName=redis
variable "redis_version" {
description = "Version of Redis to deploy"
type = string
default = "8.0.0"
}
# renovate: datasource=docker depName=grafana/grafana
variable "grafana_version" {
description = "Version of Grafana to deploy"
type = string
default = "11.2.0"
}
# Usage example with separate variables
locals {
versioned_services = {
traefik = {
image = "traefik:${var.traefik_version}"
container_ports = ["80", "443", "8080"]
networks = ["traefik_network"]
}
}
}
# =============================================================================
# Complete Example: Production-like container object
# =============================================================================
# This shows a realistic container definition with all common settings.
locals {
production_services = {
# Paperless-NGX Document Management System
paperless-webserver = {
# renovate: datasource=docker
image = "ghcr.io/paperless-ngx/paperless-ngx:2.12.1"
healthcheck = {
test = ["CMD", "curl", "-f", "http://localhost:8000"]
interval = "30s"
timeout = "10s"
retries = 5
start_period = "60s"
}
vault_env_path = "secret/paperless-ngx"
environment = "prod"
replicas = 1
volumes = {
"paperless-data" = "/usr/src/paperless/data"
"paperless-media" = "/usr/src/paperless/media"
"paperless-export" = "/usr/src/paperless/export"
"paperless-consume" = "/usr/src/paperless/consume"
}
host_ports = []
container_ports = ["8000"]
networks = ["paperless-backend-network", "traefik_network"]
use_traefik = true
is_swarm_service = false
consul_service = true
access_docker_sock = false
create_cname_record = true
}
# Redis broker for Paperless
paperless-broker = {
# renovate: datasource=docker
image = "docker.io/library/redis:8"
healthcheck = {
test = ["CMD", "redis-cli", "ping"]
interval = "30s"
timeout = "5s"
retries = 3
start_period = "10s"
}
vault_env_path = "secret/paperless-ngx"
environment = "prod"
replicas = 1
volumes = {
"paperless-redisdata" = "/data"
}
host_ports = []
container_ports = ["6379"]
networks = ["paperless-backend-network"]
use_traefik = false
is_swarm_service = false
consul_service = false
access_docker_sock = false
create_cname_record = false
}
# PostgreSQL database for Paperless
paperless-db = {
# renovate: datasource=docker
image = "docker.io/library/postgres:16.4-alpine"
healthcheck = {
test = ["CMD-SHELL", "pg_isready -U paperless"]
interval = "30s"
timeout = "5s"
retries = 3
start_period = "30s"
}
vault_env_path = "secret/paperless-ngx"
environment = "prod"
replicas = 1
volumes = {
"paperless-pgdata" = "/var/lib/postgresql/data"
}
host_ports = []
container_ports = ["5432"]
networks = ["paperless-backend-network"]
use_traefik = false
is_swarm_service = false
consul_service = false
access_docker_sock = false
create_cname_record = false
}
}
}