DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

Kubernetes CI/CD with GitOps & Argo CD

Hands-On Class (Using Real Repositories)


🎯 Class Objective

  • Understand GitOps
  • Install Argo CD
  • Build a real CI/CD pipeline
  • Use GitHub Actions for CI
  • Use Argo CD for CD
  • Debug real-world failures (ImagePullBackOff, secrets, pipelines)

This is exactly how production systems work.


🧠 CORE IDEA

❓ Why GitOps?

Traditional deployment:

❌ Manual
❌ Not auditable
❌ Not scalable

βœ… GitOps approach:

  • Git = Single Source of Truth
  • No manual kubectl apply
  • Rollback = git revert

🧩 ARCHITECTURE OVERVIEW

Developer
   |
   v
GitHub (CI Repo)
   |
   v
GitHub Actions (CI)
   |
   v
GitHub Container Registry (GHCR)
   |
   v
GitHub (GitOps Repo)
   |
   v
Argo CD (CD)
   |
   v
Kubernetes (Minikube)
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Clone this repository

git clone https://github.com/jumptotechschooldevops/k8s-ci-build.git
cd k8s-ci-build
Enter fullscreen mode Exit fullscreen mode

πŸ“‚ Structure:

k8s-ci-build/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app.js
β”‚   β”œβ”€β”€ package.json
β”‚   └── package-lock.json
└── .github/workflows/ci-cd.yml
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Purpose:

  • Build Docker image
  • Push image to GHCR
  • Update GitOps repo

2️⃣ GitOps Repository (Deployment Only)

πŸ“Œ Clone this repository

git clone https://github.com/jumptotechschooldevops/grade-api-gitops.git
cd grade-api-gitops
Enter fullscreen mode Exit fullscreen mode

πŸ“‚ Structure:

grade-api-gitops/
└── deployment.yaml
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Purpose:

  • Contains only Kubernetes manifests
  • Argo CD watches this repo
  • CI modifies this repo
  • Humans do NOT deploy manually

🧰 REQUIRED TOOLS (INSTALLATION)

1️⃣ Docker Desktop

Required for:

  • Docker builds
  • Minikube driver

Verify:

docker version
Enter fullscreen mode Exit fullscreen mode

2️⃣ kubectl

Verify:

kubectl version --client
Enter fullscreen mode Exit fullscreen mode

3️⃣ Minikube

minikube start
kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

Expected:

STATUS: Ready
Enter fullscreen mode Exit fullscreen mode

πŸš€ INSTALL ARGO CD

Step 1: Create namespace

kubectl create namespace argocd
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Argo CD

kubectl apply -n argocd \
  -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Enter fullscreen mode Exit fullscreen mode

Step 3: Wait for pods

kubectl get pods -n argocd -w
Enter fullscreen mode Exit fullscreen mode

Explain to students:

  • Init containers
  • Controllers starting
  • Normal startup delays

Step 4: Access Argo CD UI

kubectl port-forward svc/argocd-server -n argocd 8080:443
Enter fullscreen mode Exit fullscreen mode

Open browser:

https://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Ignore SSL warning.


Step 5: Login to Argo CD

Get password:

kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 --decode
Enter fullscreen mode Exit fullscreen mode

Login:

  • Username: admin
  • Password: decoded value

πŸ“¦ CREATE ARGO CD APPLICATION

πŸ“„ Create file: grade-api-app.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: grade-api
  namespace: argocd
spec:
  project: default

  source:
    repoURL: https://github.com/jumptotechschooldevops/grade-api-gitops.git
    targetRevision: main
    path: .

  destination:
    server: https://kubernetes.default.svc
    namespace: grade

  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
Enter fullscreen mode Exit fullscreen mode

Apply:

kubectl apply -f grade-api-app.yaml
Enter fullscreen mode Exit fullscreen mode

🧾 GITOPS DEPLOYMENT FILE (IMPORTANT)

πŸ“„ File:
grade-api-gitops/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grade-submission-api
  namespace: grade
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grade-submission-api
  template:
    metadata:
      labels:
        app: grade-submission-api
    spec:
      imagePullSecrets:
        - name: ghcr-secret
      containers:
        - name: grade-submission-api
          image: ghcr.io/jumptotechschooldevops/k8s-ci-build:PLACEHOLDER
          ports:
            - containerPort: 3000
Enter fullscreen mode Exit fullscreen mode

⚠️
PLACEHOLDER is intentional β€” CI will replace it.


πŸ” CREATE GHCR IMAGE PULL SECRET

GitHub PAT requirements:

  • read:packages

Create secret:

kubectl -n grade create secret docker-registry ghcr-secret \
  --docker-server=ghcr.io \
  --docker-username=jumptotechschooldevops \
  --docker-password=<YOUR_GITHUB_PAT> \
  --docker-email=devnull@example.com
Enter fullscreen mode Exit fullscreen mode

βš™οΈ CI PIPELINE (GitHub Actions)

πŸ“„ File:
k8s-ci-build/.github/workflows/ci-cd.yml

name: CI - Build Image and Update GitOps

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

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

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/jumptotechschooldevops/k8s-ci-build:${{ github.sha }}

      - name: Checkout GitOps repo
        uses: actions/checkout@v4
        with:
          repository: jumptotechschooldevops/grade-api-gitops
          token: ${{ secrets.GITOPS_PAT }}
          path: gitops

      - name: Update image tag
        run: |
          cd gitops
          sed -i "s/PLACEHOLDER/${{ github.sha }}/g" deployment.yaml

      - name: Commit and push
        run: |
          cd gitops
          git config user.name "GitHub Actions"
          git config user.email "ci@jumptotech.dev"
          git add deployment.yaml
          git commit -m "Update image to ${{ github.sha }}" || echo "No changes"
          git push
Enter fullscreen mode Exit fullscreen mode

πŸ”‘ REQUIRED GITHUB SECRETS (CI REPO)

Repo: k8s-ci-build β†’ Settings β†’ Secrets β†’ Actions

Secret Name Purpose
CR_PAT Push image to GHCR
GITOPS_PAT Push to GitOps repo

🧨 TROUBLESHOOTING (REAL ISSUES WE FACED)

❌ ImagePullBackOff

Cause:

  • Image tag = PLACEHOLDER

Fix:

  • CI replaces it with commit SHA

❌ CI error: Password required

Cause:

  • Missing CR_PAT

Fix:

  • Create GitHub PAT
  • Add to repo secrets

❌ CI error: nothing to commit

Cause:

  • File unchanged

Fix:

git commit ... || echo "No changes"
Enter fullscreen mode Exit fullscreen mode

❌ Argo CD shows Synced but pod fails

Cause:

  • Missing imagePullSecret

Fix:

  • Create ghcr-secret
  • Restart pod

βœ… FINAL VERIFICATION

kubectl get pods -n grade
Enter fullscreen mode Exit fullscreen mode

Expected:

READY   STATUS
1/1     Running
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ PIPELINE COMPLETE

Top comments (0)