DEV Community

loading...
Cover image for Push and publish Docker images with GitHub Actions

Push and publish Docker images with GitHub Actions

minompi profile image AlessandroMinoccheri Originally published at minompi.Medium ・4 min read

In many articles, I mentioned many times about using GitHub Actions because they are a good choice for a lot of reasons.

Nowadays I can admit that there is another choice that I have explored and used a lot these days.
What I mean is the functionality of pushing your docker image through your GitHub Actions during your CI process.

Usually, when I want to publish my docker images to DockerHub, I need to do it manually by the command line, like this:

Building the image

docker image build -t organization/project:0.1.0 .
Enter fullscreen mode Exit fullscreen mode

Publishing to DockerHub

docker push organization/project:0.1.0
Enter fullscreen mode Exit fullscreen mode

It’s not a lot of work, but every time you fix or add a new feature you need to remember to build a new image and publish it.
Usually, I try to avoid manual operations because human error is possible, and automating what is repetitive for me is a best practice everywhere.

So for this reason, in one open-source project Arkitect where I’m contributing nowadays, we have a Dockerfile that needs to be published every time there is a push on master, or a new release comes out.

I can build and publish the Docker image manually every time, but I prefer to avoid this and I have tried exploring GitHub Actions to automate this process.

Github Actions

Exploring GitHub’s actions to automate the process of publishing a docker image to DockerHub was interesting because I found a lot of other interesting GitHub actions and many projects that do the automation that I like.

First of all, I have inserted inside my GitHub project into Settings->Secrets, two important repository secrets:

  • DOCKERHUB_USERNAME: this is your username on Dockerhub or the name of your organization
  • DOCKERHUB_TOKEN: this is the token and you can get it going on DockerHub in Account Settings->Security. Here you can generate a new Access Token. You can take the value and put it on GitHub.

Next step, I have created a file for the workflow inside GitHub and named it docker-publish.yml

The file is something like this:

name: Arkitect
on:
  push:
    branches:
      — '*'
    tags:
      — '*'
 pull_request:
jobs:
  publish_docker_images:
    runs-on: ubuntu-latest
    steps:
    — name: Checkout
      uses: actions/checkout@v2
    — name: Docker meta
      id: meta
      uses: crazy-max/ghaction-docker-meta@v2
      with:
        images: phparkitect/phparkitect
        tags: |
          type=raw,value=latest,enable=${{ endsWith(GitHub.ref, 'master') }}
          type=ref,event=tag
        flavor: |
          latest=false
     — 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
       uses: docker/build-push-action@v2
       with:
         context: .
         push: ${{ GitHub.event_name != 'pull_request' }}
         tags: ${{ steps.meta.outputs.tags }}
         labels: ${{ steps.meta.outputs.labels }}
Enter fullscreen mode Exit fullscreen mode

But it’s not enough because this build will only start if the tests pass, so I have moved the content of this file inside my CI process to another workflow called: build.yml. This is the test suite.

So we need to create a new job that depends on the test job, thanks to the keyword “needs”, like this:

name: Arkitect
on:
  push:
    branches:
      — '*'
    tags:
      — '*'
    pull_request:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    — uses: actions/checkout@v2
    - name: Install PHP
      run : //stuff to install PHP
    - name: Test
      run: ./bin/phpunit
  publish_docker_images:
    needs: build
    runs-on: ubuntu-latest
    if: GitHub.ref == 'refs/heads/master' || GitHub.event_name == 'release'
    steps:
    — name: Checkout
      uses: actions/checkout@v2
    — name: Docker meta
      id: meta
      uses: crazy-max/ghaction-docker-meta@v2
      with:
        images: phparkitect/phparkitect
        tags: |
          type=raw,value=latest,enable=${{ endsWith(GitHub.ref, ‘master’) }}
          type=ref,event=tag
        flavor: |
          latest=false
    — 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
     uses: docker/build-push-action@v2
     with:
       context: .
       push: ${{ GitHub.event_name != 'pull_request' }}
       tags: ${{ steps.meta.outputs.tags }}
       labels: ${{ steps.meta.outputs.labels }}
Enter fullscreen mode Exit fullscreen mode

In this example, as I said before, I have created a new job that depends on the job named “build”.
In this way, if the job named “build” fails, I don’t create a new docker image, because I want to create it only if the tests pass.

I have used these GitHub Actions:
crazy-max/ghaction-docker-meta@v2: it extracts metadata (tags, labels) for Docker.

docker/build-push-action@v2: it builds and pushes Docker images with Buildx with the full support of the features provided by Moby BuildKit builder toolkit.

A condition that I have added to my docker push job is:

if: GitHub.ref == 'refs/heads/master' || GitHub.event_name == 'release'
Enter fullscreen mode Exit fullscreen mode

Because I want to execute this job only:

  • when there is a push on master
  • when a new tag is created

This is necessary for me because I don’t want to create a new docker image every time a pull request is created.

When there is a push on master the workflow, create a new docker image with the tag “latest”.
When a new tag is released, the workflow creates a new docker image, with the tag equal to the tag of the project and the tag “latest” is recreated.
In this way, I am sure to publish the last version of the docker image every time with new features or bugs fixed.

Github Actions build

In conclusion, using GitHub Actions saves me a lot of time and repetitive work every time I need to publish my docker image for my project.
There are a lot of other processes that can be automated that I would like to explore and try in my projects, so as soon as possible I will publish other articles about this argument.

Discussion (4)

Collapse
Sloan, the sloth mascot
Comment deleted
Collapse
minompi profile image
AlessandroMinoccheri Author

You can use tag latest for your image @aathith_r
You need to restart your containers to get new image.

Collapse
crazymax profile image
CrazyMax • Edited

Glad you like the meta action :)

Collapse
minompi profile image
AlessandroMinoccheri Author

Thanks for your amazing work! :)

Forem Open with the Forem app