DEV Community

Cover image for Push and publish Docker images with GitHub Actions
AlessandroMinoccheri
AlessandroMinoccheri

Posted on • Originally published at minompi.Medium

Push and publish Docker images with GitHub Actions

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.

Top comments (4)

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

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

Thanks for your amazing work! :)