Enable Push-to-Deploy on DigitalOcean Kubernetes Using GitHub Actions

The DigitalOcean Container Registry (DOCR) is a private Docker image registry with additional tooling support that enables integration with your Docker environment and DigitalOcean Kubernetes clusters. DOCR registries are private and co-located in the datacenters where DigitalOcean Kubernetes clusters are operated for secure, stable, and performant rollout of images to your clusters.


You can create continuous integration and continuous deployment (CI/CD) workflows with DigitalOcean services using GitHub Actions. In this tutorial, you learn how to deploy a Python application to a DigitalOcean Kubernetes cluster whenever you commit a change to your GitHub repository.

The workflow consists of the following steps:

  1. Creating workflow file

  2. Defining workflow actions

  3. Running workflow

Note
Following the steps below may result in charges for the use of DigitalOcean resources. Delete the resources to avoid being billed for additional resources.

Prerequisites

Before you can create a CI/CD workflow using DigitalOcean services, do the following:

doctl kubernetes cluster registry add <cluster-name>

STEP 1: Cloning the Sample GitHub Repository

We provide a sample repository that has a Python app that generates a “hello world” message and other files used in the tutorial. You can clone the repository using the following command:

[email protected]:digitalocean/sample-push-to-deploy-doks.git

STEP 2: Creating the Workflow File

The file named workflow.yaml in the sample GitHub repository defines the triggers, jobs and steps for the workflow.

You can create your own workflow file in your GitHub repository. Click Actions and choose one of the provided templates. To create a custom workflow, click set up a workflow yourself.

Create workflow yaml

This creates a template YAML file in the .gitub/workflows folder. Rename main.yml to workflow.yml.

STEP 3: Configuring Actions in the Workflow

The workflow.yml file configures the following actions for the workflow:

  1. Events that trigger workflow
  2. Workflow run
  3. Steps in job

For more information on the syntax to write the actions, see Workflow syntax for GitHub Actions.

Specifying Events that Trigger Workflow

The first section of the workflow.yml file specifies the conditions under which the workflow gets triggered. In this example, the workflow is triggered on a push to the main branch of the repository if specific files or folders are changed.

on:
  push:
    branches:
      - main
    paths:
      - 'config/**'
      - 'server.py'
      - 'Dockerfile'
      - '.github/workflows/**'

The on keyword specifies the name of the GitHub event which triggers the workflow, which is push in this case. We specify the configuration for the push event using the following keywords:

  • branches – The workflow triggers only on a push to the main branch.
  • paths – The workflow triggers when there is a change in server.py, Dockerfile, the deployment YAML file in config folder or the workflow YAML file in the workflow folder in the repository.

Creating Workflow Run

A workflow run is made up of one or more jobs that can run sequentially or in parallel. It specifies the type of machine where the job runs and several steps to represent a sequence of tasks that will be executed as part of the job. We specify these using the runs-on and steps keywords in a single build job.

jobs:
 build:
   runs-on: ubuntu-latest
   steps:
   ....

Specifying Steps in Job

A step is an individual task that can run commands in a job. A step has a uses or a run keyword to run an action or a shell command, and optionally a name keyword. The build job in this example does the following:

  1. Checks out your repository under $GITHUB_WORKSPACE so that the job can access it.

$GITHUB_WORKSPACE is one of the environment variables in the Action’s runtime environment. This directory contains a copy of the repository that triggered the workflow. Changes made here persist from one step to the next.

steps:
- name: Checkout master
  uses: actions/checkout@main
  1. Installs the doctl command-line client using DigitalOcean doctl Action.
    This action enables you to interact with DigitalOcean services. It uses DIGITALOCEAN_ACCESS_TOKEN you added previously as a secret to the GitHub repository.
- name: Install doctl
  uses: digitalocean/action-doctl@v2
  with:
    token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

doctl is now available in the virtual environment and can be used directly in the following steps.

  1. Builds the Docker image and pushes it to your container registry.

This example builds the Docker image with the $GITHUB_SHA tag, which is another environment variable in the Action’s runtime environment. Its value is the SHA of the commit that triggered the workflow. REGISTRY_NAME is the name of your DigitalOcean Container Registry you added to the GitHub repository as a secret previously. python-example is the name of the repository in your container registry.

Before we can push the tagged image, we log into the container registry. We pass the --expiry-seconds flag to generate temporary, short-lived credentials that will be revoked when the job is complete. We then push the tagged image to the container registry.

- name: Build container image
  run: docker build -t ${{ secrets.REGISTRY_NAME }}/python-example:$(echo $GITHUB_SHA | head -c7) .

- name: Log in to DigitalOcean Container Registry with short-lived credentials
  run: doctl registry login --expiry-seconds 1200

- name: Push image to DigitalOcean Container Registry
  run: docker push ${{ secrets.REGISTRY_NAME }}/python-example:$(echo $GITHUB_SHA | head -c7)
  1. Deploys to your DigitalOcean Kubernetes cluster.

The deployment.yml file in the sample repository only has a placeholder for the Docker image, IMAGE, to deploy. Before we can deploy the image to the DigitalOcean Kubernetes cluster, we need to update it to point to the image pushed to your container registry. To do this, we use the standard UNIX tools and sed to update the contents of the deployment file.

Then, we add the credentials for the cluster to a local kubeconfig file, deploy to the cluster and verify the deployment. CLUSTER_NAME is the name of the DigitalOcean Kubernetes cluster you added to the GitHub repository as a secret previously. python-example is the name of the deployment specified in the deployment.yml file.

- name: Update deployment file
  run: TAG=$(echo $GITHUB_SHA | head -c7) && sed -i 's|<IMAGE>|${{ secrets.REGISTRY_NAME }}/python-example:'${TAG}'|' $GITHUB_WORKSPACE/config/deployment.yml

- name: Save DigitalOcean kubeconfig with short-lived credentials
  run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 ${{ secrets.CLUSTER_NAME }}

- name: Deploy to DigitalOcean Kubernetes
  run: kubectl apply -f $GITHUB_WORKSPACE/config/deployment.yml

- name: Verify deployment
  run: kubectl rollout status deployment/python-example

STEP 4: Running Your Workflow

Go to the Actions tab in your GitHub repository, click on a workflow run and click Re-run jobs. Each step runs in the order specified in the workflow. Alternatively, you can edit any file in your repository and commit the changes to the repository. This commit triggers the workflow.

You can monitor the workflow run by clicking All workflows and selecting the name of the workflow. Under Jobs, click build.

Click to expand a step and view the results of that step.

GitHub Actions progress

Once everything is green, your application is live at http://<external-endpoint>, where external-endpoint is the External Endpoint of the service that you can obtain from the Kubernetes dashboard of your cluster.

Any time you make a change to your app and push a commit to the main branch of your GitHub repository, the GitHub Actions workflow triggers and the changes get re-deployed.

STEP 5: Deleting the Resources

When you no longer need the resources created in this tutorial, you can delete the DOKS cluster and container registry.

Summary

In this tutorial, you integrated a DigitalOcean Container Registry with a DigitalOcean Kubernetes cluster and set up a CI/CD workflow using GitHub Actions to deploy a Python application. You can create your own Dockerfile to build the image for your application and use the same workflow to deploy other applications. You completed the following prerequisites for the tutorial:

  • Created a DigitalOcean Container Registry and DOKS cluster

  • Created a DigitalOcean access token

  • Integrated the container registry with a DOKS cluster

What’s Next?

You can expose your deployment to the world by adding a load balancer as described in Add Load Balancers.