build-push-action/README.md
CrazyMax 5281740ad2
Add Troubleshooting section
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-09-21 18:23:09 +02:00

20 KiB

GitHub release GitHub marketplace CI workflow Test workflow Codecov

About

GitHub Action to build and push Docker images with Buildx.

💡 See also:

Screenshot


Usage

This action uses our setup-buildx action that extends the docker build command named buildx with the full support of the features provided by Moby BuildKit builder toolkit. This includes multi-arch build, build-secrets, remote cache, etc. and different builder deployment/namespacing options.

Git context

The default behavior of this action is to use the Git context invoked by your workflow.

Show workflow
name: ci

on:
push:
  branches: master

jobs:
main:
  runs-on: ubuntu-latest
  steps:
    -
      name: Set up QEMU
      uses: docker/setup-qemu-action@v1
    -
      name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1
    -
      name: Login to DockerHub
      uses: docker/login-action@v1 
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}
    -
      name: Build and push
      id: docker_build
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: user/app:latest
    -
      name: Image digest
      run: echo ${{ steps.docker_build.outputs.digest }}

If you use this action in a private repository, you have to pass the GitHub Token as a secret named GIT_AUTH_TOKEN to be able to authenticate against it with buildx:

      -
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: user/app:latest
          secrets: |
            GIT_AUTH_TOKEN=${{ github.token }}            

⚠️ Subdir for Git context is not yet supported. For the moment you can use the path context.

Path context

You can also use the PATH context alongside the actions/checkout action.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  path-context:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64,linux/386
          push: true
          tags: user/app:latest

Isolated builders

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  multi-builders:
    runs-on: ubuntu-latest
    steps:
      -
        uses: docker/setup-buildx-action@v1
        id: builder1
      -
        uses: docker/setup-buildx-action@v1
        id: builder2
      -
        name: Builder 1 name
        run: echo ${{ steps.builder1.outputs.name }}
      -
        name: Builder 2 name
        run: echo ${{ steps.builder2.outputs.name }}
      -
        name: Build against builder1
        uses: docker/build-push-action@v2
        with:
          builder: ${{ steps.builder1.outputs.name }}
          target: mytarget1
      -
        name: Build against builder2
        uses: docker/build-push-action@v2
        with:
          builder: ${{ steps.builder2.outputs.name }}
          target: mytarget2

Multi-platform image

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  multi:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
          push: true
          tags: |
            user/app:latest
            user/app:1.0.0            

Advanced usage

Local registry

For testing purposes you may need to create a local registry to push images into.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  local-registry:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:2
        ports:
          - 5000:5000
    steps:
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
        with:
          driver-opts: network=host
      -
        name: Build and push to local registry
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: localhost:5000/name/app:latest
      -
        name: Inspect
        run: |
          docker buildx imagetools inspect localhost:5000/name/app:latest          

Leverage GitHub cache

You can leverage GitHub cache using actions/cache with this action.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  github-cache:
    runs-on: ubuntu-latest
    steps:
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Cache Docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-            
      -
        name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: user/app:latest
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache

Complete workflow

If you come from v1 and you want an "automatic" tag management through Git reference and OCI Image Format Specification for labels, you will have to do it in a dedicated step for now.

The following workflow with the Prepare step will generate some outputs to handle tags and labels based on GitHub actions events. This is just an example to show many cases that you might want to use:

Event Ref Commit SHA Docker Tag Pushed
schedule nightly Yes
pull_request refs/pull/2/merge a123b57 pr-2 No
push refs/heads/<default_branch> 676cae2 sha-676cae2, edge Yes
push refs/heads/dev cf20257 sha-cf20257, dev Yes
push refs/heads/my/branch a5df687 sha-a5df687, my-branch Yes
push tag refs/tags/v1.2.3 v1.2.3, v1.2, v1, latest Yes
Show workflow
name: ci

