CI/CD with Github Actions and Argo CD
Now that we’ve built and deployed our site. Lets setup some simple CI/CD to help speed up development and content creation (i.e. blog posts).
Github Actions
Since this is a small personal project with minimal dependencies, Github Actions is a great choice and takes advantage of free compute.
First lets setup a simple buildAndPush job that triggers off our main and develop branches. It also includes the option to manually trigger for other branches if needed.
name: buildAndPush
on:
push:
branches:
- develop
- main
paths-ignore:
- '**/readme.md'
# allows manual dispatch
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
...Our job needs to:
- generate build
- provision docker (buildx, login to registry)
- build image
- push image
First some boilerplate to setup our environment.
steps:
- name: set env vars
run: |
echo "SHA=${GITHUB_SHA}" >> $GITHUB_ENV
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v2Install Hugo and generate our build.
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.90.1'
- name: Build
run: cd site && hugo --minifySetup buildx for multi-arch images.
- name: Set up QEMU
uses: docker/setup-qemu-action@v1.2.0
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1.6.0
with:
version: latestLastly, a simple build and push task using the github envs we setup earlier.
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v6
tags: |
csbull55/cbull-dev:${{ env.GITHUB_REF_NAME }}-latest
csbull55/cbull-dev:${{ env.GITHUB_REF_NAME }}-${{ env.SHA }}
push: trueNow whenever we push/merge code to the develop or main branch, this job will build and push a docker image to our remote repository for the respective branch.
Argo CD
Next we’ll use Argo CD to sync new builds with the state on the cluster.
From Argo’s site:
What is Argo CD?
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
Argo CD works by monitoring running applications in the cluster and compares them with the target state you’ve defined in git. When it detects it’s out of sync (i.e. you’ve pushed updated manifests), Argo automatically syncs the app on the cluster to match that target.
Let’s setup a simple Argo CD app and register it. I typically use the UI and grab the outputted yaml spec to throw in git.
project: default
source:
repoURL: 'https://github.com/Christian-Bull/cbull-dev-infra.git'
path: manifests
targetRevision: main
destination:
server: 'https://kubernetes.default.svc'
namespace: cbull-dev
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=trueThis sets up our source repo and defines the path and branch to watch for changes on.
Once created, lets ensure it’s healthy.
➜ ~ argocd app get cbull-dev
Name: cbull-dev
Project: default
Server: https://kubernetes.default.svc
Namespace: cbull-dev
URL: http://localhost:8080/applications/cbull-dev
Repo: https://github.com/Christian-Bull/cbull-dev-infra.git
Target: main
Path: manifests
SyncWindow: Sync Allowed
Sync Policy: Automated (Prune)
Sync Status: Synced to main (3982373)
Health Status: Healthy
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service cbull-dev cbull-dev Synced Healthy service/cbull-dev unchanged
apps Deployment cbull-dev cbull-dev Synced Healthy deployment.apps/cbull-dev configured
extensions Ingress cbull-dev cbull-dev Synced Healthy ingress.extensions/cbull-dev unchangedFinishing up
Now that we’ve switched to defining the state of our manifests in git, we need to find a way to update the image reference when we release updates.
While there may be a more elegant way to achieve this, I made a simple deployment template with a filler value in the image reference and use sed to generate the final deployment spec.
containers:
- name: cbull-dev
image: csbull55/cbull-dev:SED_imageNameLet’s add a quick deployment job on the app repository to generate the manifest and commit it to our infra repo.
name: deploy
on:
workflow_run:
workflows: ["buildAndPush"]
branches: [main]
types:
- completed
jobs:
on-success:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
repository: Christian-Bull/cbull-dev-infra
token: ${{ secrets.CBULL_PAT }}
- name: set env vars
run: |
echo "SHA=${GITHUB_SHA}" >> $GITHUB_ENV
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: update deployment spec
run: sed 's/SED_imageName/${{ env.GITHUB_REF_NAME }}-${{ env.SHA }}/g' manifests/.templates/deployment.yml > manifests/deployment.yml
- name: Create Pull Request
uses: EndBug/add-and-commit@v7
with:
branch: main