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

DigitalOcean Kubernetes (DOKS) is a managed Kubernetes service that lets you deploy Kubernetes clusters without the complexities of handling the control plane and containerized infrastructure. Clusters are compatible with standard Kubernetes toolchains and integrate natively with DigitalOcean Load Balancers and block storage volumes.

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

The workflow consists of the following steps:

  1. Create your workflow file

  2. Define your workflow actions

  3. Run your workflow

Prerequisites

Before you can create a CI/CD workflow using DigitalOcean services:

Create Your Workflow File

In your GitHub repository, click Actions. You can choose one of the provided templates to create a workflow. For this example, we will set up the workflow by clicking set up a workflow yourself.

Create workflow yaml

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

Configure Actions in Your Workflow

In the workflow.yml file, configure the following actions for your workflow:

  1. Specify events that trigger workflow
  2. Create workflow run
  3. Specify steps in job

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

Specify Events that Trigger Workflow

In the first section of the workflow.yml file, specify 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. You 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.

Create 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. These are specified using the runs-on and steps keywords. For this example, we write a single build job.

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

Specify 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 performs the following steps:

  1. Checks out your repository under $GITHUB_WORKSPACE so that the job can access it.
steps:
- name: Checkout master
  uses: actions/[email protected]

$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.

  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 as a GitHub secret as a prerequisite.
- name: Install doctl
  uses: digitalocean/[email protected]
  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.
- name: Build container image
  run: docker build -t registry.digitalocean.com/<registry-name>/<repository_name>:$(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 registry.digitalocean.com/<registry-name>/<repository_name>:$(echo $GITHUB_SHA | head -c7)

We build 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. To build and push your image, specify the name of your registry and repository in the commands.

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.

  1. Deploys to your DigitalOcean Kubernetes cluster.
- name: Update deployment file
  run: TAG=$(echo $GITHUB_SHA | head -c7) && sed -i 's|<IMAGE>|registry.digitalocean.com/<registry-name>/<repository_name>:'${TAG}'|' $GITHUB_WORKSPACE/config/deployment.yml

- name: Save DigitalOcean kubeconfig with short-lived credentials
  run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 <cluster-name>

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

- name: Verify deployment
  run: kubectl rollout status deployment/<deployment_name>

We provide a deployment.yml file that only has a placeholder for the Docker image, IMAGE, we want to deploy. Before we can deploy the image to the DigitalOcean Kubernetes cluster, we need to update it to point to the image we tagged and pushed to the container registry. To do this, we use the standard UNIX tools and sed to update the contents of our deployment file.

Then, we add the credentials for the cluster we integrated with the registry, <cluster-name>, as a prerequisite to a local kubeconfig file, deploy to the cluster and verify the deployment. <deployment_name> is the name of the deployment specified in the deployment.yml file.

To deploy to your cluster, specify the name of your registry, repository and cluster integrated with your registry in the commands.

Run Your Workflow

Once you complete configuring the steps for your workflow run in the workflow.yml file, add a commit message and commit the changes to your GitHub repository. This commit triggers the workflow. Each step runs in the order specified in the workflow.

You can monitor the progress of the workflow run by clicking All workflows and selecting the name of the workflow in the Actions tab. 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.

Next Steps

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

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 your changes get re-deployed.