Bidirectional GitOps controller for Docker with Simplecontainer

Bidirectional GitOps controller for Docker with Simplecontainer

Reasoning

GitOps mantra defines the Git repository as the source of the truth. GitOps controller tracks the changes on the Git repository and reconcile the state on the controlling receiving end. Usually controller implements health checking and drift detection to force the GitOps state if any manual change occurs.

In the context of deploying software, be it Kubernetes, Docker, Simplecontainer, or any other platform, GitOps in this context brings great visualization of the deployments, how entities are connected, and order in the history.

The known problem for GitOps is its incorporation in the external CI/CD. Keeping infrastructure and software in separate repositories brings one problem. The distribution of the infrastructure deployment follows exponential decay. It's spiky in the beginning, and later on it falls to a minimum. Software deployment, on the other hand, follows uniform distribution.

Since the infrastructure repository often holds information about which containers are to be pulled and when deployments are to be made, an update of the infrastructure repository is imminent. It boils down to the custom implementation of the update of the infrastructure Git repository. The main reason is usually GitOps controller is based on the pull only approach.

Production issues and other similar events where speed is crucial often introduce manual changes to the system.

Bidirectional GitOps controller

Bidirectional GitOps controller enables two-way communication: Push and pull. It writes to the repository and also pulls changes when they are present in the repository.

The problem with a bidirectional controller is conflicts between the current state and git, and which changes to commit back to the repository from the current state.

Simplecontainer implements a hybrid bidirectional GitOps controller. The controller itself waits for the patching events. On the patch, the event definition is updated and committed to the repository. Currently, an event can be triggered only using smrctl.

Benefits you get with this approach:

  • Enable external CI/CD to apply patches via the GitOps controller itself.
  • Using smrctl to delegate pushing a commit to the repository
  • Reusing the Simplecontainer control plane authentication instead of using Git credentials directly
  • Quick changes directly from the terminal when incidents occur
  • Immediately pull after push, not waiting on the polling of the repository to occur (this enables immediate deployment)

Archicture

The image below gives a high overview of how the bidirectional GitOps controller works on the simplecontainer node.

How it works?

To define one simple GitOps object on the node:

prefix: simplecontainer.io/v1
kind: gitops
meta:
  group: examples
  name: plain-auto
spec:
  repoURL: "https://github.com/simplecontainer/examples"
  revision: "main"
  automaticSync: true
  directoryPath: "/tests/minimal"

GitOps resource definition

This example will automatically sync changes, and will poll the examples repository under /tests/minimal path to deploy whatever resources are in.

Tests minimal contains only the containers resource:

prefix: simplecontainer.io/v1
kind: containers
meta:
  group: example
  name: busybox
spec:
  image: busybox
  tag: 1.37.0
  replicas: 1
  entrypoint: ["sleep"]
  args: ["3600"]

Containers resource definition

This container's definition will deploy a busybox container on the node.

Now let's assume we are the developers of busybox and our pipeline has just built a new version of it. The pipeline for deployment can leverage a bidirectional controller. Here is the example:

deploy:
  stage: deploy
  image: ubuntu
  before_script:
    - apt-get update && apt-get install -y curl sudo
    - curl -sL https://raw.githubusercontent.com/simplecontainer/smr/refs/heads/main/scripts/production/smrmgr.sh -o smrmgr
    - chmod +x smrmgr
    - sudo mv smrmgr /usr/local/bin
    - sudo smrmgr install
    - smrctl context import $SIMPLECONTAINER_CONTEXT $DECRYPTION_KEY -y
    - smrctl version
  script: |
    smrctl ps gitops
    smrctl commit gitops/prod/app containers/prod/app "spec: {tag: $CI_COMMIT_TAG}"

The part of the pipeline that is informing about patch changes is next:

smrctl commit gitops/prod/app containers/prod/app "spec: {tag: $CI_COMMIT_TAG}"

This process sends a modified resource definition identifier along with its corresponding YAML patch data. The GitOps controller handles the rest. Once the operation is complete, the Git repository will contain the patch data, and the changes will also be applied to the live state.