I wanted to see how to automate the creation of docker images using github actions. This is how I did it.

  1. Create a repo
  2. Create a docker hub api key
  3. Create your application
  4. Create dockerfile
  5. Add github workflow
  6. Push and test!

Let's go!

Create a sample repo

1
2
3
  mkdir actionstest
  cd actionstest
  git init

The roll over to GitHub and create a new repository. I'm calling mine wschenk/actionstest.

Now we can add the remote, in my case

1
  git remote add origin git@github.com:wschenk/actionstest.git

Creating secrets

First log into docker hub, and create a new access token. Copy this, and then go to the settings of your GitHub project. Then create the following secrets.

DOCKERHUB_USERNAMEYour login
DOCKERHUB_TOKENThe token you just created

Inside of the workflow we can access these like ${{ secrets.DOCKERHUB_USERNAME }}.

Our "application"

This is pretty simple. We print the date and then run the fortune command.

app.sh:

1
2
3
  #!/bin/sh
  date
  fortune

And we'll test it, why not.

success_test.sh:

1
2
3
  #!/bin/sh
  echo This will succeed
  exit 0

fail_test.sh:

1
2
3
  #!/bin/sh
  echo This will fail
  exit 1

Dockerfile

This is a pretty simple Dockerfile that just copies stuff over and runs the app.

1
2
3
4
5
6
7
8
9
  FROM alpine:3.14.0

  RUN apk add fortune

  WORKDIR /app
  COPY *sh /app/
  RUN chmod +x *sh

  CMD /app/app.sh

Running locally

1
docker build . -t test

Run the test:

1
2
  docker run --rm -it test /app/fail_test.sh
  echo $?

We can see that it "runs the tests" but returns a non-zero, i.e. failed status.

Build test and push action

This action has a number of steps:

  1. It runs on all push actions, regardless of branch.
  2. First it actions/checkout@v2 the repo.
  3. Then it logs into dockerhub using the secrets
  4. It uses docker/metadata-action to find the tags and labels for which branch was committed.
  5. Runs docker/build-push-action with push false to create the image.
  6. It then runs the test script from the resulting image. If this fails, the action fails.
  7. Assuming the tests pass, it "rebuilds" the image and pushes the tags to dockerhub

Create .github/workflows/build_test_and_push.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  name: Build and Push

  on: push

  jobs:
    docker:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v2
        -
          name: Login to DockerHub
          uses: docker/login-action@v1 
          with:
            username: ${{ secrets.DOCKERHUB_USERNAME }}
            password: ${{ secrets.DOCKERHUB_TOKEN }}
        -
          name: Docker meta
          id: meta
          uses: docker/metadata-action@v3
          with:
            images: wschenk/testimage
        -
          name: Build
          id: docker_build
          uses: docker/build-push-action@v2
        -
          name: Run Tests
          run: docker run ${{ steps.docker_build.outputs.digest }} sh /app/fail_test.sh
        -
          name: Build and push
          id: docker_push
          uses: docker/build-push-action@v2
          with:
            push: true
            tags: ${{ steps.meta.outputs.tags }}
            labels: ${{ steps.meta.outputs.labels }}

Test it out

1
2
3
  git add .
  git commit -m "Initial import"
  git push origin master

Since we have the fail_test.sh script being run as part of the action, it should build the image and then abort on the Run Test part of the run. If you go to your repository, click on Actions, you should see the failed run.

Lets create a staging branch to fix it:

1
git checkout -b staging

Then change like 28 inside of build_test_and_push.sh to run /app/success_test.sh instead. Commit, and then push to the staging branch:

1
2
3
git add .
git commit -m "Fixing the test in staging"
git push origin staging

This build should succeed, and if you go to hub.docker.com under your user, you should see the image there with the staging tag.

Previously

TanStack/query

2021-07-01

Next

Rails on Kubernetes with TLS certmanager

2021-07-16

howto

Previously

Deploying OpenFaaS on Digital Ocean with Terraform Everything functional

2021-06-02

Next

Rails on Kubernetes with TLS certmanager

2021-07-16