The GitOps Kubernetes Connection

The GitOps Kubernetes Connection

Kelly Griffin
Kelly Griffin
Gray Calendar Icon Published: February 28, 2020
Gray Calendar Icon Updated: March 16, 2020

In the first article in this series, we talked about making Kubernetes essential to your DevOps pipeline. We reviewed CI/CD and DevOps and why their relationship with Kubernetes is so powerful.

In this article, I’m going to dive into another term in the application development and management mix: GitOps. We’ll cover what GitOps is, how it affects an organization and how it aligns with Kubernetes.

What is GitOps?

GitOps is a process that leverages the Git developer toolset for operations and management of cloud-native applications. Git is the single source of truth when deploying applications to Kubernetes. When developers make changes to the application, Git automatically pushes them to Kubernetes for deployment. Further, if there are changes to the running state within Kubernetes that are inconsistent with the state within Git, they are reverted to the known state from within Git.

GitOps and CI/CD: What’s the Connection?

GitOps and CI/CD (continuous integration/continuous delivery or deployment) have an important working relationship. As a refresher, CI/CD lets developers continuously iterate, develop and deploy applications. Often the iteration is through a Git repository (although there can be other repositories) that flows through a toolset for pipelines. During the deployment/delivery phase, the built container-based application is “pushed” to Kubernetes for deployment. The operation of GitOps enhances the CI/CD model by using a “pull” method via Kubernetes, bringing the operational aspect into deployment/delivery.

But what happens if someone changes something running within the Kubernetes cluster? We’d use Git as the primary source of truth as a declarative deployment tool and leverage additional tools to alert us when there is divergence. By leveraging tools that can identify differences between running and declared state, Kubernetes remediates to the known/declared operating state.

Note: Continuous integration and continuous development are complementary but separate processes. In an optimal state, GitOps enables batch size as single-piece-flow, where work happens one unit at a time. However, since CI and CD processes occur in different groups, the process may vary from one organization to another.

GitOps and the Application Lifecycle

Let’s look at this through the application lifecycle lens. During a typical lifecycle, an application goes through multiple states. These include:

  • code
  • build
  • image creation
  • test
  • release

With GitOps, we extend that list to include:

  • deploy
  • monitor changes within git repository
  • log changes and events
  • alert when a change has occurred and integrate with existing monitoring/alerting systems
  • update

Under the GitOps operating model, when an application is released, Kubernetes ensures that it operates as intended. Kubernetes also manages the operation of the application by ensuring its stability and availability. If a developer changes the application via Git, Kubernetes takes the declaration and applies it as required.

What GitOps Brings to the Table

In summary, here’s what GitOps is, and what it can do for you:

  • GitOps provides an operating model for applications that ensures Git provides the framework to unify the running, operating and continuous development of an application.
  • As part of the CI/CD pipeline, GitOps provides the glue between the application build/delivery and the operations of where to run it.
  • Git provides a single source of truth for both the development and operations of the application within a Kubernetes platform.
  • Application delivery and ongoing platform management are declarative and can be version controlled.
  • Git controls rollback, upgrades and changes.
  • Developers don’t need to know or operate the operational platform (such as Kubernetes).
  • Git controls and remediates divergence, or “drift.”
  • GitOps leverages auditing, monitoring and rollback capabilities to increase reliability and stability of application releases.

In closing, while there’s a lot more to operating in GitOps mode, there’s a clear synergy between GitOps, DevOps and existing CI/CD patterns. GitOps provides a model for delivering applications to a Kubernetes platform that ensures a single source of truth and leverages all of the operational features of Kubernetes. GitOps is not a tool replacement. Quite the opposite: GitOps augments your processes, increases maturity and helps teams deliver (and operate) applications by leveraging declarative processes and tools.

See GitOps In Action: FluxCD Demo

FluxCD (or Flux) is a great tool for integrating Kubernetes and Git. Flux is a Kubernetes Operator that you, as the administrator, install into Kubernetes to manage the integration between Git and native Kubernetes. Within Kubernetes, an Operator is an extension of the native Kubernetes platform as a pattern for custom resources that are used to manage applications and their components. This means that, with the aid of the Operator inside Kubernetes, the desired state – as represented within the running state – will continually check and adjust to align with what the Git repository declares. Flux can integrate with your existing CI/CD toolsets for additional workflow, permissions and auditing. Within Kubernetes, Flux monitors Git repositories that you declare (through configuration) for changes and will update Kubernetes to that desired running state, should changes occur locally on a Kubernetes pod that shouldn’t be changed. Remember, Git is the source of truth. The Flux Operator will detect this and change the running configuration back to the declared state from Git.

In the following demo, I’ll show you how to install and implement Flux.

Pre-Requisites

You Will Need

  • a Docker hub repository where you can upload the Flaskapp docker image
  • A Git Repo that you can connect to replace anything within “< >” with your settings as required throughout this demonstration

Steps

  • Install Kubernetes
  • Install and configure fluxctl, the native installer for Flux deployment
  • Configure Flux to connect to Git Repo
  • Update deployment manifest in Git Repo
  • Update Container image and Sync
  • Configuration drift and Sync

You can use the following configuration for testing/demonstration purposes. It includes the Docker file for the Flask application, as well as the Kubernetes deployment/configuration files. You will need these as part of the demonstration and can uploaded them to your nominated GIT repository.

Docker File

    FROM python:3
    
    RUN pip install flask
    
    RUN mkdir -p /corp/app
    WORKDIR /corp/app
    COPY main.py .
    ENV FLASK_APP=/corp/app/main.py
    
    ENV APP_NAME=MyApp.DevOps
    ENV APP_VERSION=v1.0.0
    
    CMD ["flask", "run", "--host=127.0.0.1"]

