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 hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse 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) Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
grade-api-gitops/
βββ deployment.yaml CODE_BLOCK:
grade-api-gitops/
βββ deployment.yaml COMMAND_BLOCK:
docker version Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
docker version COMMAND_BLOCK:
docker version COMMAND_BLOCK:
kubectl version --client Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
kubectl version --client COMMAND_BLOCK:
kubectl version --client CODE_BLOCK:
minikube start
kubectl get nodes Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
minikube start
kubectl get nodes CODE_BLOCK:
minikube start
kubectl get nodes CODE_BLOCK:
STATUS: Ready Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
STATUS: Ready CODE_BLOCK:
STATUS: Ready COMMAND_BLOCK:
kubectl create namespace argocd Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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 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 CODE_BLOCK:
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 CODE_BLOCK:
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 COMMAND_BLOCK:
kubectl apply -f grade-api-app.yaml Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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] Enter fullscreen mode Exit fullscreen mode 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 Enter fullscreen mode Exit fullscreen mode 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" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
git commit ... || echo "No changes" COMMAND_BLOCK:
git commit ... || echo "No changes" COMMAND_BLOCK:
kubectl get pods -n grade Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
kubectl get pods -n grade COMMAND_BLOCK:
kubectl get pods -n grade CODE_BLOCK:
READY STATUS
1/1 Running Enter fullscreen mode Exit fullscreen mode 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
how-totutorialguidedev.toaimlubuntuserverdockernodekubernetesk8sgitgithub