18

I'm using GitHub Actions to build a docker image using the build-push-action. I'd like to add tags to the image before pushing it to the docker registry:

  • Each image should be tagged with latest
  • If the commit that triggered the build has a git tag attached, the image should be tagged with this tag as well.

I have something along the lines of:

- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  with:
    context: .
    push: true
    tags:
      - user/image:latest

It would be easy to always add more tags, but I want to add it only if there's a git tag. Is there a way to do that?

4 Answers 4

23

There's a docker/metadata-action that does this. Make sure to set up the push tags trigger along with whatever other triggers you might need. The action docs have a lot more details about what tags it applies for each event trigger type. See also https://docs.github.com/en/actions/publishing-packages/publishing-docker-images for even more info on the general topic of Docker image publishing.

name: Tag Docker Image with Git

on:
  push:
    tags: [ v* ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:

    runs-on: ubuntu-latest

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

    - name: Log into the Container registry
      uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata for the Docker image
      id: meta
      uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

    - name: Build and push the Docker image
      uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
Sign up to request clarification or add additional context in comments.

1 Comment

And if you're not getting the latest tag because you're using a branch other than master, like main, read github.com/docker/metadata-action#latest-tag
8

I found a solution using a dedicated action. I create the tags in a separate step and add it afterwards. The relevant parts of the CI config look like this:

- name: Docker meta
  id: docker_meta
  uses: crazy-max/ghaction-docker-meta@v1
  with:
    images: l7r7/sample
    tag-custom: latest
    tag-semver: |
      {{raw}}
- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  with:
    context: .
    push: false
    tags: ${{ steps.docker_meta.outputs.tags }}
    labels: ${{ steps.docker_meta.outputs.labels }}

To be precise, it's not exactly what I was asking for, because it will add a tag containing the branch name as well. But that's ok for me. I can live with that.

A full working example can be found here.

Comments

3

I was not able to use the above answers because they are triggered upon adding a tag, whereas I wanted it to be triggered by pushing to master.

In my case, I would:

  1. Use an action to update the tags upon on a push to master. https://github.com/mathieudutour/github-tag-action
  2. And in a separate step, deploy:
- name: Checkout
  uses: actions/checkout@v2
  with:
    fetch-depth: 0 # Without this, this action won't be able to find any or the correct tags.

- name: 'Get tag'
  id: tag
  uses: 'WyriHaximus/github-action-get-previous-tag@8a0e045f02c0a3a04e1452df58b90fc7e555e950'

- name: Set correct environment
  run: |
    TAG=${{ steps.tag.outputs.tag }}
    echo "TAG=$TAG" >> "$GITHUB_ENV"

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v1

- name: Retrieve metadata
  id: metadata
  uses: docker/metadata-action@e5622373a38e60fb6d795a4421e56882f2d7a681
  env:
    ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
  with:
    images: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}
    tags: |
      type=semver,pattern={{major}}.{{minor}}.{{patch}},value=${{ env.TAG }}
      type=semver,pattern={{major}}.{{minor}},value=${{ env.TAG }}
      type=semver,pattern={{major}},value=${{ env.TAG }}

- name: Build and push
  id: docker
  uses: docker/build-push-action@v2
  with:
    push: true
    tags: ${{ steps.metadata.outputs.tags }}

Comments

2

Maybe something like this:


- name: Build and push
  id: gen_tags
  run: |
    if [[ $GITHUB_REF == 'refs/tags/'* ]]; then
      TAGS='["user/image:latest","user/image:'${GITHUB_REF/refs\/tags\//}'"]'
    else
      TAGS='["user/image:latest"]'
    fi
    echo '::set-output name=tags::'$TAGS

- name: Build and push
  id: docker_build
  uses: docker/build-push-action@v2
  needs: gen_tags
  with:
    context: .
    push: true
    tags: ${{ fromJson(steps.gen_tags.outputs.tags) }}

The first step generates the list of tags and the second build/push. if $GITHUB_REF starts by refs/tags/ it is a tag and as such we generate a json list with both docker tags. Else, we use a list that contains only the latest tag. Since we can only pass strings around, we have to output the json as a string and then parse it in the second step using fromJson. I am sorry for the ugly escaping (you might actually have issues there and have to try few different solutions), but it's a bit tricky to do without making the script more complex.

3 Comments

Thanks for this proposal. While it's not elegant, I think the idea makes sense. However, I think I'm hitting a problem with the escaping as you already mentioned. I created a minimal example that shows the issue. Haven't found a solution yet, in case you want to have a look, here is the project: github.com/L7R7/docker-tags-github-actions/runs/…
You're probably going to have to print the output to se how it looks like. In any case, your custom action seem to be a more reliable solution.
in the 5th line, is the second part (the one adding the tag) not missing a "user/image:" prefix?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.