Skip to content

Pin container versions#16322

Merged
AlanCoding merged 3 commits into
ansible:develfrom
AlanCoding:pin_containers
Mar 4, 2026
Merged

Pin container versions#16322
AlanCoding merged 3 commits into
ansible:develfrom
AlanCoding:pin_containers

Conversation

@AlanCoding

@AlanCoding AlanCoding commented Mar 4, 2026

Copy link
Copy Markdown
Member
SUMMARY

We have been getting a lot of CI flake (errors pulling images), and I reproduced:

$ docker image pull mirror.gcr.io/library/redis:latest
latest: Pulling from library/redis
206356c42440: Downloading 
214ecf6e5c87: Downloading 
89b1b12d7109: Download complete 
f25f5c85b90d: Download complete 
ae77945b0371: Download complete 
4f4fb700ef54: Download complete 
141e1fc22067: Downloading 
unknown blob

Now, the theory is that when a new image (for :latest) is being uploaded, they don't add all the layers in exactly the right order. This leads to the tag referencing layers that do not yet exist (or are not ready to download yet). This might be expected if the update to the latest tag is still in progress, like, uploading while you are trying to download.

But past tags should never have this problem! They've been stable for months in most cases. So if the theory is correct, then using these tags should prevent this CI flake from happening again. Only one way to find out.

ISSUE TYPE
  • Bug, Docs Fix or other nominal change
COMPONENT NAME
  • API

Note

Low Risk
Low risk config-only change, but pinned versions may introduce runtime incompatibilities (e.g., Redis/Splunk/Grafana/Prometheus/pgbouncer behavior changes) that could affect local dev/CI containers.

Overview
Pins several tool service images in docker-compose.yml.j2 to explicit versions instead of :latest (Redis 7.4.8, Splunk 9.4.2, Prometheus v3.10.0, Grafana 12.3.4, pgbouncer 1.24.0) to stabilize pulls.

Adds inline upgrade notes for HAProxy and Splunk to document version-related config requirements.

Written by Cursor Bugbot for commit d6637c7. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • Chores
    • Pinned container images to specific releases (Redis, HAProxy, Splunk, Prometheus, Grafana, pgbouncer).
    • Added a Redis socket volume mapping to improve local socket access.
  • Documentation
    • Added inline upgrade/usage notes for several services, including a Splunk terms notice.

@coderabbitai

coderabbitai Bot commented Mar 4, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34b3255a-66cd-4804-8067-9890742583bd

📥 Commits

Reviewing files that changed from the base of the PR and between 7b410d8 and d6637c7.

📒 Files selected for processing (1)
  • tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2

📝 Walkthrough

Walkthrough

Update image tags in the docker-compose template and add a Redis socket volume plus inline explanatory comments; no control-flow or exported API changes.

Changes

