What is GitOps?

What is GitOps?

Someone recently asked me “What is GitOps?”

This article is available in a nicer looking format on my blog https://mattias.engineer/posts/what-is-gitops/

First of all, when we talk about GitOps we usually do this in combination with Kubernetes. This is what I will do in this article. However, GitOps could be applied to anything - not just Kubernetes.

GitOps is a deployment model. To understand what is new with GitOps I will first describe a traditional deployment model. In a traditional deployment model we usually work in an imperative way. We most likely set up a CI/CD pipeline with a number of steps that must happen in a certain order for our code to end up deployed in the target cluster. If the steps happen in a different order then nothing makes sense.

GitOps on the other hand replaces the CD part of CI/CD. It is a declarative deployment model. In GitOps we install a component in our cluster that handles deployments for us. Our goal is to describe (declaratively) what we want our applications to look like, and the GitOps component in our cluster makes sure to fulfill our wishes.

When a Kubernetes cluster is the destination for our application, then our goal is to create the Kubernetes manifests that describe our application and to make sure these end up in a git repository. Then our GitOps component has the responsibility of watching our git repository and act on any changes that it sees. Its job is to make sure what is deployed in the cluster exactly matches what it sees in the repository.

In this article I will use Argo CD as the GitOps component.

Get started with GitOps in 5(ish) minutes

Prerequisites

To follow along, there are a few requirements that must be in place. To simplify my own life I will assume that you are using macOS. Install the following tools

  • GitHub CLI (install with brew install gh, authenticate with gh auth login)
  • Minikube (install with brew install minikube)
  • Docker (Install by following the guide for Intel chip or Apple silicon)
  • kubectl (Install by following the guide for Intel chip or Apple silicon)
  • Argo CD CLI (install with brew install argocd)

Set up a git repository

The first part of the word “GitOps” is “Git”. So that seems like a good place to start. I begin by creating a new empty git repository on my local computer

$ mkdir get-started-with-gitops
$ cd get-started-with-gitops
$ git init --initial-branch main        

Next, I add the Kubernetes manifests that define my application. To keep things simple my application will consist of a deployment and a service. I will start with the deployment:


# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
? name: server
? labels:
??? app: server
spec:
? replicas: 3
? selector:
??? matchLabels:
????? app: server
? template:
??? metadata:
????? labels:
??????? app: server
??? spec:
????? containers:
??????? - name: server
????????? image: nginx:1.22.1
????????? ports:
??????????? - containerPort: 80
????????? resources:
??????????? requests:
????????????? cpu: "250m"
????????????? memory: "64Mi"
??????????? limits:
????????????? cpu: "500m"
????????????? memory: "128Mi"        

This deployment will create three replicas (replicas: 3) for my server container (name: server) that runs Nginx (image: nginx:1.22.1). Each replica exposes port 80 for HTTP traffic (containerPort: 80). I have added resource requests and limits, because my VS Code suggested this was a good idea.

Next I add my service:


# service.yaml
apiVersion: v1
kind: Service
metadata:
? name: webservice
spec:
? selector:
??? app: server
? ports:
??? - protocol: TCP
????? port: 80        

This service will target my server deployment (selector.app: server). It will target port 80. When a user accesses my service the traffic will be forwarded to one of my three pods.

I add both of these files (deployment.yaml and service.yaml) to a directory called dev. My repository now looks like this:


$ tree .
.
└── dev
??? ├── deployment.yaml
??? └── service.yaml

1 directory, 2 files        

I use the GitHub CLI to create my repository on GitHub and push my code:


$ git add .
$ git commit -m "Initial commit"

$ gh repo create get-started-with-gitops \
? --public \
? --remote origin \
? --description "Getting started with GitOps" \
? --source . \
? --push        

Set up a cluster and install Argo CD

I use minikube to set up a local kubernetes cluster:


$ minikube start        

That was easy! Now I install Argo CD in my cluster:


$ kubectl create namespace argocd
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml        

