rios0rios0/pipelines
Change Docker build pipelines to just add the tag on the image instead of triggering the whole building process again with a different tag
Open
#230 opened on Dec 19, 2025
documentationenhancementhelp wanted
Repository metrics
- Stars
- (22 stars)
- PR merge metrics
- (Avg merge 8h 32m) (39 merged PRs in 30d)
Description
Summary
Problem: When a release tag is pushed we re-run the full Docker build pipeline that already ran on main producing :latest. This wastes CI time and resources because the image content is identical — we only need to add a release tag to the already-built image.
Goal: On tag events, fetch the :latest image produced by the main build, add the release tag, and push the new tag — do not rebuild.
Background
- Current flow:
mainpush → build imageregistry/org/image:latest→ push. Tag push → pipeline triggers full rebuild and pushesregistry/org/image:vX.Y.Z. - Desired flow:
mainpush → build and push:latest. Tag push → pull:latest, tag it as the release tag, push the new tag. - Benefits: faster releases, lower CI cost, consistent image content between
:latestand release tags, fewer build failures caused by rebuild nondeterminism.
Proposed Solution
- Add a lightweight pipeline that runs on
pushof tags only. - That pipeline should:
- Authenticate to the container registry.
- Pull the
:latestimage for the same repository. - Tag the pulled image with the release tag (the git tag name).
- Push the new tag to the registry.
- Keep the existing build pipeline for
mainunchanged (it still produces:latest). - Add safeguards to ensure the
:latestimage exists and that the digest matches the commit referenced by the tag when possible.
Implementation Plan
Pipeline trigger
- New workflow file or job triggered on
pushwithtags:
on:
push:
tags:
- 'v*' # or your tag pattern
Example GitHub Actions job (Docker Hub or GHCR)
jobs:
retag:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log in to registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Pull latest image
run: |
IMAGE=ghcr.io/org/repo
docker pull ${IMAGE}:latest
- name: Tag with release
run: |
IMAGE=ghcr.io/org/repo
TAG=${GITHUB_REF#refs/tags/}
docker tag ${IMAGE}:latest ${IMAGE}:${TAG}
- name: Push release tag
run: |
IMAGE=ghcr.io/org/repo
TAG=${GITHUB_REF#refs/tags/}
docker push ${IMAGE}:${TAG}
Registry specific notes
- ECR: use
aws ecr get-login-passwordanddocker pull/docker tag/docker push. - Private registries: ensure credentials are available in secrets and the runner has network access.
- Multi-arch images: if
:latestis a manifest list, usedocker manifestorskopeoto copy/retag the manifest list rather than pulling individual arch images. Example:skopeo copy docker://registry/org/repo:latest docker://registry/org/repo:${TAG}.
Acceptance Criteria
- Tag push no longer triggers a full Docker build job for that repository; instead the retag job runs and completes in under 2 minutes (network permitting).
- The release tag points to the exact same image digest as
:latestproduced by themainbuild. - Existing
mainbuild pipeline remains unchanged and continues to produce:latest. - Logs show
docker pull,docker tag, anddocker pushsteps; nodocker buildis executed during tag pipeline. - Tests for at least one repository in the monorepo confirm the image content is identical (digest equality).
Testing Plan
- Dry run: create a test tag
vtest-<timestamp>and verify the retag job pulls:latestand pushesvtest-.... - Digest check: after pushing, compare
docker inspect --format='{{index .RepoDigests 0}}'orskopeo inspectto ensure digests match. - Failure modes: simulate missing
:latestand confirm pipeline fails with a clear error message and guidance to rebuildmain. - Multi-arch: test with a multi-arch
:latestimage and verify manifest copy preserves all architectures.
Rollback and Risks
- Risk:
:latestmay not correspond to the tag commit ifmainbuild failed or was re-run. Mitigation: add a check that:latestdigest is associated with the expected commit when possible (store image digest as build artifact or in registry metadata). If mismatch, fail the retag and require a rebuild. - Risk: network or registry rate limits. Mitigation: add retries and backoff.
- Rollback: revert the tag-only workflow and re-enable the previous tag-triggered build job.
Tasks and Labels
- Tasks
- Create
retag-on-tag.ymlworkflow (or add job to existing workflows) — implement for GHCR and Docker Hub templates. - Add registry credential secrets documentation.
- Add digest verification step (optional but recommended).
- Add tests for single-arch and multi-arch images.
- Update README and CI docs.
- Create
- Suggested labels:
ci,docker,performance,low-risk - Suggested assignees:
@devops-team,@owner-of-pipelines - Estimate: 2–4 hours for basic implementation; 1–2 additional days to cover multi-arch and digest verification.