on:
  schedule:
    - cron: '0 10 * * *' # everyday at 10am
  push:
    branches:
      - '**'
    tags:
      - 'v*.*.*'
  pull_request:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
      -
        name: Prepare
        id: prep
        run: |
          DOCKER_IMAGE=name/app
          VERSION=noop
          if [ "${{ github.event_name }}" = "schedule" ]; then
            VERSION=nightly
          elif [[ $GITHUB_REF == refs/tags/* ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
          elif [[ $GITHUB_REF == refs/heads/* ]]; then
            VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g')
            if [ "${{ github.event.repository.default_branch }}" = "$VERSION" ]; then
              VERSION=edge
            fi
          elif [[ $GITHUB_REF == refs/pull/* ]]; then
            VERSION=pr-${{ github.event.number }}
          fi
          TAGS="${DOCKER_IMAGE}:${VERSION}"
          if [[ $VERSION =~ ^v[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
            MINOR=${VERSION%.*}
            MAJOR=${MINOR%.*}
            TAGS="$TAGS,${DOCKER_IMAGE}:${MINOR},${DOCKER_IMAGE}:${MAJOR},${DOCKER_IMAGE}:latest"
          elif [ "${{ github.event_name }}" = "push" ]; then
            TAGS="$TAGS,${DOCKER_IMAGE}:sha-${GITHUB_SHA::8}"
          fi
          echo ::set-output name=version::${VERSION}
          echo ::set-output name=tags::${TAGS}
          echo ::set-output name=created::$(date -u +'%Y-%m-%dT%H:%M:%SZ')          
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64,linux/386
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.prep.outputs.tags }}
          labels: |
            org.opencontainers.image.title=${{ github.event.repository.name }}
            org.opencontainers.image.description=${{ github.event.repository.description }}
            org.opencontainers.image.url=${{ github.event.repository.html_url }}
            org.opencontainers.image.source=${{ github.event.repository.clone_url }}
            org.opencontainers.image.version=${{ steps.prep.outputs.version }}
            org.opencontainers.image.created=${{ steps.prep.outputs.created }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }}            

Update DockerHub repo description

You can update the Docker Hub repository description using a third-party action called Docker Hub Description with this action.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: Build and push
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: user/app:latest
      -
        name: Update repo description
        uses: peter-evans/dockerhub-description@v2
        env:
          DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
          DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
          DOCKERHUB_REPOSITORY: user/app

Customizing

inputs

Following inputs can be used as step.with keys

Name Type Description
builder String Builder instance (see setup-buildx action)
context String Build's context is the set of files located in the specified PATH or URL (default Git context)
file String Path to the Dockerfile (default Dockerfile)
build-args List List of build-time variables
labels List List of metadata for an image
tags List List of tags
pull Bool Always attempt to pull a newer version of the image (default false)
target String Sets the target stage to build
allow List List of extra privileged entitlement (eg. network.host,security.insecure)
no-cache Bool Do not use cache when building the image (default false)
platforms List List of target platforms for build
load Bool Load is a shorthand for --output=type=docker (default false)
push Bool Push is a shorthand for --output=type=registry (default false)
outputs CSV List of output destinations (format: type=local,dest=path)
cache-from CSV List of external cache sources (eg. type=local,src=path/to/dir)
cache-to CSV List of cache export destinations (eg. type=local,dest=path/to/dir)
secrets CSV List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)

List type can be a comma or newline-delimited string

tags: name/app:latest,name/app:1.0.0
tags: |
  name/app:latest
  name/app:1.0.0  

CSV type must be a newline-delimited string

cache-from: user/app:cache
cache-from: |
  user/app:cache
  type=local,src=path/to/dir  

outputs

Following outputs are available

Name Type Description
digest String Image content-addressable identifier also called a digest

Troubleshooting

While pushing to a registry, you may encounter these kinds of issues:

  • failed commit on ref "layer-sha256:...": invalid content digest in response: invalid checksum digest format
  • failed commit on ref "layer-sha256:...": no response
  • failed commit on ref "manifest-sha256:...": unexpected status: 401 Unauthorized
  • unexpected response: 401 Unauthorized

These issues are not directly related to this action but are rather linked to buildx, buildkit, containerd or the registry on which you're pushing your image. The quality of error message depends on the registry and are usually not very informative.

To help you solve this, you should first enable debugging in the setup-buildx action step:

  -
    name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v1
    with:
      buildkitd-flags: --debug

Next you can test pushing with containerd using this workflow. Do not forget to set ctr --debug for the pushing step. If it works then open an issue on buildkit repository.

Keep up-to-date with GitHub Dependabot

Since Dependabot has native GitHub Actions support, to enable it on your GitHub repo all you need to do is add the .github/dependabot.yml file:

version: 2
updates:
  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "daily"

Limitation

This action is only available for Linux virtual environments.