Implementing GitOps

Implementing GitOps

Published on
Authors

In today’s rapidly evolving DevOps landscape, GitOps has become a powerful approach to managing infrastructure and deployments. By treating your entire system configuration as code, stored in Git repositories, GitOps ensures consistency, traceability, and automated synchronization between your desired state (in Git) and the actual state (in production).

This differs from traditional DevOps pipelines, where deployments are often triggered and executed directly by CI/CD tools. With GitHub Actions and GitOps principles, you can automate builds, tests, and manifest updates while leveraging tools like ArgoCD or FluxCD for pull-based deployments to Kubernetes clusters.

This guide will walk you through implementing a GitOps pipeline using GitHub Actions for CI and ArgoCD for synchronization, complete with step-by-step instructions, sample workflows, and diagrams that clearly explain each process.


πŸ” Understanding GitOps vs. Traditional DevOps

Before diving into implementation, it’s essential to understand how GitOps differs from the conventional CI/CD pipelines.

βœ… Traditional DevOps Pipeline

In a standard setup:

  1. Developers push code to a repository.
  2. CI runs unit tests and builds artifacts.
  3. A Docker image is created and pushed to a registry (e.g., v2.4).
  4. The deployment is pushed directly to the cluster using commands like kubectl apply.

This is a push-based model where the CI/CD tool initiates deployment.

Diagram – Traditional DevOps

+-----------------+    +----------------+    +----------------+    +----------------+    +----------------+
| Developer Code  | -> | Push to Repo   | -> | Run Unit Tests | -> | Build Artifact | -> | Build Image    |
+-----------------+    +----------------+    +----------------+    +----------------+    +----------------+
                                                                                                |
                                                                                                v
                                                                                    +----------------------+
                                                                                    | Push to Registry     |
                                                                                    | Deploy to K8s        |
                                                                                    | (kubectl apply v2.4) |
                                                                                    +----------------------+

βœ… GitOps Pipeline

GitOps leverages Git as the source of truth:

  1. CI builds and tests as usual, creating an image (e.g., v6.7).
  2. Instead of directly deploying, a Pull Request (PR) is raised to update Kubernetes manifests in a separate repository.
  3. After approval and merge, a GitOps operator like ArgoCD pulls the updated manifest and synchronizes the cluster.

This is a pull-based model where the cluster reconciles with Git changes.

Diagram – GitOps Workflow

+-----------------+    +----------------+    +----------------+    +----------------+    +----------------+
| Developer Code  | -> | Push to Repo   | -> | Run Unit Tests | -> | Build Artifact | -> | Build Image    |
+-----------------+    +----------------+    +----------------+    +----------------+    +----------------+
                                                                                          |
                                                                                          v
                                                   +----------------+    +----------------+    +----------------+
                                                   |Push to Registry| -> | Raise PR       | -> |Update Manifests|
                                                   |                |    | Feature Branch |    | (v6.7)         |
                                                   +----------------+    +----------------+    +----------------+
                                                                                    |
                                                                                    v
                                                   +----------------+    +----------------+     +----------------+
                                                   | Approve & Merge| -> | ArgoCD Pulls   |  -> | Sync Cluster   |
                                                   | PR             |    |Updated Manifests|    | to Match v6.7  |
                                                   +----------------+    +----------------+     +----------------+

βœ… Benefits of GitOps with GitHub Actions

  • βœ… Version Control for Infrastructure: All changes are tracked, auditable, and reversible.
  • βœ… Consistency Across Environments: Use the same manifests across dev, staging, and production.
  • βœ… Reduced Risk: PR reviews catch errors early, and reconciliation ensures stability.
  • βœ… Scalability: Teams collaborate using Git workflows without stepping on each other’s changes.
  • βœ… Security: No direct access to clusters from CI tools.

Drawbacks:

  • Requires extra setup and tooling (like ArgoCD).
  • Involves more repositories and workflows.
  • Requires understanding of GitOps concepts.

βœ… Prerequisites

To implement this pipeline, you’ll need:

βœ” A GitHub account with two repositories:

  • app-repo: For application code.
  • config-repo: For Kubernetes manifests.

βœ” A Kubernetes cluster (Minikube for testing or EKS/AKS/GKE for production).

βœ” A container registry like Docker Hub or GitHub Container Registry.

βœ” ArgoCD installed in the cluster.

βœ” GitHub secrets for authentication (registry tokens, kubeconfig).

βœ” Familiarity with Docker, YAML, and Kubernetes basics.

Install ArgoCD with:

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

Create an Application in ArgoCD pointing to your config-repo.


πŸš€ Step-by-Step Implementation