That was also easy! See, this might take 5 minutes after all.

Configure Argo CD

To communicate with the Argo CD API server it must be exposed in some way. To simplify for myself I set an environment variable that adds required flags to all argocd commands I run:


$ export ARGOCD_OPTS='--port-forward --port-forward-namespace argocd'        

The username to access Argo CD is admin, but to know the password I look at the contents of a secret that Argo CD set up for me:


$ PASSWORD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo)        

Now I am ready to login to Argo CD using the CLI:


$ argocd login \
??? --name gitops \
??? --port-forward \
??? --username admin \
??? --password $PASSWORD        

Create an application in Argo CD

Time to activate GitOps! I create an application named my-app that uses my GitHub repository and my local minikube cluster, and I activate auto synchronization so that Argo CD automatically deploys my application and any new version of it in the future:


$ REPO_URL=$(gh repo view --json url --jq .url)
$ argocd app create my-app \
??? --repo $REPO_URL \
??? --path dev \
??? --dest-namespace default \
??? --dest-server https://kubernetes.default.svc \
??? --auto-prune \
??? --self-heal \
??? --sync-policy auto        

I view the status of my application with:


$ argocd app get my-app        

I get the following output:


Name:               my-app
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          default
URL:                https://127.0.0.1:49296/applications/my-app
Repo:               https://github.com/<github username>/get-started-with-gitops
Target:
Path:               dev
SyncWindow:         Sync Allowed
Sync Policy:        Automated (Prune)
Sync Status:        Synced to  (6840386)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME        STATUS  HEALTH   HOOK  MESSAGE
       Service     default    webservice  Synced  Healthy        service/webservice created
apps   Deployment  default    server      Synced  Healthy        deployment.apps/server created        

From the output I see that my Sync Status is Synced to (6840386) where the number in the parenthesis is the first seven characters of the commit SHA. My Health Status is Healthy.

I can also see that I have three instances of my Nginx pod in my cluster:


$ kubectl get pods        

I get the following output:


NAME                     READY   STATUS    RESTARTS   AGE
server-6cbf7888c-8cwcx   1/1     Running   0          1m6s
server-6cbf7888c-h5cmn   1/1     Running   0          1m6s
server-6cbf7888c-stvkm   1/1     Running   0          1m6s        

Three pods, just like I wanted. It seems like GitOps is working!

Deploy a new version

I will make a simple change to my application. Instead of running three pods I would like to run five pods. Can you imaging? Five pods! I make the required change in dev/deployment.yaml:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: server
  labels:
    app: server
spec:
  replicas: 5 # <--- this is the update
  # ...
  # the rest of the file is the same as before
  # ...        

I commit my changes to main:


$ git add . && git commit -m "Run five pods" && git push        

Argo CD syncs my application every three minutes by default. I said this guide would take five minutes, and now we might have to wait three minutes for an update? Outrageous! You can configure this behavior or trigger Argo CD to run a sync. For now I will just use the magic of editing and see if something has happened:


$ kubectl get pods        

Now I get the following response:


server-6cbf7888c-4n2w9   1/1     Running   0          38s
server-6cbf7888c-8cwcx   1/1     Running   0          4m
server-6cbf7888c-h5cmn   1/1     Running   0          4m
server-6cbf7888c-mb2zk   1/1     Running   0          38s
server-6cbf7888c-stvkm   1/1     Running   0          4m        

It worked, I now have five running pods! GitOps!

Clean up

I remove my application from Argo CD:


$ argocd app delete my-app --yes        

I shut down my minikube cluster:


$ minikube stop        

Closing thoughts

What we have seen in action is the basic principles of GitOps. This article describes the happy-path of GitOps where we skip many of the issues related to actually running this in production. Those issues vary from application to application, and we will not try to cover that in a general way here. I might revisit the GitOps topic in future articles.

要查看或添加评论,请登录

Mattias Fjellstr?m的更多文章

社区洞察

其他会员也浏览了