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 applyof versioned manifests — keep your Deployment/Service/Ingress YAML in the repo, template the image tag into it, andkubectl 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=$SHAdeploys 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
productionoverlay changing replica count and resources), without templating. Built intokubectl.
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
- Explain how a pipeline deploys a new version to EKS using desired state and a rolling update.
- Write the pipeline steps to point kubectl at the cluster, set the new image, and fail on a bad rollout.
- Compare kubectl-apply, Helm and Kustomize for managing deployed manifests, and what they have in common.
- Explain the GitOps model and how it differs from a pipeline pushing to the cluster, with two benefits.
- Explain how readiness probes and
rollout statusmake a deploy safe and verifiable. - Describe the full safe deploy path from staging to production for an EKS workload.
Official documentation
- AWS — Deploying to EKS — Running and updating workloads on EKS.
- Helm — Documentation — Charts, templating and releases.
- Argo CD — Getting started (GitOps) — Pull-based deployment from Git.
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