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.
Also read: What is CI/CD in DevOps
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.
- Copy the following code as app.js file into your git repo. This is a simple code in node.js, creating a web server which prints Hello World on you we browser.
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}/`);
});
- Copy the following snippet as your Dockerfile into your git repo. This Dockerfile containerizes your code so you don’t have a need to have nodejs installed locally.
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.
- In you GitHub account go into Actions, click on set up a workflow yourself and copy the following workflow file,
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.
- In order to deploy on Kubernetes create a folder k8s in your git repo and below file as deployment_svc.yml,
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://<node ip>: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,
- Clone the flux repository:
git clone https://github.com/fluxcd/flux && cd flux
- In order for flux to run you need to edit git-url with your git ssh url for cloning, git-path with the path for Kubernetes files which is k8s in our case. After making the given changes we can install flux to your cluster,
kubectl apply -f deploy.yml
- Now, after all pods spin up and come to running state, check for logs of pod named flux, it will print ssh key which needs to be added in your repository under settings -> deploy keys -> add depoy key, and give it read write access. This will configure your flux deployment to monitor your git repository and check for changes in your yaml files.
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.