βœ… Step 1 – Application Repository Setup

In app-repo, include:

  • Your application code (e.g., Node.js server).
  • Dockerfile.
  • GitHub Actions workflow (ci.yml).

Example Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]

βœ… Step 2 – CI Workflow with GitHub Actions

Create .github/workflows/ci.yml for building, testing, and pushing the image.

name: CI - Build and Push Image

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push
        uses: docker/build-push-action@v6
        with:
          push: true
          tags: ghcr.io/${{ github.repository_owner }}/my-app:${{ github.sha }}

βœ… Step 3 – Automate Manifest Updates via PR

After the image is built, clone config-repo, update the manifest, and create a PR.

update-manifests:
  needs: build
  runs-on: ubuntu-latest
  if: github.ref == 'refs/heads/main'
  steps:
    - uses: actions/checkout@v4
      with:
        repository: your-org/config-repo
        path: config
        token: ${{ secrets.CONFIG_REPO_TOKEN }}

    - name: Update Image Tag
      run: |
        sed -i 's|image: ghcr.io/your-org/my-app:.*|image: ghcr.io/your-org/my-app:${{ github.sha }}|' config/deployment.yaml
        cd config
        git config user.name "GitHub Actions"
        git config user.email "actions@github.com"
        git add deployment.yaml
        git commit -m "Update image to ${{ github.sha }}"
        git push origin main

    - name: Create Pull Request
      uses: peter-evans/create-pull-request@v6
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
        path: config
        commit-message: 'Update deployment image to ${{ github.sha }}'
        title: 'Automated manifest update for commit ${{ github.sha }}'
        body: 'This PR updates Kubernetes manifests with the latest image.'
        branch: update-manifest-${{ github.sha }}

βœ… Step 4 – ArgoCD Synchronization

ArgoCD watches config-repo and applies changes automatically after a PR merge.

Sample ArgoCD Application YAML

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/config-repo.git
    targetRevision: main
    path: .
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Diagram – ArgoCD Sync

+---------------+     +--------------+     +---------------+
| Merge PR      | ->  | Git Commit  |  ->  |ArgoCD Detects |
| (Manifests)   |     | (v6.7)      |      |    Change     |
+---------------+     +--------------+     +---------------+
                                              |
                                              v
                                      +--------------+
                                      | Apply to K8s |
                                      | Cluster Sync |
                                      +--------------+

βœ… Step 5 – Adding Tests and Security

Extend your pipeline by adding tests:

test:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: '20'
    - run: npm install
    - run: npm test

Use image scanning tools like Trivy to ensure your builds are secure.


βœ… Step 6 – Supporting Multi-Environments

Manage environments by creating branches in config-repo:

  • dev, staging, prod.
  • Parameterize manifests using Helm or Kustomize.
  • Use different ArgoCD applications for each environment.

βœ… Best Practices

  • πŸ” Security First: Use GitHub OIDC instead of static secrets.
  • πŸ“Š Monitoring: Integrate ArgoCD with Prometheus.
  • 🧩 Tooling Choices: Helm for complex deployments, FluxCD for simpler setups.
  • ↩ Rollback: Use Git revert and let ArgoCD sync the change.
  • βš™ Automation: Add linting, format checks, and security scans.
  • 🚧 Avoid Pitfalls: Ensure permissions and handle merge conflicts gracefully.

πŸ“– Combined Workflow Visualization

CI + GitOps Flow

 Developer Workflow (GitHub Actions)
+----------------+   +---------------+   +---------------+   +---------------+   +----------------+
| Developer Code | ->| Run Unit Test | ->| Build Image   | ->| Push to Registry| ->| Update Manifest|
| Push to Repo   |   |               |   | v6.7          |   | (ghcr.io)      |   | & Raise PR     |
+----------------+   +---------------+   +---------------+   +----------------+   +----------------+

 GitOps Workflow (ArgoCD)
+----------------+   +----------------+   +----------------+
| Merge PR       | ->| Git Commit     | ->| ArgoCD Sync   |
| (Update Manifests)| | (v6.7)        |   | to Kubernetes |
+----------------+   +----------------+   +----------------+

βœ… Conclusion

By combining GitHub Actions with ArgoCD, you can build a secure, scalable, and auditable GitOps pipeline for Kubernetes deployments. This approach empowers teams to collaborate efficiently while minimizing risks, ensuring reproducibility, and improving visibility into infrastructure changes.

Start by implementing this for a small test app, refine your workflows, and scale toward a production-ready deployment architecture. With the right tooling and best practices, GitOps can transform your deployment process into a reliable and developer-friendly workflow.

Happy GitOps-ing! πŸš€

Cheers,

Sim