Module 11: CI/CD Pipeline — GitHub Actions + ArgoCD
🎯 What You'll Build: A complete GitOps CI/CD pipeline where pushing code triggers automated testing, Docker image builds, registry publishing, Git manifest updates, and Kubernetes deployment through ArgoCD.
⏱️ Time: 6 hours
📋 Prerequisites: Module 10 — Kubernetes Manifests
🎯 Difficulty: Intermediate
In the previous module, you manually deployed DeployMart to Kubernetes using manifests.
That works well while learning, but imagine making a code change every day and manually running:
1docker build 2docker push 3kubectl apply 4kubectl rollout status
That quickly becomes repetitive and error-prone.
A modern Kubernetes workflow automates these steps.
The goal of this module is to build a pipeline where:
1Developer 2 │ 3 │ git push 4 ▼ 5GitHub 6 │ 7 ▼ 8GitHub Actions 9 │ 10 ├── Run tests 11 ├── Build Docker image 12 ├── Push image 13 └── Update Git deployment configuration 14 │ 15 ▼ 16 Git Repository 17 │ 18 ▼ 19 ArgoCD 20 │ 21 ▼ 22 Kubernetes 23 │ 24 ▼ 25 DeployMart
This approach is called GitOps.
What Is CI/CD?
CI/CD stands for Continuous Integration and Continuous Delivery/Deployment.
Continuous Integration focuses on automatically validating code changes.
For example:
1Developer pushes code 2 ↓ 3Run linting 4 ↓ 5Run unit tests 6 ↓ 7Build application 8 ↓ 9Build Docker image
Continuous Delivery or Deployment takes the validated application further:
1Validated application 2 ↓ 3Push image 4 ↓ 5Update deployment configuration 6 ↓ 7Deploy to Kubernetes
The important idea is:
Every change should move through a predictable, automated process.
CI vs CD
These concepts are related but not identical.
Continuous Integration
CI answers:
Is this code change safe to integrate?
Typical CI tasks include:
- Installing dependencies.
- Running linters.
- Running unit tests.
- Running integration tests.
- Building applications.
- Building Docker images.
Continuous Delivery
Continuous Delivery answers:
Is this version ready to be deployed?
The artifact is automatically prepared, but production deployment may require approval.
Continuous Deployment
Continuous Deployment goes one step further:
Automatically deploy every approved change.
In this module, ArgoCD will provide the continuous deployment mechanism for Kubernetes.
What Is GitOps?
GitOps treats Git as the source of truth for the desired state of your infrastructure and applications.
Instead of saying:
1kubectl set image deployment/backend backend=image:1.2.3
and making the cluster the primary record of the change, you update the configuration stored in Git.
For example:
1images: 2 - name: deploymart-backend 3 newName: ghcr.io/example/deploymart-backend 4 newTag: abc1234
Git records the desired state.
ArgoCD continuously compares:
1Git desired state 2 vs 3Kubernetes actual state
If they differ, ArgoCD can synchronize the cluster.
GitOps Architecture
Our DeployMart architecture becomes:
1 Developer 2 │ 3 git push 4 │ 5 ▼ 6 ┌───────────────┐ 7 │ GitHub │ 8 └───────┬───────┘ 9 │ 10 ▼ 11 ┌───────────────┐ 12 │ GitHub Actions│ 13 │ CI │ 14 └───────┬───────┘ 15 │ 16 ┌───────────┴───────────┐ 17 │ │ 18 Test Code Build Image 19 │ 20 ▼ 21 Container Registry 22 │ 23 ▼ 24 Update Kustomize 25 │ 26 ▼ 27 Git Repository 28 │ 29 ▼ 30 ┌────────┐ 31 │ ArgoCD │ 32 └───┬────┘ 33 │ 34 ▼ 35 Kubernetes 36 │ 37 ▼ 38 DeployMart
There are two important systems here:
GitHub Actions performs the CI work.
ArgoCD performs GitOps-based continuous deployment.
Why Not Let GitHub Actions Run kubectl apply?
A beginner-friendly pipeline might look like:
1GitHub Actions 2 │ 3 └── kubectl apply 4 │ 5 ▼ 6 Kubernetes
This can work, but it creates a different operational model.
With GitOps:
1GitHub Actions 2 │ 3 ▼ 4Update Git 5 │ 6 ▼ 7ArgoCD 8 │ 9 ▼ 10Kubernetes
The Git repository becomes the auditable declaration of what should be deployed.
This gives you useful properties:
- Git history records deployment configuration changes.
- ArgoCD continuously observes the cluster.
- Configuration can be reviewed through pull requests.
- Drift can be detected.
- Rollbacks can use Git history.
- CI and CD responsibilities are separated.
Recommended Repository Structure
A simple setup can use two repositories.
Application Repository
1deploymart/ 2├── backend/ 3├── frontend/ 4├── tests/ 5├── Dockerfile 6└── .github/ 7 └── workflows/ 8 └── ci.yaml
This repository contains application source code.
GitOps Repository
1deploymart-gitops/ 2├── apps/ 3│ └── deploymart/ 4│ ├── namespace.yaml 5│ ├── backend.yaml 6│ ├── frontend.yaml 7│ ├── services.yaml 8│ ├── ingress.yaml 9│ └── kustomization.yaml 10│ 11└── environments/ 12 ├── development/ 13 └── production/
This repository contains Kubernetes desired state.
Keeping application code and deployment configuration separate is not mandatory, but it is a useful GitOps pattern.
Container Image Tagging Strategy
Do not use only:
1latest
for automated deployments.
Instead, use an immutable identifier such as a Git commit SHA:
1ghcr.io/example/deploymart-backend:8f3a21c
The commit SHA gives you traceability:
1Git commit 2 │ 3 ├── Source code 4 ├── Tests 5 ├── Docker image 6 └── Kubernetes deployment
You can immediately determine which source revision produced the running image.
A useful tagging strategy is:
1main branch 2 ↓ 3commit SHA 4 ↓ 5Docker image 6 ↓ 7Kubernetes
For example:
1deploymart-backend:8f3a21c 2deploymart-frontend:8f3a21c
You can also publish semantic version tags for releases:
11.4.0
while keeping the SHA tag for traceability.
GitHub Actions Workflow
GitHub Actions workflows live inside:
1.github/workflows/
Create:
1.github/workflows/ci-cd.yaml
A practical workflow looks like this:
1name: DeployMart CI/CD 2 3on: 4 push: 5 branches: 6 - main 7 8permissions: 9 contents: write 10 packages: write 11 12env: 13 REGISTRY: ghcr.io 14 IMAGE_PREFIX: ${{ github.repository_owner }}/deploymart 15 16jobs: 17 18 test: 19 name: Run Tests 20 runs-on: ubuntu-latest 21 22 steps: 23 - name: Checkout repository 24 uses: actions/checkout@v4 25 26 - name: Set up Python 27 uses: actions/setup-python@v5 28 with: 29 python-version: "3.12" 30 31 - name: Install backend dependencies 32 working-directory: backend 33 run: | 34 pip install -r requirements.txt 35 36 - name: Run Django tests 37 working-directory: backend 38 run: | 39 python manage.py test 40 41 build: 42 name: Build and Push Images 43 needs: test 44 runs-on: ubuntu-latest 45 46 permissions: 47 contents: read 48 packages: write 49 50 steps: 51 - name: Checkout repository 52 uses: actions/checkout@v4 53 54 - name: Log in to GitHub Container Registry 55 uses: docker/login-action@v3 56 with: 57 registry: ${{ env.REGISTRY }} 58 username: ${{ github.actor }} 59 password: ${{ secrets.GITHUB_TOKEN }} 60 61 - name: Build backend image 62 run: | 63 docker build \ 64 -t ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-backend:${{ github.sha }} \ 65 ./backend 66 67 - name: Build frontend image 68 run: | 69 docker build \ 70 -t ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-frontend:${{ github.sha }} \ 71 ./frontend 72 73 - name: Push backend image 74 run: | 75 docker push \ 76 ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-backend:${{ github.sha }} 77 78 - name: Push frontend image 79 run: | 80 docker push \ 81 ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-frontend:${{ github.sha }} 82 83 update-manifests: 84 name: Update GitOps Repository 85 needs: build 86 runs-on: ubuntu-latest 87 88 steps: 89 - name: Checkout GitOps repository 90 uses: actions/checkout@v4 91 with: 92 repository: example/deploymart-gitops 93 token: ${{ secrets.GITOPS_TOKEN }} 94 path: gitops 95 96 - name: Update image tags 97 working-directory: gitops 98 run: | 99 cd environments/development 100 101 sed -i \ 102 "s/newTag: .*/newTag: ${{ github.sha }}/" \ 103 kustomization.yaml 104 105 - name: Commit manifest changes 106 working-directory: gitops 107 run: | 108 git config user.name "github-actions[bot]" 109 git config user.email "41898282+github-actions[bot]@users.noreply.github.com" 110 111 git add . 112 113 git commit \ 114 -m "deploy: ${{ github.sha }}" || exit 0 115 116 git push
The exact workflow will depend on your repository structure, registry, test setup, and GitOps repository.
The important architecture is:
1test 2 ↓ 3build 4 ↓ 5push image 6 ↓ 7update GitOps
The needs property ensures that a later job waits for the previous job to succeed.
For example:
1needs: test
means the image build should not start if the tests fail.
Understanding GITHUB_SHA
GitHub Actions exposes the commit SHA through:
1${{ github.sha }}
Suppose the commit is:
18f3a21c...
The Docker image becomes:
1ghcr.io/example/deploymart-backend:8f3a21c...
This creates a direct relationship:
1Git commit 8f3a21c 2 ↓ 3Docker image 8f3a21c 4 ↓ 5Kubernetes deployment 8f3a21c
This traceability becomes extremely valuable when debugging production deployments.
GitHub Container Registry
The workflow can publish images to GitHub Container Registry using:
1ghcr.io
The login step is:
1- name: Log in to GitHub Container Registry 2 uses: docker/login-action@v3 3 with: 4 registry: ghcr.io 5 username: ${{ github.actor }} 6 password: ${{ secrets.GITHUB_TOKEN }}
The workflow needs permission to publish packages:
1permissions: 2 packages: write
For a production pipeline, keep permissions as narrow as possible.
The principle is:
Give each workflow only the permissions it actually needs.
Kustomize for Image Updates
Kustomize allows you to customize Kubernetes manifests without copying the entire YAML configuration.
A basic kustomization.yaml might look like:
1apiVersion: kustomize.config.k8s.io/v1beta1 2kind: Kustomization 3 4namespace: deploymart 5 6resources: 7 - namespace.yaml 8 - backend.yaml 9 - frontend.yaml 10 - services.yaml 11 - ingress.yaml 12 13images: 14 - name: deploymart-backend 15 newName: ghcr.io/example/deploymart-backend 16 newTag: 8f3a21c 17 18 - name: deploymart-frontend 19 newName: ghcr.io/example/deploymart-frontend 20 newTag: 8f3a21c
Now the image version is controlled through Git.
When a new image is produced:
18f3a21c
the CI pipeline changes it to:
19bd71aa
and commits the change.
Why Kustomize Matters in GitOps
Without Kustomize, you may repeatedly modify:
1image: ghcr.io/example/deploymart-backend:8f3a21c
inside several YAML files.
Kustomize gives you a cleaner separation:
1Base Kubernetes configuration 2 + 3Environment-specific configuration 4 + 5Image version 6 ↓ 7Final Kubernetes configuration
This becomes particularly useful when you have:
1development 2staging 3production
with different image versions and configuration.
Install ArgoCD
ArgoCD runs inside Kubernetes and watches Git repositories.
For a learning cluster, install ArgoCD using its official installation manifest.
After installation, verify the namespace:
1kubectl get pods -n argocd
You should see ArgoCD components becoming ready.
Typical components include:
1argocd-server 2argocd-repo-server 3argocd-application-controller 4argocd-dex-server 5argocd-redis
The exact set of components can vary by ArgoCD version and installation configuration.
How ArgoCD Works
ArgoCD continuously observes:
1Git Repository 2 │ 3 ▼ 4Desired Kubernetes state 5 │ 6 │ compare 7 ▼ 8Kubernetes Cluster 9 │ 10 ▼ 11Actual state
Suppose Git says:
1newTag: 8f3a21c
but Kubernetes is currently running:
1newTag: 5c72abc
ArgoCD detects the difference.
This is called drift.
Conceptually:
1Git 2 │ 3 │ desired = 8f3a21c 4 │ 5 ▼ 6ArgoCD 7 │ 8 │ actual = 5c72abc 9 │ 10 ▼ 11Kubernetes 12 13 ↓ 14 15 OUT OF SYNC
When synchronization is enabled, ArgoCD reconciles the cluster toward the Git state.
Create an ArgoCD Application
ArgoCD represents an application using an Application resource.
Example:
1apiVersion: argoproj.io/v1alpha1 2kind: Application 3 4metadata: 5 name: deploymart 6 namespace: argocd 7 8spec: 9 project: default 10 11 source: 12 repoURL: https://github.com/example/deploymart-gitops.git 13 targetRevision: main 14 path: environments/development 15 16 destination: 17 server: https://kubernetes.default.svc 18 namespace: deploymart 19 20 syncPolicy: 21 automated: 22 prune: true 23 selfHeal: true 24 25 syncOptions: 26 - CreateNamespace=true
Replace the repository URL with your actual GitOps repository.
The important fields are:
1source 2 ↓ 3Where is the desired configuration? 4 5destination 6 ↓ 7Which Kubernetes cluster and namespace? 8 9syncPolicy 10 ↓ 11How should synchronization happen?
What Does selfHeal Mean?
Suppose someone manually changes the cluster:
1kubectl scale deployment deploymart-backend \ 2 --replicas=1 \ 3 -n deploymart
But Git says:
1replicas: 2
With self-healing enabled, ArgoCD can detect that the cluster no longer matches Git and reconcile it back toward the declared state.
This reinforces the GitOps principle:
Git describes what the system should look like.
What Does prune Mean?
Suppose a Kubernetes resource exists in the cluster but is removed from the Git-managed configuration.
With pruning enabled, ArgoCD can remove resources that are no longer declared by the application.
This is powerful, but it should be enabled carefully.
A GitOps controller has significant authority over your cluster.
ArgoCD Sync States
ArgoCD commonly shows states such as:
1Synced 2OutOfSync
Synced
Git and Kubernetes match.
1Git desired state 2 = 3Cluster state
OutOfSync
They differ.
1Git desired state 2 ≠ 3Cluster state
An OutOfSync state is not automatically a disaster.
It tells you that the declared and actual states differ.
ArgoCD Health
ArgoCD also tracks application health.
You may see states such as:
1Healthy 2Progressing 3Degraded 4Missing 5Unknown
For example:
1Application 2 │ 3 ├── Sync: Synced 4 └── Health: Healthy
is a strong indication that the application matches Git and its Kubernetes resources are healthy.
The Complete GitOps Flow
Now connect everything together.
A developer changes Django:
1def calculate_price(): 2 ...
Then commits:
1git add . 2git commit -m "feat: update pricing" 3git push origin main
GitHub receives the commit.
Step 1: GitHub Actions Starts
1git push 2 ↓ 3GitHub Actions
Step 2: Tests Run
1Install dependencies 2 ↓ 3Run Django tests 4 ↓ 5Tests pass
If tests fail:
1Tests fail 2 ↓ 3Pipeline stops 4 ↓ 5No deployment
This is critical.
A failed test should not automatically become a production deployment.
Step 3: Build Docker Images
The pipeline builds:
1deploymart-backend:COMMIT_SHA 2deploymart-frontend:COMMIT_SHA
Step 4: Push Images
The images are published to the container registry:
1GitHub Container Registry 2 │ 3 ├── backend:8f3a21c 4 └── frontend:8f3a21c
Step 5: Update GitOps Repository
The CI workflow changes:
1newTag: 5c72abc
to:
1newTag: 8f3a21c
Then commits the change.
Step 6: ArgoCD Detects the Change
ArgoCD sees:
1Git changed
and compares the desired state with the cluster.
Step 7: ArgoCD Synchronizes
ArgoCD applies the desired configuration.
1Git 2 ↓ 3ArgoCD 4 ↓ 5Kubernetes 6 ↓ 7New Pods
Step 8: Kubernetes Performs the Rollout
The Deployment replaces old Pods with new Pods according to its rollout strategy.
Finally:
1User 2 ↓ 3Ingress 4 ↓ 5Service 6 ↓ 7New application Pods
The entire process can happen without manually executing kubectl apply.
CI/CD Failure Scenarios
A good pipeline is not just about successful deployments.
You should understand what happens when something fails.
Tests Fail
1Push 2 ↓ 3Tests 4 ↓ 5FAIL 6 ↓ 7Stop
No Docker image should be promoted as a successful release.
Docker Build Fails
1Tests 2 ↓ 3Docker build 4 ↓ 5FAIL 6 ↓ 7No image push 8 ↓ 9No deployment
Registry Push Fails
1Build 2 ↓ 3Registry 4 ↓ 5FAIL 6 ↓ 7GitOps update should not happen
The workflow should update deployment configuration only after the required image push succeeds.
ArgoCD Sync Fails
The image may exist and Git may contain the new desired state, but Kubernetes may reject or fail to run the new configuration.
In this situation:
1Git 2 ↓ 3ArgoCD 4 ↓ 5Sync failure 6 ↓ 7Investigate Kubernetes
Check:
1kubectl get pods -n deploymart
Then:
1kubectl describe pod <pod-name> -n deploymart
and:
1kubectl logs <pod-name> -n deploymart
Debugging the Pipeline
Use a layered approach.
Check GitHub Actions
First verify:
1Workflow status 2 ↓ 3Tests 4 ↓ 5Build 6 ↓ 7Push 8 ↓ 9GitOps update
Check the Container Registry
Verify that the expected image tag exists.
For example:
18f3a21c
Check GitOps
Verify that the commit containing the new image tag reached the repository.
1git log --oneline
Check ArgoCD
Verify:
1Application 2 ├── Sync status 3 └── Health status
Check Kubernetes
Finally:
1kubectl get pods -n deploymart
This gives you a reliable troubleshooting path:
1GitHub Actions 2 ↓ 3Container Registry 4 ↓ 5GitOps Repository 6 ↓ 7ArgoCD 8 ↓ 9Kubernetes 10 ↓ 11Application
Rollback with GitOps
One of the biggest benefits of GitOps is that deployment history lives in Git.
Suppose:
1Current version: 8f3a21c 2Previous version: 5c72abc
If version 8f3a21c is broken, revert the GitOps change.
For example:
1newTag: 5c72abc
After committing the rollback:
1Git 2 ↓ 3ArgoCD detects change 4 ↓ 5Kubernetes 6 ↓ 7Previous image
This is cleaner than manually changing the cluster and leaving Git out of sync.
GitOps Security Principles
A CI/CD pipeline has access to valuable resources, so security matters.
Use Least-Privilege Permissions
Do not give every workflow:
1administrator
permissions.
Only grant what is required.
For example:
1permissions: 2 contents: read 3 packages: write
is preferable to broad unrestricted access when those are the only required capabilities.
Protect the Main Branch
Use repository branch protection or rules to require appropriate review and checks before changes reach your deployment branch.
Protect the GitOps Repository
The GitOps repository controls infrastructure.
Treat it as highly sensitive.
Recommended controls include:
- Pull request reviews.
- Protected branches.
- Restricted write access.
- Audit logs.
- Short-lived credentials where possible.
- Separate development and production environments.
Protect Secrets
Never write:
1DATABASE_PASSWORD: "real-password"
directly into application source code or public Git repositories.
Use an appropriate secret-management strategy.
Development and Production Environments
A mature GitOps setup usually separates environments.
For example:
1GitOps Repository 2 │ 3 ├── development 4 │ └── deploymart 5 │ 6 ├── staging 7 │ └── deploymart 8 │ 9 └── production 10 └── deploymart
The same application image can move through environments:
1Build 2 ↓ 3Development 4 ↓ 5Testing 6 ↓ 7Staging 8 ↓ 9Production
This provides a controlled promotion process.
A Better Production Pipeline
A more mature pipeline might look like:
1Developer 2 │ 3 ▼ 4Pull Request 5 │ 6 ▼ 7Lint + Unit Tests 8 │ 9 ▼ 10Code Review 11 │ 12 ▼ 13Merge 14 │ 15 ▼ 16Build Docker Image 17 │ 18 ▼ 19Security Scan 20 │ 21 ▼ 22Push Image 23 │ 24 ▼ 25Update Development 26 │ 27 ▼ 28ArgoCD 29 │ 30 ▼ 31Kubernetes 32 │ 33 ▼ 34Integration Tests 35 │ 36 ▼ 37Promote to Staging 38 │ 39 ▼ 40Approval 41 │ 42 ▼ 43Production
This is much closer to how mature software delivery platforms are designed.
GitHub Actions vs ArgoCD
These tools have different responsibilities.
| Tool | Primary Responsibility |
|---|---|
| GitHub Actions | CI automation |
| Docker | Build application containers |
| Container Registry | Store container images |
| Kustomize | Customize Kubernetes manifests |
| Git | Store desired configuration |
| ArgoCD | GitOps continuous delivery |
| Kubernetes | Run and reconcile workloads |
Think of the system as a chain:
1GitHub Actions 2 ↓ 3Container Registry 4 ↓ 5GitOps Repository 6 ↓ 7ArgoCD 8 ↓ 9Kubernetes
Do not confuse ArgoCD with a Docker registry or GitHub Actions with Kubernetes.
Each tool solves a different problem.
The Sushi Conveyor Belt Analogy
Return to the original analogy.
Imagine a sushi restaurant.
The developer provides the recipe change:
1Git commit
GitHub Actions prepares the ingredients:
1Tests 2 ↓ 3Build 4 ↓ 5Package 6 ↓ 7Container image
The container registry stores the prepared ingredients:
1Docker image
The GitOps repository contains the menu:
1Desired deployment state
ArgoCD is the chef watching the menu:
1Git 2 ↓ 3ArgoCD 4 ↓ 5Kubernetes
Kubernetes serves the final meal:
1Running application
The key idea is:
Git says what should be running, and ArgoCD continuously works to make Kubernetes match that declaration.
Useful Commands
Check GitHub-related local repository state:
1git status
Inspect recent commits:
1git log --oneline -10
Build a Kustomize configuration locally:
1kubectl kustomize environments/development
Validate what would be generated before applying it:
1kubectl kustomize environments/development
Check ArgoCD resources:
1kubectl get applications -n argocd
Inspect a specific ArgoCD Application:
1kubectl describe application deploymart -n argocd
Check Kubernetes resources:
1kubectl get all -n deploymart
Watch Pods:
1kubectl get pods -n deploymart -w
Watch a rollout:
1kubectl rollout status deployment/deploymart-backend \ 2 -n deploymart
Module 11 Hands-On Project
Build the complete DeployMart GitOps pipeline.
Your application repository should contain:
1deploymart/ 2├── backend/ 3├── frontend/ 4├── tests/ 5├── .github/ 6│ └── workflows/ 7│ └── ci-cd.yaml 8├── backend.Dockerfile 9└── frontend.Dockerfile
Your GitOps repository should contain:
1deploymart-gitops/ 2└── environments/ 3 └── development/ 4 ├── namespace.yaml 5 ├── backend.yaml 6 ├── frontend.yaml 7 ├── services.yaml 8 ├── ingress.yaml 9 └── kustomization.yaml
Then implement this workflow:
1Code push 2 ↓ 3GitHub Actions 4 ↓ 5Run tests 6 ↓ 7Build backend image 8 ↓ 9Build frontend image 10 ↓ 11Push images 12 ↓ 13Update Kustomize tags 14 ↓ 15Commit GitOps change 16 ↓ 17ArgoCD detects change 18 ↓ 19Synchronize 20 ↓ 21Kubernetes rollout 22 ↓ 23DeployMart updated
Module 11 Checkpoint
You should now be able to explain:
- What CI means.
- What CD means.
- What GitOps means.
- Why Git can act as the desired-state source of truth.
- Why GitHub Actions and ArgoCD have different responsibilities.
- How Docker images move from source code to a registry.
- Why commit SHA image tags are useful.
- How Kustomize manages image versions.
- How ArgoCD detects Git changes.
- What
SyncedandOutOfSyncmean. - What
selfHealdoes. - What
prunedoes. - How GitOps rollback works.
- How to debug failures across the CI/CD pipeline.
Final Architecture
At the end of this module, your DeployMart platform should conceptually look like this:
1 Developer 2 │ 3 git push 4 │ 5 ▼ 6 ┌─────────────────┐ 7 │ GitHub │ 8 └────────┬────────┘ 9 │ 10 ▼ 11 ┌─────────────────┐ 12 │ GitHub Actions │ 13 │ │ 14 │ Tests │ 15 │ Build │ 16 │ Security checks │ 17 │ Push image │ 18 └────────┬────────┘ 19 │ 20 ▼ 21 ┌─────────────────┐ 22 │ Container │ 23 │ Registry │ 24 └────────┬────────┘ 25 │ 26 │ image 27 ▼ 28 ┌─────────────────┐ 29 │ GitOps Repository│ 30 │ │ 31 │ Kustomize │ 32 │ image tag │ 33 └────────┬────────┘ 34 │ 35 │ desired state 36 ▼ 37 ┌───────────┐ 38 │ ArgoCD │ 39 └─────┬─────┘ 40 │ 41 sync 42 │ 43 ▼ 44 ┌───────────────────┐ 45 │ Kubernetes │ 46 │ │ 47 │ Django Pods │ 48 │ Next.js Pods │ 49 │ Services │ 50 │ Ingress │ 51 └─────────┬─────────┘ 52 │ 53 ▼ 54 DeployMart
The critical transition from Module 10 is:
1Module 10: 2 3Developer 4 ↓ 5kubectl apply 6 ↓ 7Kubernetes
to:
1Module 11: 2 3Developer 4 ↓ 5Git push 6 ↓ 7GitHub Actions 8 ↓ 9Docker Registry 10 ↓ 11GitOps Repository 12 ↓ 13ArgoCD 14 ↓ 15Kubernetes
That transition is the foundation of GitOps-based Kubernetes delivery.
Once you understand this flow, you have the foundation needed to move into advanced topics such as Helm, Kustomize overlays, Kubernetes security, observability, secrets management, autoscaling, and production-grade GitOps workflows.