This is the fourth part in a series focused on teaching the fundamentals of building and developing applications using Acorn. In the previous step we introduced Acorn development mode, a feature which allows to develop an application in an interactive and iterative way. In this step we will detail the CICD pipeline used for the VotingApp with a focus on the CD part which automates the deployment of a new version of the application.
Note: if you want to follow the steps detailed in this post you only need access to a cluster running Acorn, a one node k3s cluster is totally fine.
Project organisation
The VotingApp is managed in GitLab in https://gitlab.com/voting-application each microservice having its own git repository. An additional repo, named config, is used to specify the application in different ways (and using different tools), this one acts as the source of trust in a GitOps approach as we will see below.

The GitLab repository of each microservice contains:
- the application code
- a Dockerfile which specifies how the container image is created
- a .gitlab-ci.yaml file which defines the CICD pipeline of the microservice
Example: GitLab repository of the result microservice
When a code change is pushed in the master branch the following actions are triggered:
- run of a test suite (definitely something to enhance on the VotingApp 🙂 )
- creation of a new git tag in the SemVer format
- build and push the container image of the microservice
- update of the config repository to alert about the new microservice’s tag
Next, when the above actions are done, the CI pipeline of the config repository is triggered, it performs the following actions:
- creation of a new tag for the whole application
- build of a new Acorn image of the application
- push the Acorn image into an OCI registry (DockerHub in the current setup)
- update of the file defining the Acorn application (more on that in the next part)
In this post we will focus on the CD part, the actions which take place after all the steps of the CI part are done. In other words we will answer the following question: how is each new version of the Acorn image deployed ?
We will detail 2 different approaches:
- the first one follows a GitOps approach using Argo CD
- the second one uses Acorn automated upgrade feature
GitOps with Argo CD
Argo CD is a GitOps Continuous Delivery tool for Kubernetes. It can monitor git repositories and make sure changes in those repos are applied to the cluster. In other words it ensures the current state of an application (the way it runs in the cluster) is the same as the desired state (the one defined as yaml files in git).
To illustrate this approach, we first install Argo CD in our cluster. This can be done with Helm:
$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm upgrade --install argo-cd argo/argo-cd -n argocd --version 5.19.6 --create-namespace
Next we get the auto-generated Argo CD admin password:
$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Next, from another terminal, we run the following port-forward command to expose the web frontend locally:
kubectl port-forward service/argo-cd-argocd-server -n argocd 8080:443
Then, from a web browser, we can access Argo CD UI and login using the password retrieved above.
Argo CD login page
We can see an empty dashboard because we haven’t asked Argo CD to deploy any applications yet.
Argo CD dashboard: no application have been created yet
Before defining an Argo Cd application, let’s first explore 2 different ways we can deploy an Acorn image:
- Using the acorn cli
If we want to deploy the version v1.0.72 of the VotingApp, which is already packaged as an Acorn image in the DockerHub, we could use the following command:
acorn run -n vote docker.io/lucj/voting:v1.0.72
- Using an App resource
The Acorn application could also be deployed using a yaml manifest like the following one:
apiVersion: api.acorn.io/v1
kind: App
metadata:
name: vote
namespace: vote
spec:
image: docker.io/lucj/voting:v1.0.72
To illustrate this second approach, we create the file app.yaml containing the above specification and create the App resource:
kubectl apply -f app.yaml
We can use the acorn cli to get information on that application as we’ve done before:

The http endpoints returned allow us to access the application frontends and vote for our favorite pet.


