Motivation#
Anyone managing production container environments knows the problem: images update quickly, security fixes are released constantly, and manually keeping up is tedious and error-prone.
By combining Renovate, GitHub Actions, and Portainer GitOps, this process can be fully automated:
- Renovate regularly checks the deployed container images and creates pull requests for updates.
- GitHub Actions handles the automation of Renovate runs.
- Portainer automatically deploys changes from the Git repository to the Docker environment.
This creates a clean GitOps workflow for Docker updates.
Configuring Renovate#
Renovate runs via a GitHub Action and monitors a docker-compose
repository.
A central config.js
file is required, which can look like this (anonymized version):
module.exports = {
platform: 'github',
token: process.env.RENOVATE_TOKEN,
gitAuthor: 'John Doe <john@example.com>',
username: 'exampleuser',
repositories: ['exampleuser/docker-compose'],
onboarding: false,
hostRules: [
{
hostType: 'docker',
matchHost: 'docker.io',
username: 'dockeruser',
password: String(process.env.DOCKER_HUB_PASSWORD || ''),
},
{
hostType: 'docker',
matchHost: 'ghcr.io',
username: 'exampleuser',
password: String(process.env.GHCR_TOKEN || ''),
}
],
};
👉 Important: Credentials (e.g., Docker Hub or GitHub Container Registry) must come exclusively from GitHub Secrets.
GitHub Workflow#
The corresponding workflow (.github/workflows/renovate.yml
) controls Renovate execution:
name: renovate
on:
workflow_dispatch: # manual trigger
schedule: # daily run at 12:00 UTC
- cron: '0 12 * * *'
push: # on push to main
branches:
- main
jobs:
renovate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run Renovate
uses: renovatebot/github-action@v43
with:
configurationFile: ${{ github.workspace }}/config.js
token: ${{ secrets.RENOVATE_TOKEN }}
env:
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
Optional Notification#
Optionally, you can add a notification step, e.g., via ntfy, whenever a Renovate pull request is open. Example:
- name: Check Open PRs and Notify
env:
GITHUB_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
NTFY_URL: ${{ secrets.NTFY_URL }}
NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }}
run: |
echo "Fetching open pull requests..."
OPEN_PRS=$(gh pr list \
--repo "flohoss/docker-compose" \
--state open \
--assignee "flohoss" \
--json number,title,url)
if [ "$(echo "$OPEN_PRS" | jq length)" -gt 0 ]; then
echo "Open PRs found, sending notifications..."
echo "$OPEN_PRS" | jq -c '.[]' | while read -r pr; do
NUMBER=$(echo "$pr" | jq -r '.number')
TITLE=$(echo "$pr" | jq -r '.title')
URL=$(echo "$pr" | jq -r '.url')
curl -s -X POST "$NTFY_URL" \
-H "Authorization: Bearer $NTFY_TOKEN" \
-H "X-Tags: twisted_rightwards_arrows" \
-H "X-Title: PR #${NUMBER} - ${TITLE}" \
-H "X-Actions: view, Open PR, ${URL}" \
-d "A Renovate PR needs your attention."
done
else
echo "No open pull requests found."
fi
Renovate Rules for Docker Images#
Through the renovate.json
file, you can set rules to determine which images are updated or restricted to certain versions:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"assignees": ["exampleuser"],
"packageRules": [
{
"matchDatasources": ["docker"],
"matchPackageNames": ["redis"],
"allowedVersions": "7.x"
},
{
"matchDatasources": ["docker"],
"matchPackageNames": ["postgres"],
"allowedVersions": "17.x"
},
{
"matchDatasources": ["docker"],
"pinDigests": true
}
]
}
Examples:
- Redis will only be updated within version 7.
- Postgres will only be updated within version 17.
- All images are digest-pinned for reproducible builds.
GitOps with Portainer#
Portainer can deploy stacks directly from a Git repository.
Example:
- Stack is based on
https://github.com/exampleuser/docker-compose
. - In Portainer, “Redeploy from Git repository” is enabled.
- Additionally, a polling interval is configured (e.g., every 5 minutes).
👉 Once Renovate merges a PR and updates the compose.yml
, Portainer automatically pulls the changes and redeploys the stack.
Result:
- No manual intervention for container updates.
- All changes are versioned and traceable via Git.
- Portainer ensures automated deployment in the Docker environment.
Conclusion#
Combining Renovate + GitHub Actions + Portainer GitOps creates a lean and reliable workflow for automated Docker updates:
- PR-based updates with full transparency
- Configurable update rules (e.g., specific major versions only)
- Automatic rollout in the runtime environment
This saves time, reduces risk, and maintains full control. 🚀