docker-build-push/README.md
CrazyMax 953dc85723
Simplify "Complete workflow" with Docker meta action
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-10-28 19:40:17 +01:00

20 KiB

GitHub release GitHub marketplace CI workflow Test workflow Codecov

Upgrade from v1

v2 of this action includes significant updates and now uses Docker Buildx. It works with 3 new actions (login, setup-buildx and setup-qemu) that we have created. It's also rewritten as a typescript-action to be as closed as possible of the GitHub Runner during its execution.

Upgrade notes and many usage examples have been added to handle most use cases but v1 is still available through releases/v1 branch.

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.

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
          build-args: |
            arg1=value1
            arg2=value2            
      -
        name: Image digest
        run: echo ${{ steps.docker_build.outputs.digest }}

Building from current repository automatically uses the GitHub Token as provided by secrets so it does not need to be passed. But if you want to authenticate against another private repository, you have to use 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=${{ secrets.MYTOKEN }}            

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

More info: https://docs.docker.com/engine/reference/commandline/build/#git-repositories

Path context

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

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

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

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

Push to multi-registries

The following workflow will connect you to DockerHub and GitHub Container Registry and push the image to these registries.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  multi-registries:
    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: Login to GitHub Container Registry
        uses: docker/login-action@v1 
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      -
        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
            ghcr.io/user/app:latest
            ghcr.io/user/app:1.0.0            

Cache to registry

You can import/export cache from a cache manifest or (special) image configuration on the registry.

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  registry-cache:
    runs-on: ubuntu-latest
    steps:
      -
        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
          cache-from: type=registry,ref=user/app:latest
          cache-to: type=inline

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          

Export image to Docker

You may want your build result to be available in the Docker client through docker images to be able to use it in another step of your workflow:

Show workflow
name: ci

on:
  push:
    branches: master

jobs:
  export-docker:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      -
        name: Build
        uses: docker/build-push-action@v2
        with:
          context: .
          file: ./Dockerfile
          load: true
          tags: myimage:latest
      -
        name: Inspect
        run: |
          docker image inspect myimage: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

If you want to export layers for all stages, you have to specify mode=max attribute in cache-to.

Handle tags and labels

If you come from v1 and want an "automatic" tag management and OCI Image Format Specification for labels, you can do it in a dedicated step. The following workflow will use the Docker meta action to handle tags and labels based on GitHub actions events and Git metadata.

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: Docker meta
        id: docker_meta
        uses: crazy-max/ghaction-docker-meta@v1
        with:
          images: name/app # list of Docker images to use as base name for tags
          tag-sha: true # add git short SHA as Docker tag
      -
        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.docker_meta.outputs.tags }}
          labels: ${{ steps.docker_meta.outputs.labels }}

Update DockerHub repo description

You can update the DockerHub repository description using a third-party action called DockerHub 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
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PASSWORD }}
          repository: user/app

Customizing

inputs

Following inputs can be used as step.with keys

List type is a newline-delimited string

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

CSV type is a comma-delimited string

tags: name/app:latest,name/app:1.0.0
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/CSV 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/CSV 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/CSV 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 List List of output destinations (format: type=local,dest=path)
cache-from List List of external cache sources (eg. type=local,src=path/to/dir)
cache-to List List of cache export destinations (eg. type=local,dest=path/to/dir)
secrets List List of secrets to expose to the build (eg. key=value, GIT_AUTH_TOKEN=mytoken)
ssh List List of SSH agent socket or keys to expose to the build

outputs

Following outputs are available

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

Troubleshooting

See TROUBLESHOOTING.md

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.