main.py Python Script File

import os
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    appname = os.environ['APP_NAME']
    appversion = os.environ['APP_VERSION']

    response = "%s - %s.%s\n" %('Hello World', appname, appversion)
    return response

Kubernetes Deployment File

apiVersion: v1 
kind: Namespace 
metadata: 
  name: my-demo 
--- 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: fluxdemo 
  namespace: my-demo 
  annotations: 
    flux.weave.works/tag.flask: glob:develop-v* 
    flux.weave.works/automated: 'true' 
  labels: 
    role: fluxdemo 
    env: demo 
    app: flux 
spec: 
  replicas: 1 
  selector: 
    matchLabels: 
      role: fluxdemo 
  template: 
    metadata: 
      labels: 
        role: fluxdemo 
    spec: 
      containers: 
      - name: nginx 
        image: nginx:1.16-perl 
        imagePullPolicy: IfNotPresent 
        ports: 
        - name: http 
          containerPort: 80 
        volumeMounts: 
        - name: nginx-proxy-config 
          mountPath: /etc/nginx/conf.d/default.conf 
          subPath: nginx.conf 
      - name: flask 
        image: docker.io/<your docker repo>/flaskapp:develop-v1.8.0 
        imagePullPolicy: IfNotPresent 
        ports: 
        - name: http 
          containerPort: 5000 
        env: 
        - name: APP_NAME 
          value: myfluxdemo.K8s.GitOps 
        - name: APP_VERSION 
          value: v1.0.5 
      volumes: 
      - name: nginx-proxy-config 
        configMap: 
          name: nginx-conf 
---
apiVersion: v1
kind: ConfigMap 
metadata: 
  name: nginx-conf
  namespace: my-demo
data:
  nginx.conf: |-
    #CODE1.0:
    #add the nginx.conf configuration - this will be referenced within the deployment.yaml
    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://localhost:5000/;
            proxy_set_header Host "localhost";
        }
    }

Install Flux

Configure Flux for Repo

Create a Namespace

kubectl create ns <namespace>
export FLUX_FORWARD_NAMESPACE= <namespace>
fluxctl list-workloads

Install Fluxcd to create connection to your Git Repo

export GHUSER=""
export REPO="gitops-demo"
export NS="flux"
fluxctl install \
--git-user=${GHUSER} \
--git-email=${GHUSER}@users.noreply.github.com \
--git-url=git@github.com:
Image download failed.
{REPO} \
--namespace=${NS} | kubectl apply -f -

Create SSH Key for Adding to Your GitHub Repository

Type the following in your terminal to obtain the key you will need for the next step.

fluxctl identity

Open GitHub, navigate to the Repository added when you installed Fluxcd, go to Setting > Deploy keys, click on Add deploy key, give it a title, check Allow write access, paste the public key and click Add key.

Update Deployment Manifest in Git Repo

  • Open up your GitRepo that has the deployment.yaml file
  • Scroll down to the section as below and change the APP_VERSION number
    env:
    - name: APP_NAME
      value: myfluxdemo.K8s.GitOps
    - name: APP_VERSION
      value: v1.0.5
  • Save and Commit the change to your repo

Flux will (within 5 minutes) update your deployment

To test from a localhost, use the “Port-forward” command within Kubernetes:

kubectl get pods -n  copy the pod name kubectl port-forward  8080:80 -n

Open another terminal:

curl -s -i http://localhost:8080

Update Container Image and Sync

Now let’s now make a modification to the Docker image and upload to our Docker hub repository. For this, we will modify the main.py file within the flaskapp directory.

  • Update the main.py file. Change Hello World to something else
response = "%s - %s.%s\n" %('Flux World', appname, appversion)
  • Create a new Docker file and upload to Docker (with another incremental version number)
  • Wait 5 minutes - Flux will now automatically deploy new Image

Configuration Drift and Sync

Now let’s test what happens when there is a manual change to the running configuration

kubectl scale deployment/fluxdemo --replicas=4 -n

Now let’s watch the pods for a few minutes and see what happens. We will see the additional pods for a short period, but within 5 minutes, we will see the excess number of pods terminate. Therefore, Flux has brought the configuration back to the declared state of deployment currently held within Git.

kubectl get po -n  --watch

Re-run the same command again and you can see that this view has now filtered down to the just one running pod.

Don’t forget to clean up and remove the deployment and Git connection (if you wish). Otherwise, start adding more repositories and keep on building.

More Resources

Rancher makes it easier to operate and manage of multi-cluster, hybrid-cloud Kubernetes. It also has built-in tools for developers and other consumers of Kubernetes and computing power.

New to Rancher? Learn how Rancher works in the technical architecture guide.

Kelly Griffin
github
Kelly Griffin
Infrastructure, Security and Microservices Consultant
Kelly Griffin is an infrastructure, security and microservices consultant with more than 20 years’ experience delivering enterprise solutions. Kelly has worked with enterprise clients in Australia, Singapore, New Zealand and around the globe. His experience includes Azure, AWS and Google Cloud, containerization with Docker and Kubernetes and security through cloud and containerization. He helps customers drive cloud-native adoption and modernize business and application services. Kelly works independently and in team engagements and has developed in-depth skillsets for helping customers leverage cloud-native services to modernize. Whether developing go-to-market strategies for business services or innovating by leveraging container and cloud-native technologies, his number one focus is the customer.
Get started with Rancher