A look into GitOps : Future of DevOps?

A look into GitOps : Future of DevOps?

·

7 min read

GitOps is a new approach for continuous deployment of your workload on Kubernetes. Extension of the DevOps workflow pattern, it uses any source code/version control repository as the single source of truth for all the infrastructure to be deployed on Kubernetes.

  • GitOps works on the principle of a single source of truth and the complete state of an application is assumed to be present on a git repository. It brings the power to the developers to maintain their own infrastructure and code base in a single repository which is then reproduced on a cloud infrastructure such as Kubernetes.
  • In practice the two elements i.e., IAC(Infrastructure as a Code) YAML files and source code are maintained in a version control(Git repository), which is monitored by another entity i.e., GitOps operator running on a cloud infra(Kubernetes) which generates a pull request to the repository whenever it observes a change in running application’s version.

In simple aspects of CI/CD, continuous integration is merging of the developed code into master branch and continuous deployment is releasing the latest version of code from master branch to a runtime. This is exactly what GitOps does it automates your infra updates, where you as a developer don’t have to bother about any CI/CD files and other setups, and can solely focus on your code with a one time configuration for YAML files in your repository.

DevOps CI/CD vs. GitOps

DevOps CI/CD

A traditional deployment pipeline involves two paradigms, one being continuous integration meaning the source code changes extracted from multiple contributors is integrated into one git repository and is passed through build/test stages, and continuous deployment which is taking the integrated code and reflecting the change on a running software.

This kind of approach of deployment of code is known as push based deployments wherein whenever a new piece of code is pushed to a repository a new build cycle is triggered which creates a docker image pushes it to a repository and the YAML files residing in the the code repository is applied to deploy the change.

  • This approach completely resides on push based changes and hence needs a monitoring tool in place for the pushes that take place, it cannot version control the changes that take place in code repository on it’s own and maintain the state on the running environment.
  • This approach is not designed keeping security as a priority and hence the CI/CD tool required read access for the source repository and also needs complete read write access of the infrastructure in order deploy the changes, which makes the infra vulnerable since changes can be made from outside the cluster.

GitOps for deployment

GitOps uses a more modern approach bringing pull based deployments into picture. In this scenario no external monitoring is required, instead a tool, operator comes into play which directly compares the states of deployed infrastructure with that of code residing in the repository and basis this manages the state of the infrastructure. Not only code based changes can be reflected to infra, in fact operator can compare the changes in image registry as well to keep the infra up to date with latest image changes.

GitOps advantages

  • With GitOps you can deploy changes faster as compared to any traditional CI/CD tools since only single source of truth exists, hence there is no need to manage and monitor other tools, a developer only needs to concern with the source code repository and it’s changes to deploy their code.
  • Fault tolerance is increased with GitOps since if the infra or code breaks with a new push, you are only one git revert away from undoing your changes and fixing your environment. The changes since are directly compared and reflected the management and recovery is improved substantially.
  • Management remains with the operations team, since operator resides alongside infra you don’t need any access credentials to leave your infra, only access required is from operator to infra rest everything is managed within your environment and hence your developers need not require direct access to infra.
  • Every thing is tracked at a single location hence all the infra changes can be found in git logs and every change that is being pushed to infra can be seen in git commits, so you do not require third party tools to keep monitoring in check it is managed internally in git.
  • GitOps enables two way tracking of your environment, hence if there is any change in your infra or failures the state is compared with the repository and restored automatically, also since it compares your infra with source code directory there’s no way for direct infra changes and deployments which makes your infra completely isolated and secure.
  • GitOps operator enables monitoring for your infra as well and can send alerts in form of emails or slack notifications making your infra more robust.

GitOps disadvantages

  • GitOps operator becomes a single point of failure for your infra since if the operator fails there’s no deployments possible hence a proper monitoring tools needs to be in place to keep a track of your operator being in running state.
  • Since GitOps only offers continuous deployments, proper planning is required for integrating it with a continuous integration tool, which is commonly Gits own CI tool which is GitHub actions or GitLab CI/CD.

Understanding GitOps with a test setup

Now we take a look at how GitOps works in detail by taking a test repository into consideration.

Pre-requisites

  • A GitHub account with git installed locally
  • A container registry account with access to push/pull to a repository and Docker installed locally
  • A running Kubernetes cluster with proper access from your local machine

Ready your environment registry and CI pipeline

We will host a sample application running a http server using NodeJS and create a container for the application using Dockerfile.

const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
FROM node:11-alpine COPY . . CMD ["node","node.js"]

Now, since we have our code and dockerfile ready we need to create a docker image and push it to a registry. For this example we consider you have an account on https://hub.docker.com/ with proper read/write access in place. You can manually build an image and push it to registry but since we are following GitOps practice we will automate our build using GitHub actions.

name: CI on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Generate build number id: buildnumber uses: einaregilsson/build-number@v3 with: token: ${{secrets.github_token}} - name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: <Your_username>/helloworld:${{ steps.buildnumber.outputs.build_number }}

After commit you should see .github/workflows/main.yml present in your code repo. It’ll trigger a new pipeline everytime a commit is observed in master branch, but since we haven’t configured DockerHub credentials as of yet your push will fail.
So to configure secrets, go to settings -> secrets and add these two secrets,

DOCKERHUB_USERNAME value : <Your Username> DOCKERHUB_TOKEN value: <Your Password>

Now next time the pipeline runs you’ll see a successful CI build.

apiVersion: apps/v1 kind: Deployment metadata: name: nodejs-helloworld annotations: flux.weave.works/automated: "true" labels: app: helloworld spec: replicas: 1 selector: matchLabels: app: helloworld template: metadata: labels: app: helloworld spec: containers: - name: helloworld image: <your user name>/helloworld:latest ports: - containerPort: 3000 --- apiVersion: v1 kind: Service metadata: name: helloworld-svc spec: selector: app: helloworld ports: - protocol: TCP port: 3000 targetPort: 3000 nodePort: 30001 type: NodePort

You can apply the following file and check on your browser hitting, http://:30001/

The next step is setting GitOps operator in your infra

Make sure you have a Kubernetes cluster deployed with Kubectl configured from your local machine. The GitOps operator we will be installing is Flux. Follow the steps to install the same using helm,

git clone https://github.com/fluxcd/flux && cd flux
kubectl apply -f deploy.yml

Testing GitOps operator for CD

After setting up our repository and operator on Kubernetes, you can commit your new code and change your image tag in k8s/deployment_svc.yml and you should see a new build automatically triggered through GitHub actions which is basically you CI, and a deployment created in Kubernetes by flux comparing k8s/deployment_svc.yml with the infra.
This way we have achieved a complete CI/CD pipeline configuration using GitHub actions and GitOps.

Summary

After understanding differences between traditional CI/CD vs. GitOps CD and configuring a test CI/CD using GitOps operator we can conclude that GitOps is a modern DevOps paradigm which is meant to ease your deployments with providing utmost security, with better management of code and infra since there exists only a single source of truth for syncing and operability.

Originally published at solutelabs.com.