DEV Community

Cover image for Beginner’s Guide: Build, Push, and Deploy Docker Image with GitHub Actions
Md. Abu Raihan Srabon
Md. Abu Raihan Srabon

Posted on

Beginner’s Guide: Build, Push, and Deploy Docker Image with GitHub Actions

In this post, we’ll introduce GitHub Actions and explain how to use them for automating Docker image builds, pushing images to a self-hosted registry, and deploying them to a remote server. This guide is tailored for beginners who want to start simple and expand their knowledge over time.

  1. What’s GitHub Actions?

GitHub Actions is a powerful tool for automating software workflows directly within your GitHub repository. It allows you to build, test, and deploy your code directly from GitHub. You define your automation tasks as YAML files within your repository, and these tasks run on GitHub’s hosted servers (or self-hosted runners if you prefer).

Why use GitHub Actions?

  • Seamless integration with GitHub repositories.
  • Customization: Create workflows tailored to your project needs.
  • Ease of use: Simple YAML configuration.
  1. What This Script Does

The given GitHub Actions script automates the CI/CD pipeline for building, tagging, and pushing a Docker image to a self-hosted registry, then deploying it to a remote server. Let’s dive into the main sections of the script and understand how each part works.

a. Checking Out the Code

- name: Checkout Code
  uses: actions/checkout@v3
Enter fullscreen mode Exit fullscreen mode

This step clones the repository into the GitHub Actions runner, enabling the workflow to access your project files.

b. Setting Up Docker Buildx

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v2
Enter fullscreen mode Exit fullscreen mode

Docker Buildx allows the runner to build multi-platform images and use advanced build features.

c. Configuring and Logging into the Docker Registry

- name: Add Registry to /etc/hosts
  run: |
    echo "${{ secrets.HOSTS_ENTRY }}" | sudo tee -a /etc/hosts

- name: Configure Docker for Insecure Registry
  run: |
    sudo mkdir -p /etc/docker
    echo '{ "insecure-registries": ["https://harbor.example.com"] }' | sudo tee /etc/docker/daemon.json
    sudo systemctl restart docker

- name: Log in to Docker Registry
  uses: docker/login-action@v2
  with:
    registry: harbor.example.com
    username: ${{ secrets.DOCKER_USERNAME }}
    password: ${{ secrets.DOCKER_PASSWORD }}
Enter fullscreen mode Exit fullscreen mode

These steps set up Docker on the runner to connect to the self-hosted Harbor registry. It configures Docker to treat the registry as an insecure source (use this cautiously) and logs in using provided credentials.

d. Tagging with a Date-Time-Based Version

- name: Generate Date-Time-Based Tag
  id: generate_tag
  run: |
    new_version=$(date -u +"v%Y.%m.%d.%H%M%S")
    echo "Generated tag: $new_version"
    echo "version=$new_version" >> $GITHUB_ENV
Enter fullscreen mode Exit fullscreen mode

This step creates a version tag based on the current UTC date and time, ensuring unique version identifiers for each image build.

e. Building and Pushing the Docker Image

- name: Build Docker Image
  run: |
    PROJECT_NAME=$(echo "${GITHUB_REPOSITORY}" | cut -d'/' -f2)
    docker build -f .docker/Dockerfile \
      -t harbor.example.com/${{ vars.PROJECT_NAME }}/$PROJECT_NAME:${{ env.version }} -t harbor.example.com/${{ vars.PROJECT_NAME }}/$PROJECT_NAME:latest .
  env:
    GITHUB_REPOSITORY: ${{ github.repository }}

- name: Push Docker Image
  run: |
    PROJECT_NAME=$(echo "${GITHUB_REPOSITORY}" | cut -d'/' -f2)
    docker push harbor.example.com/${{ vars.PROJECT_NAME }}/$PROJECT_NAME:${{ env.version }}
    docker push harbor.example.com/${{ vars.PROJECT_NAME }}/$PROJECT_NAME:latest
  env:
    GITHUB_REPOSITORY: ${{ github.repository }}
Enter fullscreen mode Exit fullscreen mode

This section builds the Docker image using the Dockerfile and tags it with both the generated version and latest. It then pushes the images to the Harbor registry.

f. Deploying to a Remote Server

- name: Deploy to Remote Server
  if: success()
  env:
    SSH_HOST: ${{ secrets.SSH_HOST }}
    SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
    SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
    DEPLOY_COMMANDS: ${{ secrets.DEPLOY_COMMANDS }}
  run: |
    echo "${SSH_PRIVATE_KEY}" > /tmp/private_key
    chmod 600 /tmp/private_key
    ssh -o StrictHostKeyChecking=no -i /tmp/private_key ${SSH_USERNAME}@${SSH_HOST} "${DEPLOY_COMMANDS}"
  shell: bash
Enter fullscreen mode Exit fullscreen mode

Finally, this step connects to a remote server via SSH and runs the deployment commands specified in the GitHub secret DEPLOY_COMMANDS. This helps automate the release process.

Below is an image of the complete GitHub Actions script:

Image description

  1. What We Have Accomplished by Running This Script

By running this GitHub Actions workflow, we have:

  • Automated the process of checking out code and setting up Docker on a GitHub-hosted runner.
  • Built a Docker image from the code and tagged it with both a version and latest.
  • Pushed the Docker image to a self-hosted Harbor registry.
  • Deployed the image to a remote server using secure SSH commands.

This streamlines the CI/CD process, making development and deployment faster and more reliable.

  1. Link to GitHub Gist

For an easy reference and to adapt this workflow to your needs, you can find the complete script here on GitHub Gist.

Feel free to use this template as a starting point for automating your Docker workflows and deployment pipelines. With GitHub Actions, you can achieve seamless automation with just a few configuration steps!

Top comments (0)