How to Deploy to DigitalOcean Kubernetes with GitHub Actions

In this post, I will document how I automate deploying my docker images to Digital Ocean Kubernetes using GitHub actions.

Create Digital Ocean API Token

We need to have a Digital Ocean personal token to give the Github action access to the Kubernetes cluster. It can be created from here. The expiration needs to be set to “No expiry” for this automation to keep working in the future.

After the token is generated, we need to use it in the Github action script, but to avoid having the token in plain text in the Github script, we store it in the Github repository’s secret, and you can do that from:

https://github.com/{username}/{repo-name}/settings/secrets/actions/new

The name will be used in the GitHub action script.

Install Digital Ocean Commandline (doctl)

This can be done easily using this step code.

- name: Install doctl
  uses: digitalocean/action-doctl@v2
  with:
    token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

Saving Kubernetes Cluster

- name: Save DigitalOcean kubeconfig
  run: doctl kubernetes cluster kubeconfig save the-cluster-id

Rolling out the deployment

# Kubernetes rollout the latest image
- name: Kubernetes rollout the latest image
  run: kubectl -n {namespace} rollout restart deployment {deployment-name}

Those were the minimum steps that are needed to get the auto-deploying working, but in my production setup, I do more steps including building the image with the right tag and deploying it to the staging/production cluster depending on the branch name.

Full example of microservice Github action yml file.

# This is a basic workflow to help you get started with Actions

name: docker push and build

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [master, develop]
    tags:
      - "v*"
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v3
        with:
          # list of Docker images to use as base name for tags
          images: |
            docker-id/image-name

          # generate Docker tags based on the following events/attributes
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}

      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Install doctl
        uses: digitalocean/action-doctl@v2
        with:
          token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

      # Save the right kuberenetes context depending on the branch name
      - name: Save DigitalOcean kubeconfig Staging
        if: github.ref == 'refs/heads/develop'
        run: doctl kubernetes cluster kubeconfig save qikfgax1-qikfgax1-aszz-qweqw-bb53721318

      # Save the right kuberenetes context depending on the branch name
      - name: Save DigitalOcean kubeconfig Production
        if: github.ref == 'refs/heads/master'
        run: doctl kubernetes cluster kubeconfig save qikfgax1-3ddc-12312-5561-12341321

      # Kubernetes rollout the latest image
      - name: Kubernetes rollout the latest image
        run: kubectl -n karma-stats rollout restart deployment karma-stats