Our favourite by far way of achieving an automated CI /CD process is using GitLab CI and Flux GitOps.
GitLab is a very powerful and open source project. It provides Git repository servicices, docker registry, CI/CD tool, Wiki, ticketing system and much more. We specifically value its CI/CD pipeline capabilities. Just by adding a .gitlab-ci.yml file in your repo, GitLab automatically executes the commands inside it to do various things like running tests, building docker images, deploying to servers etc.
In our process, we want each of our projects to generate a docker image as artifact. That’s so we can use this image later on for our deployment with Flux. To achieve that, we inject all our projects with a pre-configured .gitlab-ci.yml which in summary performs a docker build and docker push.
With this implementation the creation of all projects is consistent and is defined by each project’s Dockerfile only.
Flux is the CD part of the CI/CD process. It runs inside the cluster and is responsible for the deployment of all your projects. In fact, it is constantly looking for changes in a specific git repository you ll give it access to (aka GitOps repo). All .yml files commited to this repo will automatically get picked up by Flux and deployed. It will pick up any additions, removals or changes to deployments, services, ingress, secrets and any kind of kuberentes resources. That said, you must provide Flux with credentials to any docker registry your deployments use so it can pull the images successfully.
Flux also does another thing automatically. It deploys new images for the deployments it manages. If GitOps repo contains a deployment for an image my-image:v.1.0.0 and you push a new image my-image:v.1.0.1, Flux automatically picks that new image and replaces the pod on the cluster with it.
And if that wasn’t great enough, Flux also aims to keep your GitOps repo as a single source of truth of what is deployed in your cluster. After deploying a new image for your project, it updates the version of it in your GitOps repo by making a commit. That way, anytime your server goes down or you want to re-create your whole infrastructure from scratch, your projects will come up configured exactly as they were on your last commit!
The above can be summarized with an illustration: