Devops
DevopsIntermediate

GitOps: Infrastructure as Code with Git-Centric Workflows

DeveloperHat Team
5 min read
GitOpsInfrastructure as CodeCI/CDKubernetes

TL;DR

Learn how to implement GitOps practices for infrastructure management, continuous deployment, and automated operations using tools like ArgoCD and Flux

import { MermaidDiagram } from '@/components/mermaid-diagram'

Learn how to implement GitOps practices for infrastructure management, continuous deployment, and automated operations. This comprehensive guide covers principles, tools, and best practices.

diagram={

graph TB

subgraph "Source Control"

Git["Git Repository"]

PR["Pull Request"]

Review["Code Review"]

end

subgraph "CI Pipeline"

Build["Build"]

Test["Test"]

Image["Image Build"]

end

subgraph "CD Pipeline"

ArgoCD["ArgoCD"]

Sync["Sync"]

Deploy["Deploy"]

end

Git --> PR

PR --> Review

Review --> Build

Build --> Test

Test --> Image

Image --> ArgoCD

ArgoCD --> Sync

Sync --> Deploy

style Git fill:#3b82f6,stroke:#2563eb,color:white

style PR fill:#3b82f6,stroke:#2563eb,color:white

style Review fill:#3b82f6,stroke:#2563eb,color:white

style Build fill:#f1f5f9,stroke:#64748b

style Test fill:#f1f5f9,stroke:#64748b

style Image fill:#f1f5f9,stroke:#64748b

style ArgoCD fill:#f1f5f9,stroke:#64748b

style Sync fill:#f1f5f9,stroke:#64748b

style Deploy fill:#f1f5f9,stroke:#64748b

}

/>

$1

GitOps principles include:

1. Declarative Configuration: Infrastructure as code

2. Version Control: Single source of truth

3. Automated Sync: Continuous reconciliation

4. Drift Detection: Automatic correction

5. Audit Trail: Complete history

$1

$1

Install and configure ArgoCD:

``yaml

argocd-install.yaml

apiVersion: v1

kind: Namespace

metadata:

name: argocd

---

apiVersion: helm.cattle.io/v1

kind: HelmChart

metadata:

name: argocd

namespace: argocd

spec:

repo: https://argoproj.github.io/argo-helm

chart: argo-cd

version: 5.51.6

targetNamespace: argocd

valuesContent: |-

server:

extraArgs:

- --insecure

config:

repositories: |

- type: git

url: https://github.com/your-org/your-repo.git

username: git

password:

configManagementPlugins: |

- name: kustomize

init:

command: ["/bin/sh", "-c"]

args: ["kustomize version"]

generate:

command: ["/bin/sh", "-c"]

args: ["kustomize build"]

redis:

enabled: true

dex:

enabled: true

repoServer:

serviceAccount:

create: true

name: argocd-repo-server

controller:

serviceAccount:

create: true

name: argocd-application-controller

applicationSet:

enabled: true

`

$1

Define application using Kustomize:

`yaml

kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1

kind: Kustomization

resources:

- deployment.yaml

- service.yaml

- ingress.yaml

- configmap.yaml

- secret.yaml

namePrefix: myapp-

nameSuffix: -prod

commonLabels:

app: myapp

environment: production

commonAnnotations:

maintainer: devops-team

contact: devops@example.com

configMapGenerator:

- name: app-config

files:

- config/app.properties

literals:

- API_URL=https://api.example.com

- ENVIRONMENT=production

secretGenerator:

- name: app-secrets

files:

- secrets/api-key.txt

literals:

- DB_PASSWORD=ENC[AES256_GCM,data:xxx,tag:yyy]

images:

- name: myapp

newName: registry.example.com/myapp

newTag: v1.2.3

patches:

- path: patches/increase-replica-count.yaml

target:

kind: Deployment

name: myapp

replacements:

- source:

kind: ConfigMap

name: app-config

fieldPath: data.API_URL

targets:

- select:

kind: Deployment

name: myapp

fieldPaths:

- spec.template.spec.containers.[name=myapp].env.[name=API_URL].value

configurations:

- kustomizeconfig.yaml

`

$1

Define ArgoCD application:

`yaml

application.yaml

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: myapp

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/your-org/your-repo.git

targetRevision: HEAD

path: k8s/overlays/production

kustomize:

images:

- registry.example.com/myapp:v1.2.3

destination:

server: https://kubernetes.default.svc

namespace: production

syncPolicy:

automated:

prune: true

selfHeal: true

syncOptions:

- CreateNamespace=true

- PruneLast=true

- ApplyOutOfSyncOnly=true

retry:

limit: 5

backoff:

duration: 5s

factor: 2

maxDuration: 3m

ignoreDifferences:

- group: apps

kind: Deployment

jsonPointers:

- /spec/replicas

revisionHistoryLimit: 10

`

$1

Configure GitHub Actions workflow:

`yaml

.github/workflows/ci.yaml

name: CI Pipeline

on:

push:

branches: [ main ]

pull_request:

branches: [ main ]

env:

REGISTRY: registry.example.com

IMAGE_NAME: myapp

KUSTOMIZE_VERSION: 5.1.1

jobs:

build-and-test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Set up Node.js

uses: actions/setup-node@v4

with:

node-version: '20'

cache: 'npm'

- name: Install dependencies

run: npm ci

- name: Run tests

run: npm test

- name: Run linting

run: npm run lint

- name: Build application

run: npm run build

security-scan:

needs: build-and-test

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Run SAST scan

uses: github/codeql-action/analyze@v2

- name: Run dependency scan

run: |

npm audit

trivy fs .

build-image:

needs: security-scan

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Set up Docker Buildx

uses: docker/setup-buildx-action@v3

- name: Login to registry

uses: docker/login-action@v3

with:

registry: ${{ env.REGISTRY }}

username: ${{ secrets.REGISTRY_USERNAME }}

password: ${{ secrets.REGISTRY_PASSWORD }}

- name: Build and push

uses: docker/build-push-action@v5

with:

context: .

push: true

tags: |

${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache

cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max

update-manifests:

needs: build-image

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Install Kustomize

run: |

curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash

sudo mv kustomize /usr/local/bin/

- name: Update image tag

run: |

cd k8s/overlays/production

kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

- name: Commit and push changes

run: |

git config --global user.name 'GitHub Actions'

git config --global user.email 'actions@github.com'

git add k8s/overlays/production/kustomization.yaml

git commit -m "Update image tag to ${{ github.sha }}"

git push

`

diagram={

graph TB

subgraph "Git Repository"

Code["Application Code"]

K8s["K8s Manifests"]

CI["CI Pipeline"]

end

subgraph "Container Registry"

Build["Image Build"]

Push["Image Push"]

Tag["Image Tag"]

end

subgraph "Kubernetes"

ArgoCD["ArgoCD"]

Watch["Watch Changes"]

Apply["Apply Changes"]

end

Code --> CI

CI --> Build

Build --> Push

Push --> Tag

K8s --> ArgoCD

ArgoCD --> Watch

Watch --> Apply

style Code fill:#3b82f6,stroke:#2563eb,color:white

style K8s fill:#3b82f6,stroke:#2563eb,color:white

style CI fill:#3b82f6,stroke:#2563eb,color:white

style Build fill:#f1f5f9,stroke:#64748b

style Push fill:#f1f5f9,stroke:#64748b

style Tag fill:#f1f5f9,stroke:#64748b

style ArgoCD fill:#f1f5f9,stroke:#64748b

style Watch fill:#f1f5f9,stroke:#64748b

style Apply fill:#f1f5f9,stroke:#64748b

`}

/>

$1

$1

  • Clear organization
  • Environment separation
  • Documentation
  • Security scanning
  • Version control
  • $1

  • Automated testing
  • Security checks
  • Image scanning
  • Version tagging
  • Notifications
  • $1

  • Health checks
  • Drift detection
  • Audit logging
  • Metrics collection
  • Alerting
  • $1

  • RBAC configuration
  • Secrets management
  • Network policies
  • Image scanning
  • Access control
  • $1

    Effective GitOps implementation requires:

    1. Clear processes

    2. Automation

    3. Security controls

    4. Monitoring

    5. Documentation

    Remember to:

  • Follow best practices
  • Automate everything
  • Monitor closely
  • Document changes
  • Review regularly
  • $1

    1. [ArgoCD Documentation](https://argo-cd.readthedocs.io/)

    2. [Flux Documentation](https://fluxcd.io/docs/)

    3. [GitOps Principles](https://www.weave.works/technologies/gitops/)

    4. [Kubernetes Best Practices](https://kubernetes.io/docs/concepts/configuration/overview/)

    5. [Container Security](https://docs.docker.com/develop/security-best-practices/)

    Why This Matters

    Understanding the business and technical context helps you make informed decisions rather than blindly following patterns.

    Trade-offs to Consider

    Every architectural decision involves trade-offs. Consider your specific requirements, team expertise, and scale when evaluating options.

    When NOT to Use This

    Knowing when a solution doesn't apply is as valuable as knowing when it does. Consider alternatives for your specific situation.

    Decision Framework

    Use this framework to evaluate whether this approach is right for your use case based on your specific constraints and requirements.