The acronym “CI/CD” and its respective phrases (continuous integration & continuous [delivery|deployment]) are sometimes munged together yet there are clear definitions and lines of delineation for each, despite many CI/CD offerings out there that enable you to use a single framework to implement both sides of the CI/CD equation using the same tooling.

The intent of continuous delivery is pretty simple: take a built, tested, validated artifact and “deliver or deploy” it to one or more target execution environments. What exactly an “artifact” is within a CI/CD system completely depends on each application and target execution environment. It might be a NPM package, JAR file, or ZIP file to be deployed to a set of virtual machines; or it could be a Docker image that needs to be deployed to a container runtime or container orchestrator like Kubernetes.

For Kubernetes deployment targets, one of the tools out there for the delivery side of the CI/CD equation is Flux a CNCF sandbox project.

Flux: GitOps centric k8s delivery

First off, FYI; this article is purely based on my personal experience using Flux which was centered around addressing my individual CD use-case. This article does not exhaustively cover every single Flux feature or capability.

When you look at the zillion different CI/CD platforms, frameworks and cloud based services out there, Flux stands out for several reasons. First it only handles the continuous delivery side of the “slash” in CI/CD (Flux is not for building artifacts), secondly its specifically targeting Kubernetes execution environments, and third its GitOps centric.

First off, so what is “GitOps” you ask? Whenever you develop custom software ( and CI/CD pipelines are indeed software…) generally you have to store the “state” or “desired state” of your system somewhere; this might be an RDBMS, NoSQL db system etc whatever… With GitOps, you decoratively describe the intended state of your system using Git and leverage all the built in constructs and capabilities that Git provides for history etc rather than writing all of that yourself. Git becomes the ultimate source of truth for the history and lineage of all actions taken over time for your system. By leveraging Git as your source of truth from which all actions stem from, you can (in theory) always “reset” your state back to any previous point in time; depending of course, on the capabilities of the consumer of the described state.

So at the end of the day, GitOps is basically a way of doing DevOps whereby, changes to a Git repository subsequently trigger all downstream actions in your environment and this is exactly the paradigm by which Flux operates within. Its important to note that this Git repository that drives a CD system may or may not be the same repository that the CI system consumes from to build the artifacts that the CD system subsequently delivers to target execution environments;_ i.e. you may store the CD systems state configuration in an entirely different repository from where your application source code resides._

Flux high-level architecture

With Flux you install a Flux daemon onto a target Kubernetes cluster that you want to be the target of your CD system (i.e. where application artifacts get deployed to). Each Flux daemon has a 1 to 1 relationship with a single Git repository, from which the daemon consumes configuration that tells Flux what “state” should be applied to the k8s cluster that the Flux daemon resides within. (i.e. the Git repo contains standard k8s YAML manifests and/or HelmRelease chart declarations). Flux basically reacts to changes in this Git repository and makes the necessary changes in Kubernetes by applying the updated k8s YAML manifests (or HelmReleases by invoking Helm within the cluster itself via the Flux helm-operator). (FYI, Flux can also optionally generate the raw k8s YAML manifests via tools like Kustomize

Flux has the added benefit that it can optionally monitor Docker registries/repositories via its “automation” feature for each Docker image:tag referenced within the Git repository’s k8s YAML or HelmReleases. The effect of this is that when a new Docker image version is pushed to a image registry, Flux can detect this and automatically update previously applied k8s YAML with the detected new image tag, apply the change to the cluster (and subsequently bi-directionally update the Flux associated Git repository with the new image reference). Thirdly…. you can manually force changes on the Flux daemon via a CLI tool called which, once your requested changes are applied, again will be reflected back in the Git repository to ensure the declared state is up to date. For example you can manually update a running Flux named “workload” to utilize an older image via fluxctl, have the Pods updated to the new image on the cluster, and in turn, the YAML/helm release configs updated in the Flux git repository… complete with all the nice Git lineage, history and tracking one expects. The _fluxctl _CLI has numerous other capabilities such as locking/unlocking, rollbacks, toggling automation of workloads and more.

Wow, that’s a bunch…. here is a summary of all the ways you can control what gets “continuously delivered” your Kubernetes cluster with Flux.

  • Manually change and commit updated k8s manifests or Helm configs in Flux Git repo? Flux can auto-apply to cluster.
  • New image:tag pushed to a registry by a CI system for a Flux workload? Flux can auto-apply to cluster AND update Flux Git repo.
  • Manual workload adjustment via fluxctl CLI? Flux can auto-apply to cluster AND update Flux Git repo.
  • Changes to a running k8s workload via kubectl or other non-flux tool/api? NO!_ Flux will not detect this kind of change._

Overall…IMHO: it is this kind of functionality that makes Flux pretty impressive.

#continuous-delivery #continuous-deployment #devops #flux #kubernetes

Continuous delivery with Flux
1.45 GEEK