In this example we created the application manually using the resource definition from app.yaml . We will now let Argo CD automatically deploy and update the application for us.
First, we remove the application and all its related resources
acorn rm vote --all -j vote --force
Next, we define the following Argo CD Application resource:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: votingapp
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://gitlab.com/voting-application/config.git
targetRevision: master
path: acorn
directory:
include: "app.yaml"
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated: {}
syncOptions:
- CreateNamespace=true
Using this resource definition we ask Argo CD to:
- monitor the acorn/app.yaml file located in the master branch of the https://gitlab.com/voting-application/config.git repository
- ensure the current state of the application (the way it is running in the cluster) converges towards the desired state (the content of app.yaml)
First we save this specification in argo-votingapp.yaml and create the associated resource:
kubectl apply -f argo-votingapp.yaml
Next we go to the Argo CD UI (the one we previously exposed using a port-forward) and see Argo CD deployed our Acorn app.
Using the Application resource Argo CD deployed the Acorn application
Using the Application resource Argo CD deployed the Acorn application
We can also verify the app is visible from the Acorn cli:

Argo CD is now configured to follow the changes in the app.yaml file existing in the config repository. When a new Acorn image will be built and pushed to the registry, the CI will update app.yaml replacing the previous tag with the newer one. Argo CD will soon detect the change and automatically deploy the new version of the application.
Let’s see into action pushing some little changes to the worker go code:
# changes in go/main.go, …
git add go/
git commit -m 'fix: adding logs'
git push origin master
This triggers the CI pipeline of the worker repository creating the tag v1.0.4 for that particular microservice.
Tag v1.0.4 is created for the worker microservice
The CI pipeline of the config repository is then triggered generating the tag v1.0.73 for the whole application.
Tag v1.0.73 is created for the whole application
After a couple of minutes Argo CD detects the new tag in app.yaml and deploys the version v1.0.73 of the application.
Version v1.072 of the VotingApp was replaced with v1.0.73
Let’s now delete the application definition, this can be done from Argo CD UI or using the following kubectl command:
kubectl delete -f argo-votingapp.yaml
We can also close the terminal running the port-forward toward Argo CD.
To summarize: with this approach, the CI builds the acorn image, pushes it to the registry and updates a configuration file in git. When Argo CD sees the changes it deploys the new version of the application.
Acorn Automatic upgrade
In the previous part we used Argo CD to deploy the Acorn application, this approach follows the GitOps approach which considers Git as the source of trust. We will now see how Acorn can be used to automatically upgrade the running application when a new version of the image is available.
At the beginning of this post, we detailed the way the CI actually works. As a reminder, at the end of the CI a new Acorn image is pushed to the DockerHub (in https://hub.docker.com/repository/docker/lucj/voting)
When running an Acorn application, we can specify a pattern in the image tag as follows:
acorn run -n vote docker.io/lucj/voting:v#.#.#
Once the application is up and running we can use acorn app vote
to get the app’s info:

We can see the version v1.0.73 was deployed, this version was the latest one following the pattern v#.#.# (at the time the command was run). With this configuration, each time a new release is created it will automatically be deployed by Acorn.
Let’s illustrate this pushing a new change to the vote microservices
# changes in app.py, ….
git add app.py
git commit -m 'fix: add some more logs'
git push origin master
This change triggers the CI of the vote microservice then the one of the config repository. After a few minutes minutes we will notice the acorn application was automatically upgraded to the new version:

We can see the version is now v1.0.74, the http endpoints being the same as the previous version (v1.0.73).
To summarize: with the automated approach, the CI just needs to build the acorn image and pushes it to the registry. If the tag of this new image matches the pattern provided in the run command, it will automatically be deployed replacing the previous version.
Wrapping up
In this new post of the VotingApp series we detailed 2 different ways the application can be updated, either using a GitOps approach with Argo CD or directly with the Acorn automatic upgrade feature. In the next post we will expose the VotingApp using a custom domain and ensure it is accessible via TLS.
Luc Juggery is a software engineer with 18+ years of experience and co-founder of 2 startups located in Sophia-Antipolis, southern France. You can chat with him on Twitter, read more of his work on Medium, find his tutorials on YouTube, or take one of his Docker or Kubernetes training courses on Udemy.
Photo by Angely Acevedo on Unsplash