Cohort / File(s) Summary
Docker Compose template
tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2
Pinned service images and adjusted related metadata: redis image -> mirror.gcr.io/library/redis:7.4.8 and added redis_socket_{{ container_postfix }}:/var/run/redis/:rw volume; splunk -> mirror.gcr.io/splunk/splunk:9.4.2 and added SPLUNK_GENERAL_TERMS note; prometheus -> mirror.gcr.io/prom/prometheus:v3.10.0; grafana -> mirror.gcr.io/grafana/grafana-enterprise:12.3.4; pgbouncer -> mirror.gcr.io/bitnami/pgbouncer:1.24.0; haproxy image left at mirror.gcr.io/library/haproxy:2.3 but received inline comments about upgrades. No control-flow changes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Pin container versions' directly matches the PR's primary objective of pinning container image versions to specific, stable tags rather than using :latest tags.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Comment thread tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2`:
- Line 103: Several Docker images in the docker-compose Jinja template are only
tag-pinned (e.g., mirror.gcr.io/library/redis:7.4.8,
mirror.gcr.io/library/haproxy:2.8.18, mirror.gcr.io/splunk/splunk:10.2.1-rhel9,
mirror.gcr.io/prom/prometheus:v3.10.0,
mirror.gcr.io/grafana/grafana-enterprise:12.3.4,
quay.io/sclorg/postgresql-15-c9s, mirror.gcr.io/bitnami/pgbouncer:1.24.0,
mirror.gcr.io/otel/opentelemetry-collector-contrib:0.88.0,
mirror.gcr.io/grafana/loki:2.9.5, hashicorp/vault:1.14) which makes deployments
non-deterministic; update the template (docker-compose.yml.j2) to append the
canonical `@sha256`:<digest> for each image reference so they are fully
digest-pinned (replace each plain tag like mirror.gcr.io/library/redis:7.4.8
with mirror.gcr.io/library/redis:7.4.8@sha256:<digest>), obtaining the correct
sha256 values from your image registry or Docker Hub and ensuring you update all
listed image identifiers in the template.
- Line 115: Update the HAProxy 2.8 incompatible settings: replace the deprecated
inline header usage in the backend/http health check (the `option httpchk` usage
referenced by the template) by moving headers out of the version string into
explicit http-check send-header/http-check expect lines (or use the canonical
`http-check send`/`http-check expect` sequence) so headers are not on the same
line as the version; and add an explicit global `no strict-limits` entry in the
global section to avoid startup failures when `maxconn 1000` exceeds system
limits. Ensure you update the template entries that define `option httpchk` and
the global block that sets `maxconn`/limits accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4e2282a4-054d-4362-af63-22db2839554b

📥 Commits

Reviewing files that changed from the base of the PR and between 57f9eb0 and 7b410d8.

📒 Files selected for processing (1)
  • tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2

{% endif %}
redis_{{ container_postfix }}:
image: mirror.gcr.io/library/redis:latest
image: mirror.gcr.io/library/redis:7.4.8

@coderabbitai coderabbitai Bot Mar 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2"

# Check if file exists
if [ ! -f "$FILE" ]; then
    echo "File not found: $FILE"
    exit 1
fi

echo "=== File exists, examining image references ==="
echo ""

# Extract lines 103, 115, 133, 148, 161, 202
echo "Line 103:"
sed -n '103p' "$FILE"

echo "Line 115:"
sed -n '115p' "$FILE"

echo "Line 133:"
sed -n '133p' "$FILE"

echo "Line 148:"
sed -n '148p' "$FILE"

echo "Line 161:"
sed -n '161p' "$FILE"

echo "Line 202:"
sed -n '202p' "$FILE"

echo ""
echo "=== All image references in file ==="
rg -n '^\s*image:\s*' "$FILE"

echo ""
echo "=== Image references WITHOUT `@sha256`: digest ==="
rg -n '^\s*image:\s*' "$FILE" | rg -v '@sha256:'

Repository: ansible/awx

Length of output: 2002


Add SHA256 digests to pin image versions for reproducibility and supply-chain security.

Image tags can be retargeted; use @sha256 digests for deterministic deployments. The following images are tag-pinned but lack digest pinning at lines 103, 115, 133, 148, 161, 175, 202, 223, 239, 286:

  • mirror.gcr.io/library/redis:7.4.8
  • mirror.gcr.io/library/haproxy:2.8.18
  • mirror.gcr.io/splunk/splunk:10.2.1-rhel9
  • mirror.gcr.io/prom/prometheus:v3.10.0
  • mirror.gcr.io/grafana/grafana-enterprise:12.3.4
  • quay.io/sclorg/postgresql-15-c9s
  • mirror.gcr.io/bitnami/pgbouncer:1.24.0
  • mirror.gcr.io/otel/opentelemetry-collector-contrib:0.88.0
  • mirror.gcr.io/grafana/loki:2.9.5
  • hashicorp/vault:1.14

Pin each with the corresponding @sha256:<digest> to strengthen reproducibility and supply-chain guarantees.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2`
at line 103, Several Docker images in the docker-compose Jinja template are only
tag-pinned (e.g., mirror.gcr.io/library/redis:7.4.8,
mirror.gcr.io/library/haproxy:2.8.18, mirror.gcr.io/splunk/splunk:10.2.1-rhel9,
mirror.gcr.io/prom/prometheus:v3.10.0,
mirror.gcr.io/grafana/grafana-enterprise:12.3.4,
quay.io/sclorg/postgresql-15-c9s, mirror.gcr.io/bitnami/pgbouncer:1.24.0,
mirror.gcr.io/otel/opentelemetry-collector-contrib:0.88.0,
mirror.gcr.io/grafana/loki:2.9.5, hashicorp/vault:1.14) which makes deployments
non-deterministic; update the template (docker-compose.yml.j2) to append the
canonical `@sha256`:<digest> for each image reference so they are fully
digest-pinned (replace each plain tag like mirror.gcr.io/library/redis:7.4.8
with mirror.gcr.io/library/redis:7.4.8@sha256:<digest>), obtaining the correct
sha256 values from your image registry or Docker Hub and ensuring you update all
listed image identifiers in the template.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's going a bit too far. Someone could file another issue for that. Diverges far out of current scope, and this doesn't make it any worse.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlanCoding, understood — tag pinning is already a meaningful improvement over :latest and this PR doesn't regress anything. Would you like me to open a follow-up GitHub issue to track the SHA256 digest pinning as a separate hardening step?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like me to open a follow-up GitHub issue to track the SHA256 digest pinning as a separate hardening step?

