Skip to main content

ArgoCD

We've gone a long ways now to having builds which we can use and deploy on Kubernetes. It's been a journey but we are almost there. Now we will use ArgoCD to automatically deploy our builds.

GitHub Manifest

Code

Create a GitHub repository to house the ArgoCD manifest. This example uses argocd-example.

The recommended directory structure is:

info
.github
workflows
clock-staging.yml
clock-production.yml
staging
clock
application.yaml
templates
deployment.yaml
production
clock
application.yaml
templates
deployment.yaml

For this repository, you don't necessarily need a develop branch. GitHub will do most of the automation work so having a single main branch is fine.

Repository Settings

Ensure GitHub Actions are properly configured. Check "Allow all actions and reusable workflows" and set Workflow permissions to "Read and write permissions".

Application Templates

The application.yaml file tells ArgoCD how to run the application deployment and includes information for pushing Slack notifications. Key points:

  • Replace repoURL with your specific username (this example uses a placeholder username only)
  • Ensure a namespace called "example" exists on your Kubernetes cluster
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: clock
namespace: argocd
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: staging
notifications.argoproj.io/subscribe.on-sync-failed.slack: staging
notifications.argoproj.io/subscribe.on-sync-status-unknown.slack: staging
notifications.argoproj.io/subscribe.on-health-degraded.slack: staging
notifications.argoproj.io/subscribe.on-deployed.slack: staging
spec:
project: default
source:
repoURL: git@github.com:0toalpha/argocd-example.git
targetRevision: HEAD
path: "staging/clock/templates"
destination:
server: https://kubernetes.default.svc
namespace: example
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: true
prune: true

Application Template

Under the template folder, we also have a deployment.yaml file. This tells argocd how to run the deployment.

kind: Deployment
apiVersion: apps/v1
metadata:
name: clock
spec:
replicas: 1
selector:
matchLabels:
app: clock
template:
metadata:
labels:
app: clock
spec:
containers:
- name: clock
image: 0toalpha/clock:v0.1.0
imagePullPolicy: Always
env:
- name: MESSAGE
value: "Hello World"
- name: AXIOM_DATASET
valueFrom:
secretKeyRef:
name: axiom
key: dataset
- name: AXIOM_TOKEN
valueFrom:
secretKeyRef:
name: axiom
key: token
- name: AXIOM_ORG_ID
valueFrom:
secretKeyRef:
name: axiom
key: orgId
resources:
requests:
memory: "128Mi"
cpu: 0.25
limits:
memory: "256Mi"
cpu: 0.5
imagePullSecrets:
- name: dockerhub
restartPolicy: Always
hostNetwork: false

Notice this is where we have our environment variables set. We still need secrets for axiom under the example namespace. Let's do it real quick again. In the staging kubernetes server, create this script while inserting the correct secrets:

example.yaml

DOCKER_USERNAME=
DOCKER_API_TOKEN=
AXIOM_DATASET=staging
AXIOM_ORGID=
AXIOM_TOKEN=
# Create namespaces
kubectl create ns example
# Delete Secrets
kubectl delete secrets --all -n example
# Axiom secrets
kubectl create secret generic axiom --from-literal=dataset=$AXIOM_DATASET --from-literal=orgId=$AXIOM_ORGID --from-literal=token=$AXIOM_TOKEN --namespace example
# Dockerhub secrets
kubectl create secret docker-registry dockerhub --docker-server https://index.docker.io/v1/ --docker-username $DOCKER_USERNAME --docker-password $DOCKER_API_TOKEN --namespace example

Run the script via:

kubectl apply -f example.yaml

Git Actions

The git actions we have written here are used to tie into the event from when the build kicked off when we tagged our commit. We want the build to come back and kick off another git hub action to replace the build number in our manifests.

clock-staging.yml

name: ArgoCD Clock Staging
on:
repository_dispatch:
types: [clock-staging]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clock Update Image Version
id: imgupd-clock-staging
uses: mikefarah/yq@master
with:
cmd: yq eval '.spec.template.spec.containers[0].image = "${{ github.event.client_payload.image }}"' -i staging/clock/templates/deployment.yaml
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Apply image ${{ github.event.client_payload.image }}
tip

Notice the clock-staging event triggers this action.

clock-production.yml

name: ArgoCD Clock Production
on:
repository_dispatch:
types: [clock-production]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clock Update Image Version
id: imgupd-clock-production
uses: mikefarah/yq@master
with:
cmd: yq eval '.spec.template.spec.containers[0].image = "${{ github.event.client_payload.image }}"' -i production/clock/templates/deployment.yaml
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Apply image ${{ github.event.client_payload.image }}

Preparing ArgoCD Repository

Remember when we added ssh keys to GitHub? It's time to retrieve the id_rsa file.

tip

The id_rsa file should start and end with

-----BEGIN OPENSSH PRIVATE KEY-----
-----END OPENSSH PRIVATE KEY-----

Now to go the ArgoCD Dashboard and go to Settings > Repositories

Add Repository

Select "+ Connect Repo"

Connect Repo

Configure the argocd-example repo and check "Skip server verification"

Configure Repo

Check the repo status.

Repo Status

Initializing ArgoCD Application

On the kubernetes server, git clone the argocd-example. Navigate to staging > clock and run the following:

kubectl apply -f application.yaml

ArgoCD Dashboard

Back on the ArgoCD Dashboard, you should now see the application being loaded.

ArgoCD Application

Let's check on Axiom that it is running by checking the logs

Open Axiom and check the logs being pushed from the running application.

Logger Check

To demonstrate automatic deployment, modify the application code. Create a feature branch from develop called feature/message and update the code to include version logging. The new version should log updates every minute instead of every second. This demonstrates that code changes triggers automatic container builds and deployments to the server.

Reviewing Steps:

  1. Commit feature.
  2. Create pull request to develop.
  3. You can watch in the pull request that a test build is done on the pull request.
  4. Once all checks are done and we are happy with the code, merge pull request.
  5. Create a tag on develop called v0.2.0 and push the tag.
  6. On GitHub > Actions, we can watch the build on v0.2.0.
  7. Once the build has been completed, it will trigger the version update on GitHub repo argocd-example. We can check the code and see that the version has updated.

Notice in argocd-example Actions, you can see the git action ran.

Argo Action Ran

If you check the staging deployment.yaml file, you will notice the version has updated

kind: Deployment
apiVersion: apps/v1
metadata:
name: clock
spec:
replicas: 1
selector:
matchLabels:
app: clock
template:
metadata:
labels:
app: clock
spec:
containers:
- name: clock
image: 0toalpha/clock:v0.2.0
...

If you go to ArgoCD, select your application and the pod, you can view the logs. Notice the version output.

Log Output