Publishing Docker Images

Here, we're going to see how you can build your docker images on merge, and then push it to a remote registry. We're going to use both Docker Hub and AWS ECR (Elastic Container Registry).

Docker Hub

To user Docker Hub and push your images there, you need to have a valid account. So, head to hub.docker.com and create a free account (no need to upgrade to any paid plans).

Once you have your account set up, you can use the following command to login to Docker Hub:

docker login -u <YOUR-USERNAME> -p <YOUR-PASSWORD>

Your images need to be tagged in a certain way. Specifically, they need to be tagged like this:

<YOUR-USERNAME>/<YOUR-IMAGE-NAME>:<YOUR-IMAGE-TAG>

You can tag your images when building them using:

docker build -t <YOUR-USERNAME>/<YOUR-IMAGE-NAME>:<YOUR-IMAGE-TAG> .

You can also tag a pre-existing image with docker tag command:

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

Once you're logged in, and your image is properly tagged, you can push your image to your account using the docker push command:

docker push <YOUR-USERNAME>/<YOUR-IMAGE-NAME>:<YOUR-IMAGE-TAG>

Building GitHub action to push to Docker Hub

We can create a GitHub action to build and then push the image into our Docker Hub account:

name: build & push

on:
  push:
    branches:
      - main
    paths-ignore:
      - '**.md'

jobs:
  run:
    runs-on: ubuntu-latest
    env:
      REPO_NAME: <your-repo-name>

    steps:
      - name: GitHub checkout
        uses: actions/checkout@v2

      - name: ECR Login
        run: docker login -u ${{ secrets.DOCKER_HUB_USER }} -p "${{ secrets.DOCKER_HUB_PASSWORD }}"
      
      - name: Docker Build
        run: docker build -t ${{ secrets.DOCKER_HUB_USER }}/${{ env.REPO_NAME }} .

      - name: Docker Push
        run: docker push ${{ secrets.DOCKER_HUB_USER }}/${{ env.REPO_NAME }}:latest

AWS ECR

AWS ECR is a private registry for docker images. Before pushing your images there, you need a repository. Let's create that via Terraform:

resource "aws_ecr_repository" "repo" {
  name = "my-repo"
}

Once created, the AWS console will show you the commands you will need to use to prepare and push your images, including the step required for logging in. Just click on the View Push Commands on top right.

Here's a GitHub Action that uses the commands shown on the AWS console to push the image. Note that the role you're using mush have the necessary ECR permissions.

name: build & push

on:
  push:
    branches:
      - main
    paths-ignore:
      - '**.md'

permissions:
  id-token: write
  contents: read    

jobs:
  run:
    runs-on: ubuntu-latest
    env:
      REPO_NAME: repo-name

    steps:
      - name: GitHub checkout
        uses: actions/checkout@v2

      - name: AWS
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: ${{ secrets.ROLE_ARN }}
          aws-region: ca-central-1

      - name: ECR Login
        run: aws ecr get-login-password --region ca-central-1 | docker login --username AWS --password-stdin <registry-address> 

      - name: Docker Build
        run: docker build -t ${{ env.REPO_NAME }} . 

      - name: Docker Tag
        run: docker tag ${{ env.REPO_NAME }}:latest <registry-address>/${{ env.REPO_NAME }}:latest

      - name: ECR Push
        run: docker push <registry-address>/${{ env.REPO_NAME }}:latest