Skip to content
Latchkey

Docker publish workflow (joeferner/redis-commander)

The Docker publish workflow from joeferner/redis-commander, explained and optimized by Latchkey.

C

CI health: C - fair

Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: joeferner/redis-commander.github/workflows/docker-publish.ymlLicense MITView source

What it does

This is the Docker publish workflow from the joeferner/redis-commander repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
---
name: Docker publish

on:
  push:
    # Publish `master` as Docker `latest` image, version tags as respective version too
    branches:
      - master
      - main
    tags:
      - v[0-9]*
    paths-ignore:
      - '.github/**'
      - '.s2i/**'
      - 'dist/**'
      - 'docs/**'
      - 'k8s/**'
      - 'test/'
      - '.*'
      - 'docker-compose.yml'
      - 'ecosystem.config.js'
      - 'CHANGELOG.md'
      - 'README.md'
      - 'SECURITY.md'

env:
  GITHUB_REG: ghcr.io
  GITHUB_REPO: ${{ github.repository }}
  DOCKERHUB_IMAGE: rediscommander/redis-commander

defaults:
  run:
    shell: bash

permissions:
  actions: read
  checks: read
  contents: read
  deployments: read
  packages: write
  pull-requests: read
  repository-projects: read
  security-events: read
  statuses: read

