In this tutorial, we will set up a GitHub Actions pipeline to automatically build and publish Docker images for AWS CLI, Azure CLI, and Google Cloud Platform (GCP) CLI to Docker Hub repositories.
Prerequisites
Before we begin, ensure you have the following:
- A GitHub repository containing Dockerfiles for AWS, Azure, and GCP CLI. You can find the repository for AWS Dockerfile here.
- Docker Hub account and authentication token for pushing Docker images.
- GitHub repository secrets configured for Docker Hub credentials.
AWS Dockerfile
# Use the latest Alpine Linux base image
FROM alpine:3.19.1
ENV TERRAFORM_VERSION=1.7.4
# Install necessary packages: Python 3, pip, awscli, jq, git
RUN apk --update --no-cache add \
python3 \
py3-pip \
py3-yaml \
aws-cli \
jq \
git \
openssl \
unzip \
curl \
py3-cryptography \
# Install yq (YAML processor)
&& wget -q -O /usr/bin/yq $(wget -q -O - https://api.github.com/repos/mikefarah/yq/releases/latest | jq -r '.assets[] | select(.name == "yq_linux_amd64") | .browser_download_url') \
&& chmod +x /usr/bin/yq \
&& echo "Intalling Terraform ...." \
&& wget -q https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
&& unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/bin \
&& rm -rf /var/cache/apk/*
# Add a non-root user named dockuser
RUN addgroup -g 1000 dockuser \
&& adduser -D -G dockuser -u 1000 dockuser
# Switch to the dockuser
USER dockuser
# Set the working directory
WORKDIR /home/dockuser
Azure Dockerfile
# Use the latest Alpine Linux base image
FROM alpine:3.19.1
ENV TERRAFORM_VERSION=1.7.4
ENV AZURE_CLI_VERSION=2.0.81
# Install necessary packages: Python 3, pip, jq, git
RUN apk --update --no-cache add \
alpine-sdk \
python3 \
python3-dev \
py3-pip \
py3-yaml \
jq \
git \
openssl \
unzip \
curl \
py3-cryptography \
gcc \
libc-dev \
libffi-dev \
# Install yq (YAML processor)
&& wget -q -O /usr/bin/yq $(wget -q -O - https://api.github.com/repos/mikefarah/yq/releases/latest | jq -r '.assets[] | select(.name == "yq_linux_amd64") | .browser_download_url') \
&& chmod +x /usr/bin/yq \
&& echo "Intalling Terraform ...." \
&& wget -q https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
&& unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/bin \
&& rm -rf /var/cache/apk/*
RUN pip install --upgrade pip --break-system-packages \
&& pip install azure-cli --break-system-packages
# Add a non-root user named dockuser
RUN addgroup -g 1000 dockuser \
&& adduser -D -G dockuser -u 1000 dockuser
# Switch to the dockuser
USER dockuser
# Set the working directory
WORKDIR /home/dockuser
GCP Dockerfile
# Use the latest Alpine Linux base image
FROM alpine:3.19.1
ENV TERRAFORM_VERSION=1.7.4
ENV CLOUD_SDK_VERSION=467.0.0
ENV PATH /google-cloud-sdk/bin:$PATH
# Add a non-root user named dockuser
RUN addgroup -g 1000 dockuser \
&& adduser -D -G dockuser -u 1000 dockuser
RUN if [ `uname -m` = 'x86_64' ]; then echo -n "x86_64" > /tmp/arch; else echo -n "arm" > /tmp/arch; fi;
# Install necessary packages: Python 3, pip, awscli, jq, git
RUN ARCH=`cat /tmp/arch` && apk --update --no-cache add \
python3 \
py3-pip \
py3-yaml \
jq \
git \
openssl \
unzip \
curl \
py3-cryptography \
bash \
gnupg \
# Install yq (YAML processor)
&& wget -q -O /usr/bin/yq $(wget -q -O - https://api.github.com/repos/mikefarah/yq/releases/latest | jq -r '.assets[] | select(.name == "yq_linux_amd64") | .browser_download_url') \
&& chmod +x /usr/bin/yq \
&& echo "Intalling Terraform ...." \
&& wget -q https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
&& unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/bin \
&& curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${CLOUD_SDK_VERSION}-linux-${ARCH}.tar.gz \
&& tar xzf google-cloud-cli-${CLOUD_SDK_VERSION}-linux-${ARCH}.tar.gz \
&& rm google-cloud-cli-${CLOUD_SDK_VERSION}-linux-${ARCH}.tar.gz \
&& gcloud components install kubectl \
&& rm -rf /var/cache/apk/*
# Switch to the dockuser
USER dockuser
# Set the working directory
WORKDIR /home/dockuser
AWS Docker Image YAML (docker_aws_image.yml)
name: AWS Build and publish a Docker image
on:
push:
branches:
- '*'
env:
REGISTRY: devtoolhub
IMAGE_NAME: aws_cli
COMPARE_TAG: latest
SHA: ${{ github.event.after }}
jobs:
build:
name: AWS Build & push docker image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.SHA }}
- name: Debug
run: |
echo "github.ref -> {{ github.ref }}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=moby/buildkit:v0.13.0
- name: lint Action for AWS
uses: hadolint/[email protected]
with:
dockerfile: aws/Dockerfile
ignore: DL3018,SC2046,DL4006
failure-threshold: warning
no-color : false
no-fail: true
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: AWS Docker metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.revision=${{ env.SHA }}
tags: |
type=edge,branch=$repo.default_branch
type=semver,pattern=v{{version}}
type=sha,prefix=,suffix=,format=short
- name: AWS Build & push Docker image
uses: docker/build-push-action@v5
with:
context: aws/
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: AWS Docker Scout
id: docker-scout
uses: docker/scout-action@v1
with:
image: ${{ steps.metadata.outputs.tags }}
command: cves
ignore-unchanged: true
only-severities: critical,high,medium,low,unspecified
only-fixed: true
Azure Docker Image YAML (docker_azure_image.yml)
name: Azure Build and publish a Docker image
on:
push:
branches:
- '*'
env:
REGISTRY: devtoolhub
IMAGE_NAME: azure_cli
COMPARE_TAG: latest
SHA: ${{ github.event.after }}
jobs:
build:
name: Azure Build & push docker image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.SHA }}
- name: Debug
run: |
echo "github.ref -> {{ github.ref }}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=moby/buildkit:v0.13.0
- name: lint Action for Azure
uses: hadolint/[email protected]
with:
dockerfile: azure/Dockerfile
ignore: DL3018,SC2046,DL4006
failure-threshold: warning
no-color : false
no-fail: true
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Azure Docker metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.revision=${{ env.SHA }}
tags: |
type=edge,branch=$repo.default_branch
type=semver,pattern=v{{version}}
type=sha,prefix=,suffix=,format=short
- name: Azure Build & Push Docker image
uses: docker/build-push-action@v5
with:
context: azure/
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Azure Docker Scout
id: docker-scout
uses: docker/scout-action@v1
with:
image: ${{ steps.metadata.outputs.tags }}
command: cves
ignore-unchanged: true
only-severities: critical,high,medium,low,unspecified
only-fixed: true
GCP Docker Image YAML (docker_gcp_image.yml)
name: GCP Build and publish a Docker image
on:
push:
branches:
- '*'
env:
REGISTRY: devtoolhub
IMAGE_NAME: gcp_cli
COMPARE_TAG: latest
SHA: ${{ github.event.after }}
jobs:
build:
name: GCP Build & push docker image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ env.SHA }}
- name: Debug
run: |
echo "github.ref -> {{ github.ref }}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=moby/buildkit:v0.13.0
- name: lint Action for GCP
uses: hadolint/[email protected]
with:
dockerfile: gcp/Dockerfile
ignore: DL3018,SC2046,DL4006
failure-threshold: warning
no-color : false
no-fail: true
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: GCP Docker metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.revision=${{ env.SHA }}
tags: |
type=edge,branch=$repo.default_branch
type=semver,pattern=v{{version}}
type=sha,prefix=,suffix=,format=short
- name: GCP Build & Push Docker image
uses: docker/build-push-action@v5
with:
context: gcp/
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Docker Scout
id: docker-scout
uses: docker/scout-action@v1
with:
image: ${{ steps.metadata.outputs.tags }}
command: cves
ignore-unchanged: true
only-severities: critical,high,medium,low,unspecified
only-fixed: true
Explanation of YAML File Steps
- Checkout: This step checks out the codebase from the repository.
- Debug: Displays the GitHub reference being used for the workflow.
- Set up QEMU: Sets up QEMU for cross-platform builds.
- Set up Docker Buildx: Sets up Docker Buildx for multi-platform builds.
- Lint Action for AWS/Azure/GCP: Uses Hadolint to lint Dockerfiles, ignoring certain rules.
- Log in to Docker Hub: Authenticates with Docker Hub using provided credentials.
- Docker Metadata: Generates metadata for Docker image including tags and labels.
- Build & Push Docker image: Builds Docker image and pushes it to Docker Hub.
- Docker Scout: Scans the Docker image for vulnerabilities using Docker Scout.
Docker Hub URLs
- Azure CLI Docker Hub URL: devtoolhub/azure_cli
- AWS CLI Docker Hub URL: devtoolhub/aws_cli
- GCP CLI Docker Hub URL: devtoolhub/gcp_cli
Conclusion
In this tutorial, we have set up a GitHub Actions pipeline to automate the building and publishing of Docker images for AWS CLI, Azure CLI, and GCP CLI. By leveraging GitHub Actions, you can streamline your CI/CD processes and ensure the consistency and reliability of your Docker images.