RizTech Academy logo
RizTech Academy
Deployment PipelinesLesson 3 of 540 min

Deploying to EKS from CI

The image is built and in ECR; now the pipeline must get it running on EKS. This lesson is the deploy stage: how a pipeline updates a Kubernetes workload to a new image, the tools for doing it (kubectl, Helm, GitOps), and how to make the deploy safe and verifiable. It combines the EKS module (how workloads run) with the pipeline (automating the change).

The core action: update the image, let Kubernetes roll it out

Because Kubernetes is declarative (the Foundation), deploying a new version means one thing: change the desired state to the new image, and Kubernetes performs a rolling update (the scaling-and-health lesson) — new pods up, old pods down, gated by readiness, zero downtime. The simplest pipeline deploy is exactly that:

      - run: aws eks update-kubeconfig --name production --region eu-west-1   # point kubectl at the cluster
      - run: |
          kubectl set image deployment/greetings greetings=$ECR/greetings:${{ github.sha }}
          kubectl rollout status deployment/greetings --timeout=300s        # wait, and FAIL if the rollout fails

kubectl set image updates the deployment to the new commit-tagged image; kubectl rollout status waits for the rollout to complete and fails the pipeline if the deploy fails — so a bad deploy is caught in the pipeline, not by users. The pipeline's assumed role (via OIDC) authenticates to both the cluster (IAM governs EKS access — the eks-basics lesson) and ECR. This is the minimal, real deploy: update the image, wait for a healthy rollout, fail loudly if it does not.

Beyond kubectl set image: manifests, Helm, Kustomize

kubectl set image is fine for a simple case, but real deployments manage the whole set of manifests, and you want the deployed config to be in version control (like everything else). Common approaches:

  • kubectl apply of versioned manifests — keep your Deployment/Service/Ingress YAML in the repo, template the image tag into it, and kubectl apply -f. The manifests are the source of truth, in Git.
  • Helm — the Kubernetes package manager. A Helm chart templates your manifests with values (image tag, replica count, environment differences), so helm upgrade --install greetings ./chart --set image.tag=$SHA deploys a parameterised, versioned release. Helm is widely used for its templating and release management (rollback tracking, the next lesson).
  • Kustomize — an alternative that layers environment-specific overlays on a base set of manifests (a base, plus a production overlay changing replica count and resources), without templating. Built into kubectl.

All three keep your Kubernetes configuration in version control and parameterise the per-environment and per-deploy differences — which is the same "config in Git, environments differ only in inputs" discipline as the Terraform environments lesson. Which you use is a team choice; the principle is that the deployed state is declared in versioned files, not typed ad-hoc.

GitOps: the cluster pulls its desired state

A more advanced and increasingly popular pattern worth knowing is GitOps (with tools like Argo CD or Flux). Instead of the pipeline pushing changes to the cluster (kubectl apply from CI), you:

  • Keep the desired state (the manifests) in a Git repository.
  • Run an agent in the cluster that continuously pulls from Git and reconciles the cluster to match it.
  • To deploy, the pipeline updates the image tag in the Git repo (a commit); the in-cluster agent notices and applies it.

The benefits: Git is the single source of truth for what is deployed (you can see, review and revert the cluster's state as commits — rollback is a git revert); the cluster self-heals toward the declared state (drift is corrected automatically); and the pipeline needs no direct cluster credentials (the agent pulls, rather than CI pushing). For a foundation, the idea to hold is that GitOps flips the model — the cluster pulls its desired state from Git, rather than a pipeline pushing to it — which many teams find safer and more auditable at scale. You do not need it to start (push-based kubectl/Helm from CI is perfectly good), but it is where mature EKS delivery often goes.

Making the deploy safe

Whatever tool you use, the deploy stage should be safe and verifiable (the Foundation's deploy discipline):

  • Deploy to staging first, verify, then production (the pipeline-design lesson) — with production gated by approval.
  • Wait for the rollout and fail on failure (kubectl rollout status, or Helm's --wait) — so the pipeline knows if the deploy did not become healthy, and does not report success on a broken deploy.
  • Rely on readiness probes (the EKS/Foundation lesson) — the rolling update only shifts traffic to pods that pass readiness, so a broken new version does not receive traffic and the old version keeps serving.
  • Verify after deploy — a smoke test or health check against the deployed service confirms it actually works, not just that the rollout completed.
  • Be ready to roll back immediately if verification fails (the next lesson).

Put together: the deploy stage updates the workload to the new commit-tagged image (via kubectl/Helm/Kustomize, or GitOps), waits for a healthy rollout gated by readiness, verifies it, and stands ready to roll back — to staging automatically and to production behind an approval. That is how a pipeline safely gets a new version running on EKS.

Check your work

Core deploy: change desired state to the new image → Kubernetes does a rolling update (readiness-gated, zero downtime). Minimal: kubectl set image ... + kubectl rollout status (fails the pipeline if the rollout fails). The pipeline's OIDC role authenticates to EKS (IAM-governed) and ECR.

Better tooling: versioned manifests via kubectl apply; Helm (charts templated by values — image tag, replicas; helm upgrade --install); Kustomize (base + per-env overlays). All keep deployed config in Git, parameterising per-env/per-deploy differences.

GitOps (Argo CD/Flux): the cluster runs an agent that pulls desired state from Git and reconciles — deploy = commit the new tag; Git is the source of truth (rollback = git revert), drift self-corrects, CI needs no cluster credentials. The cluster pulls rather than CI pushing. Not required to start; where mature delivery goes.

Safe deploy: staging → verify → production (gated); wait for the rollout and fail on failure; rely on readiness probes (broken version gets no traffic); verify with a smoke test; be ready to roll back.

Practice

  1. Explain how a pipeline deploys a new version to EKS using desired state and a rolling update.
  2. Write the pipeline steps to point kubectl at the cluster, set the new image, and fail on a bad rollout.
  3. Compare kubectl-apply, Helm and Kustomize for managing deployed manifests, and what they have in common.
  4. Explain the GitOps model and how it differs from a pipeline pushing to the cluster, with two benefits.
  5. Explain how readiness probes and rollout status make a deploy safe and verifiable.
  6. Describe the full safe deploy path from staging to production for an EKS workload.

Official documentation

Next: rollback strategies that actually work.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship