Skip to main content
Kubernetes Introduction
CHAPTER 16 Intermediate

CI/CD with Kubernetes

Updated: May 15, 2026
30 min read

# CHAPTER 16

CI/CD with Kubernetes

1. Introduction

In Chapter 15, we discussed the complexity of manually managing Load Balancers and routing traffic to perform advanced deployments like Blue-Green or Canary. While this is tedious on traditional servers, Kubernetes (K8s)—the undisputed king of container orchestration—was built specifically to handle these advanced deployment strategies natively. In this chapter, we will bridge the gap between our CI pipeline and a Kubernetes cluster. We will explore how to configure GitHub Actions to authenticate with K8s, update deployment manifests dynamically, and trigger "Rolling Updates" across massive fleets of containers seamlessly.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the integration points between a CI pipeline and a K8s cluster.
  • Define a Kubernetes Deployment manifest.
  • Authenticate a CI runner with a Kubernetes API using kubeconfig.
  • Utilize CI tools to inject dynamic Image Tags into K8s manifests.
  • Understand Kubernetes Native Rolling Updates.

3. Beginner-Friendly Explanation

Imagine a fleet of 50 delivery trucks (Containers) managed by an automated Dispatcher (Kubernetes).
  • The Old Way: You (the CI Pipeline) have to call all 50 drivers individually, tell them to pull over, change their cargo, and restart their trucks.
  • The Kubernetes Way: You don't talk to the trucks. You talk exclusively to the Dispatcher. The CI Pipeline hands the Dispatcher a single piece of paper (a YAML manifest) that says: "I want all trucks to carry cargo Version 2.0." The Dispatcher looks at the paper, automatically pulls over one truck at a time, changes the cargo, verifies it runs, and then moves to the next truck until all 50 are updated.

Kubernetes abstracts away the complexity of the servers; your CI pipeline only has to update a single text file to trigger massive, highly-available deployments.

4. The K8s Deployment Manifest

Before we can deploy, we must define what we want Kubernetes to run. This is done via a YAML file (e.g., deployment.yml) stored in our Git repository alongside our application code.
yaml
1234567891011121314151617181920
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web-app
spec:
  replicas: 3 # Run 3 identical containers for high availability
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: main-container
        # THE CRITICAL LINE: Which version of our code?
        image: mycompany/myapp:latest 
        ports:
        - containerPort: 80

5. The CI/CD Kubernetes Workflow

The ultimate goal of a K8s CI/CD pipeline is to update the image: line in the manifest above, and tell the cluster to apply the changes.
  1. 1. Build & Push: The CI pipeline compiles the code and builds a Docker Image tagged with the unique Git commit hash (e.g., mycompany/myapp:a1b2c3d). It pushes this to Docker Hub.
  1. 2. Update Manifest: The CI pipeline uses a tool (like sed or kustomize) to rewrite the deployment.yml file, changing image: mycompany/myapp:latest to image: mycompany/myapp:a1b2c3d.
  1. 3. Authenticate: The CI pipeline securely loads the K8s cluster credentials.
  1. 4. Deploy: The CI pipeline runs kubectl apply -f deployment.yml. Kubernetes takes over and gracefully updates the running containers.

6. Mini Project: Deploy App to K8s Cluster

Let's build a GitHub Actions workflow that executes the K8s deployment phase.

Step-by-Step Architecture Concept:

yaml
12345678910111213141516171819202122232425262728293031323334
name: Deploy to Kubernetes

on:
  push:
    branches: [ "main" ]

jobs:
  deploy-to-k8s:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. (Assume Docker Build and Push steps happened here)

      # 2. Authenticate with Kubernetes
      - name: Set up Kubeconfig
        uses: azure/k8s-set-context@v3
        with:
          method: kubeconfig
          kubeconfig: ${{ secrets.KUBECONFIG_DATA }} # The secure cluster password

      # 3. Dynamically update the image tag in the YAML file
      - name: Update Deployment YAML
        # This replaces the word 'latest' with our actual Git commit hash!
        run: |
          sed -i 's/latest/${{ github.sha }}/g' k8s/deployment.yml

      # 4. Trigger the Deployment!
      - name: Apply to Kubernetes Cluster
        run: kubectl apply -f k8s/deployment.yml
        
      # 5. Wait to ensure it actually worked
      - name: Verify Deployment
        run: kubectl rollout status deployment/my-web-app

