After writing Making the Leap into DevOps and Using Github Actions To Test Before You Deploy, I decided that using Github to manage Kubernetes was my next step. Up until this point, I had a collection of random YAML files sitting on a Linux machine that was backed up.
Trying to maintain random YAML files was not working anymore so I needed a different way to manage my Kubernetes. I decided to move my configurations into Github. I then used Github Actions to make my changes live in my Kubernetes cluster.
Kubernetes Deployment
This part was pretty simple. I started with just a simple Ubuntu instance running in my default
namespace. The deployment YAML is below
apiVersion: apps/v1
kind: Deployment
metadata:
generation: 1
labels:
apps: ubuntu
name: ubuntu
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: ubuntu
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: ubuntu
namespace: default
spec:
containers:
- command:
- /bin/sleep
- 3651d
env:
- name: MY_SERVICE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
image: ubuntu:latest
imagePullPolicy: Always
name: ubuntu
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
This is a simple deployment that will deploy ubuntu and run the sleep command for 3651 days. This is one of those random hacks I use that maybe I should document similar to my Using Docker Instead of Virtual Environments (venv) post but that’s for another day. In short, it allows me to have a Linux machine in Kubernetes in case I need to test out anything.
I called this file default-ubuntu_deployment.yaml
and added it to the config
directory of my Github repo. I’m using this naming convention to help my Github Action figure out what to do with the YAML. The naming convention used here is <K8 Namespace>-<K8 Name>_<K8 Type>.yaml
so that I can use a central Github Action to manage all of Kubernetes deployments.
Setting Up Github Actions
The Kubernetes YAML is pretty simple so now we move onto the Github Actions.
Reusable Github Action
I started with a Github Action that I can reuse for other deployments in the future. I called this file do-k8-apply.yml
and placed it in the .github/workflows
directory of my repo.
name: Build, push, and deploy
# Controls when the action will run.
on:
workflow_call:
inputs:
k8-name:
required: true
type: string
k8-type:
required: true
type: string
k8-namespace:
required: false
type: string
default: default
secrets:
local_cluster_name:
required: true
local_token:
required: true
# A workflow run is made up of one or more jobs that can run sequentially or in parallel.
jobs:
# This workflow contains a single job called "build".
build:
# The type of runner that the job will run on.
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it.
- name: Checkout master
uses: actions/checkout@main
# Install doctl.
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.LOCAL_TOKEN }}
- name: Save DigitalOcean kubeconfig with short-lived credentials
run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 ${{ secrets.LOCAL_CLUSTER_NAME }}
- name: Deploy to Kubernetes
id: k8-deploy
run: kubectl apply -f $GITHUB_WORKSPACE/config/${{ inputs.K8-NAMESPACE }}-${{ inputs.K8-NAME }}_${{ inputs.K8-TYPE }}.yaml
- name: Verify deployment
run: kubectl -n ${{ inputs.K8-NAMESPACE }} rollout status ${{ inputs.K8-TYPE }}/${{ inputs.K8-NAME }}
This workflow makes use of three input variables
- k8-name
- k8-type
- k8-namespace
I’ve already set the default value of k8-namespace
to default
so it isn’t a required input. The other two variables have no default value so they are required. I also changed the run
lines for Deploy to Kubernetes
and Verify deployment
to leverage the variables that I’ve defined. Other than these changes, the Github Action is similar to what was already provided in Enable Push-to-Deploy on DigitalOcean Kubernetes Using GitHub Actions.
Deployment Specific Github Action
The next step was to create another Action that will be triggered whenever I make changes to my Ubuntu deployment. I called this file ubuntu.yml
and placed it in the .github/workflows
of the repo.
name: Build, push, and deploy
# Controls when the action will run.
on:
# Triggers the workflow on push request on the main branch for changes in the specified paths.
push:
branches:
- main
paths:
- 'config/default-ubuntu_deployment.yaml'
- '.github/workflows/ubuntu.yml'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel.
jobs:
# This workflow contains a single job called "build".
deploy:
uses: ./.github/workflows/do-k8-apply.yml
with:
k8-name: ubuntu
k8-type: deployment
secrets:
local_token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
local_cluster_name: ${{ secrets.CLUSTER_NAME }}
This starts with an on
statement that looks for any pushes to the main
branch. These pushes would require changes to the paths
specified. In short, this will execute whenever I change this yml file or the default-ubuntu_deployment.yaml
that I created above.
The jobs
section contains a job definition called deploy
that makes use of the do-k8-apply.yml
created above. We supply that with values for the k8-name
and k8-type
variables.
Putting It All Together
Committing a change to the main
branch of my repo that makes a change to either of the following files:
- config/default-ubuntu_deployment.yaml
- .github/workflows/ubuntu.yml
will trigger the following commands
- kubectl apply -f config/default-ubuntu_deployment.yaml
- kubectl -n default rollout status deployment/ubuntu
It’s a simplistic way of managing my Kubernetes in Github but now I can build upon this for future deployments.