The DigitalOcean Container Registry (DOCR) is a private Docker image registry that lets you store and manage private container images. DOCR integrates natively with Docker environments and DigitalOcean Kubernetes 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:
Before you can create a CI/CD workflow using DigitalOcean services, do the following:
Create a DigitalOcean Container Registry and add the registry name as a secret to your GitHub repository. Name the secret REGISTRY_NAME
.
Create a DigitalOcean Kubernetes cluster and add the cluster name as a secret to your GitHub repository. Name the secret CLUSTER_NAME
.
Create a DigitalOcean access token for your container registry and add it as a secret to your GitHub repository. Name the secret DIGITALOCEAN_ACCESS_TOKEN
.
Integrate your DigitalOcean Container Registry with your DigitalOcean Kubernetes cluster in the control panel or using doctl
:
doctl kubernetes cluster registry add <cluster-name>
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:
git@github.com:digitalocean/sample-push-to-deploy-doks.git
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.
This creates a template YAML file in the .gitub/workflows
folder. Rename main.yml
to workflow.yml
.
The workflow.yml
file configures the following actions for the workflow:
For more information on the syntax to write the actions, see Workflow syntax for GitHub Actions.
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.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:
....
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:
$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
doctl
command-line client using DigitalOcean doctl Action.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.
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)
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
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.
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.
When you no longer need the resources created in this tutorial, you can delete the DOKS cluster and container registry.
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
You can expose your deployment to the world by adding a load balancer as described in Add Load Balancers.