7. Real-World Scenarios

A gaming company relied on manual scripts to deploy server updates. During a major launch, an engineer ran the script, and all 100 game servers restarted simultaneously, disconnecting thousands of players. They migrated to Kubernetes and integrated it with GitLab CI. Because Kubernetes performs Rolling Updates by default, when the CI pipeline ran kubectl apply, K8s intelligently updated only 10 servers at a time, waiting for them to report "Healthy" before moving to the next 10. The entire 100-server fleet was updated with zero downtime, and the CI pipeline managed the entire process just by updating a single YAML string.

8. Best Practices

  • GitOps (ArgoCD): The pipeline above uses "Push-based" deployment (the CI runner pushes commands into the cluster). For massive enterprises, the gold standard is "Pull-based" deployment (GitOps). You install a tool like ArgoCD *inside* your cluster. Your CI pipeline ONLY updates the YAML file in GitHub. ArgoCD constantly watches GitHub; when it sees a change, the cluster pulls the new configuration itself. This means your CI pipeline never needs K8s admin credentials, massively increasing security.

9. Security Recommendations

  • Kubeconfig Vaulting: The kubeconfig file grants absolute administrator access to your entire Kubernetes cluster. It is the most dangerous secret your company owns. Never commit it to Git. If you use push-based deployments, it must be stored in a highly secure CI vault (like GitHub Secrets), and the CI runner must only have access to the specific Kubernetes Namespace it needs to deploy into, enforcing least privilege.

10. Troubleshooting Tips

  • ImagePullBackOff: The most common CI/K8s error. The CI pipeline will report kubectl rollout status failed. If you investigate the cluster, you will see ImagePullBackOff. This means the pipeline successfully pushed the YAML to K8s, but K8s couldn't download the Docker image. This usually means your CI pipeline forgot to authenticate K8s to your private Docker Registry (via an imagePullSecret), or the image name/tag in the YAML was misspelled.

11. Exercises

  1. 1. Explain the architectural difference between pushing code directly to traditional servers versus applying a YAML manifest to a Kubernetes API.
  1. 2. What is the operational purpose of dynamically substituting the latest image tag with the Git commit hash (github.sha) during the CI pipeline?

12. FAQs

Q: Do I need to install kubectl on the GitHub runner? A: No, GitHub Actions provides Ubuntu runners that already have kubectl, Docker, and the AWS CLI pre-installed, allowing you to run these commands instantly.

13. Interview Questions

  • Q: Describe the integration architecture between a CI/CD pipeline and a Kubernetes cluster. How does the pipeline dictate which specific container image the cluster should pull and execute?
  • Q: Contrast "Push-based" Kubernetes deployments (using kubectl apply in a CI runner) with "Pull-based" GitOps deployments (using ArgoCD). What is the primary security advantage of the GitOps model?

14. Summary

In Chapter 16, we unlocked the highest tier of continuous delivery by integrating our automation pipelines with Kubernetes. We shifted from the tedious manual orchestration of servers to the elegant declaration of desired state. We learned how to secure cluster authentication within ephemeral CI runners, and mastered the technique of dynamically injecting unique build hashes into Kubernetes manifests via shell scripting. By combining the compilation power of CI with the native, zero-downtime Rolling Updates of Kubernetes, we established a deployment architecture capable of scaling to enterprise demands.

15. Next Chapter Recommendation

Our pipeline works perfectly for 10 developers. But what happens when 500 developers push code at the same time, and the CI queue backs up for hours? Proceed to Chapter 17: Scaling CI Pipelines.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·