jobs:
  build_publish:
    name: Build image and push
    if: github.repository == 'joeferner/redis-commander'
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU for Buildx
        id: qemu
        uses: docker/setup-qemu-action@v3
        with:
          platforms: all

      - name: Install Buildx
        id: buildx
        uses: docker/setup-buildx-action@v3
        with:
          version: latest
          install: true

      # log into github container registry as named registry
      # and dockerhub without explicit name
      # =============
      #- name: Log in to Dockerhub
      #  uses: docker/login-action@v3
      #  with:
      #    username: "${{secrets.DOCKER_USERNAME}}"
      #    password: "${{secrets.DOCKER_PASSWORD}}"

      - name: Log in to Github Container registry
        uses: docker/login-action@v3
        with:
          registry: "${{ env.GITHUB_REG }}"
          username: "${{ github.actor }}"
          password: "${{ secrets.GITHUB_TOKEN }}"


      - name: Prepare Tags
        id: prep
        env:
          GITHUB_IMAGE: ${{ env.GITHUB_REG }}/${{ env.GITHUB_REPO }}
        run: |
          VERSION=latest
          # first ghcr.io, second dockerhub
          TAGS="${GITHUB_IMAGE}:${VERSION}"
          #TAGS="$TAGS,${DOCKERHUB_IMAGE}:${VERSION}"

          # If this is git tag, use the tag name as a docker tag too
          if [[ $GITHUB_REF == refs/tags/v* ]]; then
            VERSION=${GITHUB_REF#refs/tags/v}
            VERSION_MINOR=${VERSION%.*}
            VERSION_MAJOR=${VERSION%%.*}
            # also tag with version numbers additionally to "latest"
            TAGS="$TAGS,${GITHUB_IMAGE}:${VERSION},${GITHUB_IMAGE}:${VERSION_MINOR},${GITHUB_IMAGE}:${VERSION_MAJOR}"
            #TAGS="$TAGS,${DOCKERHUB_IMAGE}:${VERSION},${DOCKERHUB_IMAGE}:${VERSION_MINOR},${DOCKERHUB_IMAGE}:${VERSION_MAJOR}"
          fi

          # Set output parameters.
          echo "tags=${TAGS}" >> $GITHUB_OUTPUT
          echo "docker_image=${DOCKERHUB_IMAGE}" >> $GITHUB_OUTPUT


      - name: Show docker image tags to build
        run: |
          echo "Docker image: ${{ steps.prep.outputs.docker_image }}"
          echo "Image tags:  ${{ steps.prep.outputs.tags }}"

      - name: Docker build and push to GHCR and Dockerhub for prepared tags
        uses: docker/build-push-action@v6
        with:
          builder: ${{ steps.buildx.outputs.name }}
          context: .
          platforms: linux/amd64,linux/arm/v7,linux/arm64
          push: true
          tags: ${{ steps.prep.outputs.tags }}
        # platform linux/riscv64 starts with alpine:edge, not available on 3.15 by now
        # see "docker manifest inspect alpine:3.15 | alpine:edge

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

---
name: Docker publish
 
on:
  push:
    # Publish `master` as Docker `latest` image, version tags as respective version too
    branches:
      - master
      - main
    tags:
      - v[0-9]*
    paths-ignore:
      - '.github/**'
      - '.s2i/**'
      - 'dist/**'
      - 'docs/**'
      - 'k8s/**'
      - 'test/'
      - '.*'
      - 'docker-compose.yml'
      - 'ecosystem.config.js'
      - 'CHANGELOG.md'
      - 'README.md'
      - 'SECURITY.md'
 
env:
  GITHUB_REG: ghcr.io
  GITHUB_REPO: ${{ github.repository }}
  DOCKERHUB_IMAGE: rediscommander/redis-commander
 
defaults:
  run:
    shell: bash
 
permissions:
  actions: read
  checks: read
  contents: read
  deployments: read
  packages: write
  pull-requests: read
  repository-projects: read
  security-events: read
  statuses: read
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  build_publish:
    timeout-minutes: 30
    name: Build image and push
    if: github.repository == 'joeferner/redis-commander'
    runs-on: latchkey-small
 
    steps:
      - name: Checkout
        uses: actions/checkout@v4
 
      - name: Set up QEMU for Buildx
        id: qemu
        uses: docker/setup-qemu-action@v3
        with:
          platforms: all
 
      - name: Install Buildx
        id: buildx
        uses: docker/setup-buildx-action@v3
        with:
          version: latest
          install: true
 
      # log into github container registry as named registry
      # and dockerhub without explicit name
      # =============
      #- name: Log in to Dockerhub
      #  uses: docker/login-action@v3
      #  with:
      #    username: "${{secrets.DOCKER_USERNAME}}"
      #    password: "${{secrets.DOCKER_PASSWORD}}"
 
      - name: Log in to Github Container registry
        uses: docker/login-action@v3
        with:
          registry: "${{ env.GITHUB_REG }}"
          username: "${{ github.actor }}"
          password: "${{ secrets.GITHUB_TOKEN }}"
 
 
      - name: Prepare Tags
        id: prep
        env:
          GITHUB_IMAGE: ${{ env.GITHUB_REG }}/${{ env.GITHUB_REPO }}
        run: |
          VERSION=latest
          # first ghcr.io, second dockerhub
          TAGS="${GITHUB_IMAGE}:${VERSION}"
          #TAGS="$TAGS,${DOCKERHUB_IMAGE}:${VERSION}"
 
          # If this is git tag, use the tag name as a docker tag too
          if [[ $GITHUB_REF == refs/tags/v* ]]; then
            VERSION=${GITHUB_REF#refs/tags/v}
            VERSION_MINOR=${VERSION%.*}
            VERSION_MAJOR=${VERSION%%.*}
            # also tag with version numbers additionally to "latest"
            TAGS="$TAGS,${GITHUB_IMAGE}:${VERSION},${GITHUB_IMAGE}:${VERSION_MINOR},${GITHUB_IMAGE}:${VERSION_MAJOR}"
            #TAGS="$TAGS,${DOCKERHUB_IMAGE}:${VERSION},${DOCKERHUB_IMAGE}:${VERSION_MINOR},${DOCKERHUB_IMAGE}:${VERSION_MAJOR}"
          fi
 
          # Set output parameters.
          echo "tags=${TAGS}" >> $GITHUB_OUTPUT
          echo "docker_image=${DOCKERHUB_IMAGE}" >> $GITHUB_OUTPUT
 
 
      - name: Show docker image tags to build
        run: |
          echo "Docker image: ${{ steps.prep.outputs.docker_image }}"
          echo "Image tags:  ${{ steps.prep.outputs.tags }}"
 
      - name: Docker build and push to GHCR and Dockerhub for prepared tags
        uses: docker/build-push-action@v6
        with:
          builder: ${{ steps.buildx.outputs.name }}
          context: .
          platforms: linux/amd64,linux/arm/v7,linux/arm64
          push: true
          tags: ${{ steps.prep.outputs.tags }}
        # platform linux/riscv64 starts with alpine:edge, not available on 3.15 by now
        # see "docker manifest inspect alpine:3.15 | alpine:edge
 

What changed

4 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow