Tools
Tools: Kubernetes CI/CD with GitOps & Argo CD
2026-01-27
0 views
admin
Hands-On Class (Using Real Repositories) ## ๐ฏ Class Objective ## ๐ง CORE IDEA ## โ Why GitOps? ## โ
GitOps approach: ## ๐งฉ ARCHITECTURE OVERVIEW ## 2๏ธโฃ GitOps Repository (Deployment Only) ## ๐งฐ REQUIRED TOOLS (INSTALLATION) ## 1๏ธโฃ Docker Desktop ## 2๏ธโฃ kubectl ## 3๏ธโฃ Minikube ## ๐ INSTALL ARGO CD ## Step 1: Create namespace ## Step 2: Install Argo CD ## Step 3: Wait for pods ## Step 4: Access Argo CD UI ## Step 5: Login to Argo CD ## ๐ฆ CREATE ARGO CD APPLICATION ## ๐งพ GITOPS DEPLOYMENT FILE (IMPORTANT) ## ๐ CREATE GHCR IMAGE PULL SECRET ## GitHub PAT requirements: ## โ๏ธ CI PIPELINE (GitHub Actions) ## ๐ REQUIRED GITHUB SECRETS (CI REPO) ## ๐งจ TROUBLESHOOTING (REAL ISSUES WE FACED) ## โ ImagePullBackOff ## โ CI error: Password required ## โ CI error: nothing to commit ## โ Argo CD shows Synced but pod fails ## โ
FINAL VERIFICATION This is exactly how production systems work. Traditional deployment: โ Manual โ Not auditable โ Not scalable ๐ Clone this repository ๐ Clone this repository ๐ Create file: grade-api-app.yaml ๐ File: grade-api-gitops/deployment.yaml โ ๏ธ PLACEHOLDER is intentional โ CI will replace it. ๐ File: k8s-ci-build/.github/workflows/ci-cd.yml Repo: k8s-ci-build โ Settings โ Secrets โ Actions Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. as well , this person and/or CODE_BLOCK: 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) CODE_BLOCK: 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) CODE_BLOCK: 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) COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/k8s-ci-build.git cd k8s-ci-build COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/k8s-ci-build.git cd k8s-ci-build COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/k8s-ci-build.git cd k8s-ci-build CODE_BLOCK: k8s-ci-build/ โโโ Dockerfile โโโ src/ โ โโโ app.js โ โโโ package.json โ โโโ package-lock.json โโโ .github/workflows/ci-cd.yml CODE_BLOCK: k8s-ci-build/ โโโ Dockerfile โโโ src/ โ โโโ app.js โ โโโ package.json โ โโโ package-lock.json โโโ .github/workflows/ci-cd.yml CODE_BLOCK: k8s-ci-build/ โโโ Dockerfile โโโ src/ โ โโโ app.js โ โโโ package.json โ โโโ package-lock.json โโโ .github/workflows/ci-cd.yml COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/grade-api-gitops.git cd grade-api-gitops COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/grade-api-gitops.git cd grade-api-gitops COMMAND_BLOCK: git clone https://github.com/jumptotechschooldevops/grade-api-gitops.git cd grade-api-gitops CODE_BLOCK: grade-api-gitops/ โโโ deployment.yaml CODE_BLOCK: grade-api-gitops/ โโโ deployment.yaml CODE_BLOCK: grade-api-gitops/ โโโ deployment.yaml COMMAND_BLOCK: docker version COMMAND_BLOCK: docker version COMMAND_BLOCK: docker version COMMAND_BLOCK: kubectl version --client COMMAND_BLOCK: kubectl version --client COMMAND_BLOCK: kubectl version --client CODE_BLOCK: minikube start kubectl get nodes CODE_BLOCK: minikube start kubectl get nodes CODE_BLOCK: minikube start kubectl get nodes CODE_BLOCK: STATUS: Ready CODE_BLOCK: STATUS: Ready CODE_BLOCK: STATUS: Ready COMMAND_BLOCK: kubectl create namespace argocd COMMAND_BLOCK: kubectl create namespace argocd COMMAND_BLOCK: kubectl create namespace argocd COMMAND_BLOCK: kubectl apply -n argocd \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml COMMAND_BLOCK: kubectl apply -n argocd \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml COMMAND_BLOCK: kubectl apply -n argocd \ -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml COMMAND_BLOCK: kubectl get pods -n argocd -w COMMAND_BLOCK: kubectl get pods -n argocd -w COMMAND_BLOCK: kubectl get pods -n argocd -w COMMAND_BLOCK: kubectl port-forward svc/argocd-server -n argocd 8080:443 COMMAND_BLOCK: kubectl port-forward svc/argocd-server -n argocd 8080:443 COMMAND_BLOCK: kubectl port-forward svc/argocd-server -n argocd 8080:443 CODE_BLOCK: https://localhost:8080 CODE_BLOCK: https://localhost:8080 CODE_BLOCK: https://localhost:8080 COMMAND_BLOCK: kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 --decode COMMAND_BLOCK: kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 --decode COMMAND_BLOCK: kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 --decode CODE_BLOCK: apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: grade-api namespace: argocd spec: project: default 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 CODE_BLOCK: apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: grade-api namespace: argocd spec: project: default 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 CODE_BLOCK: apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: grade-api namespace: argocd spec: project: default 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 COMMAND_BLOCK: kubectl apply -f grade-api-app.yaml COMMAND_BLOCK: kubectl apply -f grade-api-app.yaml COMMAND_BLOCK: kubectl apply -f grade-api-app.yaml CODE_BLOCK: 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 CODE_BLOCK: 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 CODE_BLOCK: 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 COMMAND_BLOCK: kubectl -n grade create secret docker-registry ghcr-secret \ --docker-server=ghcr.io \ --docker-username=jumptotechschooldevops \ --docker-password=<YOUR_GITHUB_PAT> \ [email protected] COMMAND_BLOCK: kubectl -n grade create secret docker-registry ghcr-secret \ --docker-server=ghcr.io \ --docker-username=jumptotechschooldevops \ --docker-password=<YOUR_GITHUB_PAT> \ [email protected] COMMAND_BLOCK: kubectl -n grade create secret docker-registry ghcr-secret \ --docker-server=ghcr.io \ --docker-username=jumptotechschooldevops \ --docker-password=<YOUR_GITHUB_PAT> \ [email protected] CODE_BLOCK: 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 "[email protected]" git add deployment.yaml git commit -m "Update image to ${{ github.sha }}" || echo "No changes" git push CODE_BLOCK: 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 "[email protected]" git add deployment.yaml git commit -m "Update image to ${{ github.sha }}" || echo "No changes" git push CODE_BLOCK: 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 "[email protected]" git add deployment.yaml git commit -m "Update image to ${{ github.sha }}" || echo "No changes" git push COMMAND_BLOCK: git commit ... || echo "No changes" COMMAND_BLOCK: git commit ... || echo "No changes" COMMAND_BLOCK: git commit ... || echo "No changes" COMMAND_BLOCK: kubectl get pods -n grade COMMAND_BLOCK: kubectl get pods -n grade COMMAND_BLOCK: kubectl get pods -n grade CODE_BLOCK: READY STATUS 1/1 Running CODE_BLOCK: READY STATUS 1/1 Running CODE_BLOCK: READY STATUS 1/1 Running - 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) - Git = Single Source of Truth - No manual kubectl apply - Rollback = git revert - Build Docker image - Push image to GHCR - Update GitOps repo - Contains only Kubernetes manifests - Argo CD watches this repo - CI modifies this repo - Humans do NOT deploy manually - Docker builds - Minikube driver - Init containers - Controllers starting - Normal startup delays - Username: admin - Password: decoded value - read:packages - Image tag = PLACEHOLDER - CI replaces it with commit SHA - Missing CR_PAT - Create GitHub PAT - Add to repo secrets - File unchanged - Missing imagePullSecret - Create ghcr-secret - Restart pod
toolsutilitiessecurity toolskubernetesgitopsrepositoriesobjectiveapproach