To use a Docker container you need to prefix your step with docker:// and then specify the image name. This works for Docker Hub images out of the box. Here is an example to build a Jekyll static website using the official Jekyll Docker Image in Github actions:

name: Deploy Website

# Controls when the action will run.
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  push:
    branches: [main]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Builds the website inside docker container
      - name: Build website
        uses: docker://jekyll/jekyll
        with:
          args: jekyll build
        env:
          JEKYLL_ENV: production
          JEKYLL_ROOTLESS: true

As you can see, all we needed to do was tell GitHub actions that our second step uses the docker://jekyll/jekyll container image. The arguments are passed to the Docker image which may be different for various containers. In this case, we want to build the website with the production environment variable set.

I really like this because it avoids clumsily installing all the dependencies in the blank Ubuntu image (ubuntu-latest) that the job starts with. There are other benefits too:

  • It is consistent across build environments. You can build using the same image on your local machine and in Github actions without worrying about what the build step will do. It does exactly what the container should do.
  • You avoid installing stuff. The container is ready-to-go, plug-and-play style approach. If you use official images like we did with Jekyll, you can be certain that it comes with everything it needs.
  • Finally, it is easy to share. Most of these advantages are common to containers in general. You can share your build process and anyone can replicate it so long as they use the same container image.

For more complex pipelines, you can use a custom image with all the dependencies and tools you need. You will have to maintain that image but at least you get the same benefits.