CI Workflow: Build & Push Docker Image To GHCR

by SLV Team 47 views
CI Workflow: Build & Push Docker Image to GHCR

Hey guys! Let's dive into setting up a slick CI workflow that automatically builds and pushes our Docker image to ghcr.io. Right now, we're missing a CI workflow that handles the automatic build and push of our Docker image to ghcr.io. This is super important because it automates the process for both releases and development builds, ensuring we always have up-to-date images. I will walk you through how to implement this feature, building upon our discussions in issue #474.

Workflow Overview

This workflow will be designed to trigger under several conditions, ensuring that our Docker images are always up-to-date and properly tagged. Here’s a breakdown:

  • Release Creation: When a new release is created, the workflow will automatically build and push the Docker image tagged with the release name. This is crucial for maintaining stable and versioned images.
  • Push to development Branch: Any push to the development branch will trigger the workflow to build and push the image tagged as latest. This keeps our development environment running on the cutting edge.
  • Manual Trigger (workflow_dispatch): We’ll also include an option to manually trigger the workflow using workflow_dispatch. This is handy for on-demand builds and pushes.

Example Image Tags:

  • ghcr.io/bb-Ricardo/netbox-sync:v1.0.0 (for releases)
  • ghcr.io/bb-Ricardo/netbox-sync:latest (for development)

Setting Up the CI Workflow

Let's break down the steps to create this CI workflow. We'll use GitHub Actions for this, as it's tightly integrated with GitHub and provides a seamless experience. This detailed walkthrough ensures that even if you're new to CI/CD, you can follow along and get everything set up correctly.

Step 1: Create the Workflow File

First, we need to create a new workflow file in our repository. Create a file named .github/workflows/docker-image.yml. This file will define our CI workflow.

Step 2: Define the Workflow Triggers

Next, we'll define when this workflow should run. As mentioned earlier, we want it to trigger on release creation, pushes to the development branch, and manual triggers. Add the following to your docker-image.yml file:

name: Docker Image CI

on:
  release:
    types: [created]
  push:
    branches:
      - development
  workflow_dispatch:
  • name: Docker Image CI: This sets the name of our workflow, which will be displayed in the GitHub Actions UI.
  • on:: This section defines the triggers for the workflow.
    • release:: Triggers the workflow when a new release is created.
      • types: [created]: Specifies that the workflow should only run when a release is created.
    • push:: Triggers the workflow on pushes to specific branches.
      • branches:: Specifies the branches to watch for pushes.
        • - development: The workflow will run when changes are pushed to the development branch.
    • workflow_dispatch:: Allows the workflow to be manually triggered.

Step 3: Define the Jobs

Now, let's define the jobs that will run as part of this workflow. We'll have a single job called build-and-push that builds the Docker image and pushes it to GHCR. Add the following to your docker-image.yml file:

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to GHCR
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker builder
        id: meta
        uses: docker/metadata-action@v4
        with:
          flavor: latest
          from_repo: true
          versioning: | 
            latest: type=ref,event=branch
            vX.Y.Z: type=semver,pattern=v((?P<version>\d+.\d+.\d+))
            vX.Y: type=semver,pattern=v((?P<version>\d+.\d+))
            vX: type=semver,pattern=v((?P<version>\d+))

      - name: Build and push Docker image
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Let's break down each step:

  • runs-on: ubuntu-latest: Specifies that the job will run on an Ubuntu-based virtual machine.
  • steps:: This section defines the steps that will be executed in the job.
    • name: Checkout code: Checks out the repository code into the virtual machine.
      • uses: actions/checkout@v3: Uses the official actions/checkout action to perform the checkout.
    • name: Set up Docker Buildx: Sets up Docker Buildx, which allows us to build multi-architecture Docker images.
      • uses: docker/setup-buildx-action@v2: Uses the docker/setup-buildx-action action to set up Buildx.
    • name: Login to GHCR: Logs in to GitHub Container Registry (GHCR).
      • uses: docker/login-action@v2: Uses the docker/login-action action to log in.
      • with:: Specifies the configuration options for the login action.
        • registry: ghcr.io: Specifies the registry to log in to.
        • username: ${{ github.actor }}: Uses the github.actor context variable to get the username.
        • password: ${{ secrets.GITHUB_TOKEN }}: Uses the GITHUB_TOKEN secret to authenticate.
    • name: Extract metadata (tags, labels) for Docker builder: Extracts metadata for the Docker image, such as tags and labels.
      • id: meta: Sets an ID for this step, allowing us to reference its outputs later.
      • uses: docker/metadata-action@v4: Uses the docker/metadata-action action to extract metadata.
      • with:: Specifies the configuration options for the metadata action.
        • flavor: latest: Use the default metadata logic.
        • from_repo: true: Infer the source repository.
        • versioning: Define the versioning rules.
    • name: Build and push Docker image: Builds and pushes the Docker image to GHCR.
      • uses: docker/build-push-action@v3: Uses the docker/build-push-action action to build and push the image.
      • with:: Specifies the configuration options for the build and push action.
        • context: .: Sets the build context to the root of the repository.
        • push: true: Enables pushing the image to the registry.
        • tags: ${{ steps.meta.outputs.tags }}: Uses the tags generated by the metadata action.
        • labels: ${{ steps.meta.outputs.labels }}: Uses the labels generated by the metadata action.

Step 4: Commit and Push the Workflow File

Now that we've defined our workflow file, commit it to the repository and push it to GitHub. This will automatically trigger the workflow based on the defined triggers.

git add .github/workflows/docker-image.yml
git commit -m "Add CI workflow to build and push Docker image to GHCR"
git push origin development

Verifying the Workflow

To verify that the workflow is working correctly, you can either create a new release, push changes to the development branch, or manually trigger the workflow. Here’s how to manually trigger the workflow:

  1. Go to your repository on GitHub.
  2. Click on the "Actions" tab.
  3. Select the "Docker Image CI" workflow.
  4. Click on the "Run workflow" button.
  5. Click on the "Run workflow" button again to confirm.

This will trigger the workflow, and you can monitor its progress in the Actions tab. Once the workflow completes successfully, you should see the Docker image in your GHCR repository.

Best Practices and Considerations

When setting up and maintaining CI workflows, it's important to follow some best practices to ensure everything runs smoothly:

  • Use Secrets: Avoid hardcoding sensitive information like passwords and API keys in your workflow files. Instead, use GitHub Secrets to securely store and access this information.
  • Monitor Workflow Runs: Regularly monitor your workflow runs to identify and address any issues. GitHub Actions provides detailed logs and reports to help you troubleshoot problems.
  • Keep Dependencies Up-to-Date: Regularly update your workflow dependencies to ensure you're using the latest versions and security patches.
  • Test Your Workflow: Before deploying your workflow to production, test it thoroughly to ensure it behaves as expected.

Final Thoughts

Implementing a CI workflow to automatically build and push Docker images to GHCR is a game-changer for streamlining our development and release processes. By automating these tasks, we reduce the risk of human error, ensure consistency across environments, and free up valuable time for more strategic work. Following these steps and best practices, you'll have a robust CI pipeline that keeps your Docker images up-to-date and readily available. Happy building, and let me know if you have any questions or run into any snags along the way!