If you can do that, sure.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo ansible/awx \
  --title "Pin container images with SHA256 digests in docker-compose dev template" \
  --assignee AlanCoding \
  --body "## Summary

The docker-compose Jinja template at \`tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2\` currently pins container images to specific tags (improved in `#16322`), but image tags can be silently retargeted by maintainers. Pinning to \`@sha256:<digest>\` would make deployments fully deterministic and harden against supply-chain attacks.

## Images to update

| Image | Current tag |
|-------|-------------|
| \`mirror.gcr.io/library/redis\` | \`7.4.8\` |
| \`mirror.gcr.io/library/haproxy\` | \`2.3\` |
| \`mirror.gcr.io/splunk/splunk\` | \`9.4.2\` |
| \`mirror.gcr.io/prom/prometheus\` | \`v3.10.0\` |
| \`mirror.gcr.io/grafana/grafana-enterprise\` | \`12.3.4\` |
| \`quay.io/sclorg/postgresql-15-c9s\` | _(floating tag)_ |
| \`mirror.gcr.io/bitnami/pgbouncer\` | \`1.24.0\` |
| \`mirror.gcr.io/otel/opentelemetry-collector-contrib\` | \`0.88.0\` |
| \`mirror.gcr.io/grafana/loki\` | \`2.9.5\` |
| \`hashicorp/vault\` | \`1.14\` |

## Proposed change

Append \`@sha256:<digest>\` to each image reference, e.g.:
\`\`\`
mirror.gcr.io/library/redis:7.4.8@sha256:<digest>
\`\`\`

SHA256 digests can be retrieved via:
\`\`\`bash
docker manifest inspect mirror.gcr.io/library/redis:7.4.8 --verbose | jq '.[0].Descriptor.digest'
# or
skopeo inspect --format '{{.Digest}}' docker://mirror.gcr.io/library/redis:7.4.8
\`\`\`

## References

- PR that introduced tag pinning: https://github.com/ansible/awx/pull/16322
- Comment thread: https://github.com/ansible/awx/pull/16322#discussion_r2885172832
- Requested by: `@AlanCoding`"

Length of output: 43


@AlanCoding, done! The follow-up issue has been opened at #16324 — it lists all 10 images that need SHA256 digest pinning and includes instructions for retrieving the digests via docker manifest inspect or skopeo.

Comment thread tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 Outdated
@sonarqubecloud

sonarqubecloud Bot commented Mar 4, 2026

Copy link
Copy Markdown

@AlanCoding
AlanCoding merged commit 143d4ce into ansible:devel Mar 4, 2026
23 checks passed
@john-westcott-iv

Copy link
Copy Markdown
Member

My only thought on this is that you will want to occasionally update these pins so that you don't end up a version thats 10 years old. But that can be solved with process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants