Epitomsoft Academy · Cloud & DevOps course
Kubernetes in Production on AWS
An end-to-end course: from a developer’s git push, through a CI/CD pipeline, to a secure, autoscaling, fully monitored Kubernetes cluster on Amazon EKS – with real examples and working code.
What you will learn
From code to a production cluster
Kubernetes is the industry standard for running containerised applications. Using one realistic example – the “campus jobs” web app – you will follow the complete journey: building and shipping releases, serving user requests, and operating the platform reliably.
- Explain the Kubernetes architecture: control plane, nodes, pods and controllers
- Build a CI/CD pipeline with GitHub Actions, Docker and Amazon ECR
- Trace a user request from DNS to a pod and the database
- Write Deployments, Services, Ingress, ConfigMaps, Secrets and autoscalers
- Secure workloads with IAM roles for service accounts and RBAC
- Monitor, log, alert and roll back with confidence
Course at a glance
- Sessions: 3 animated video lessons + reading + lab
- Level: Intermediate
- Prerequisites: Linux command line, Git and basic Docker
- You will build: A containerised API deployed with CI/CD to a local Kubernetes cluster, with autoscaling and monitoring
Session 1 of 3
The CI/CD pipeline: from git push to EKS
Follow release 1.4 of the campus jobs API through build, tests, security scans, Docker, Amazon ECR and a zero-downtime rolling update.
Read the full transcript
- Welcome: Hi, I am Epi! This is session one of Kubernetes in production. You will see how a code change travels from a developer’s laptop to a live Kubernetes cluster on AWS. Our example: releasing version 1.4 of the campus jobs API, which adds a remote-only filter.
- Step 1 · Commit: It starts with a developer. They write the new feature, commit it and run git push. The code lands in a GitHub repository, usually through a pull request that a teammate reviews and approves.
- Step 2 · Trigger CI: The merge triggers GitHub Actions, the CI/CD pipeline. A workflow file stored in the repository tells it exactly what to do, step by step, on a fresh build machine.
- Step 3 · Quality gates: First come the quality gates. The pipeline builds the code, runs the automated tests, and scans it: SonarQube checks code quality, and Trivy looks for known vulnerabilities. If any gate fails, the pipeline stops, and nothing is deployed.
- Step 4 · Build image: Next, the pipeline builds a Docker image: the application plus everything it needs to run, packaged together. The image is tagged with the version and the git commit, so every release can be traced back to its code.
- Step 5 · Push to ECR: The image is pushed to Amazon ECR, a private container registry. ECR keeps every version, so you can always roll back, and it can scan images again for vulnerabilities.
- Step 6 · Continuous delivery: Now continuous delivery takes over. A tool such as Argo CD or Helm updates the Kubernetes manifests to the new image tag. With GitOps, the desired state of the cluster is stored in Git, and the cluster is synced to match it.
- Step 7 · Rolling update: Amazon EKS performs a rolling update. New pods start with version 1.4, and they must pass their health checks before old pods are removed. Users never see any downtime.
- Step 8 · Feedback: Monitoring closes the loop. If error rates rise after a release, alerts fire, and the team can roll back to the previous version in seconds. The developer gets fast feedback, and the cycle starts again.
- Recap: That is the CI/CD pipeline: commit, build, test, scan, package, push, deploy and monitor, all automated. In the next session, we follow what happens when a user actually opens the app.
Session 2 of 3
How a user request flows through Kubernetes
Follow one request through Route 53, the load balancer, Ingress, Service and Pods – with configuration, secrets and the database.
Read the full transcript
- Welcome: Welcome to session two! Now we follow one user request through a production Kubernetes cluster on AWS. Our example: a student opens jobs dot example dot com, and searches for remote jobs.
- Step 1 · DNS: The user types the address in a browser or app. Amazon Route 53, the AWS DNS service, translates the name into the address of the load balancer.
- Step 2 · Load balancer: The request reaches the Application Load Balancer. It handles HTTPS using a TLS certificate, spreads traffic across availability zones, and only sends traffic to healthy targets.
- Step 3 · Ingress: The load balancer hands the request to the Kubernetes Ingress. Ingress rules decide where each request goes, based on the host name and the URL path. On EKS, the AWS Load Balancer Controller manages this for you.
- Step 4 · Service: The Ingress sends the request to a Service. Pods come and go, but a Service gives them one stable name and address, and spreads requests across them.
- Step 5 · Pod: The Service forwards the request to one healthy pod. Pods run your containers, and Kubernetes only sends traffic to pods that pass their readiness check.
- Step 6 · Configuration: The application reads its settings from a ConfigMap, and its sensitive values, like the database password, from a Secret. Nothing sensitive is baked into the image.
- Step 7 · Database: To answer the search, the app queries the database: Amazon RDS for PostgreSQL, running across two availability zones for high availability.
- Step 8 · Response: Finally, the response travels back through the Service, the Ingress and the load balancer to the user, usually in a fraction of a second.
- Recap: That is the request path: DNS, load balancer, Ingress, Service, Pod, configuration and database, and back to the user. In the next session, we see how to keep all of this running smoothly in production.
Session 3 of 3
Running Kubernetes in production
A job fair sends traffic up ten times: see autoscaling, storage, security, health checks, metrics, logs and alarms in action.
Read the full transcript
- Welcome: Welcome to session three: running Kubernetes in production. Our example: at nine a.m. a virtual job fair starts, and traffic jumps ten times. Let us see how the platform handles it, safely and automatically.
- Step 1 · Autoscaling: The Horizontal Pod Autoscaler watches CPU, memory or custom metrics. When average CPU rises above its target, it adds pods, and when traffic drops, it removes them. If the servers fill up, a node autoscaler such as Karpenter adds more nodes.
- Step 2 · Storage: Some data must survive pod restarts. Kubernetes uses persistent volumes and persistent volume claims, backed on AWS by EBS disks or EFS file systems, while large files often go to S3.
- Step 3 · Security: IAM roles for service accounts, called IRSA, give each pod only the AWS permissions it needs, with no hard-coded keys. Kubernetes RBAC controls what people and tools can do inside the cluster.
- Step 4 · Health probes: Health probes keep the app reliable. A readiness probe decides whether a pod should receive traffic, and a liveness probe restarts a pod that has stopped responding.
- Step 5 · Metrics: Prometheus collects metrics from the cluster and the application, and Grafana turns them into dashboards that the team watches during the job fair.
- Step 6 · Logs: Fluent Bit runs on every node and collects the logs from all containers, so nothing is lost when a pod is replaced.
- Step 7 · Alarms: Amazon CloudWatch stores the logs and metrics, and alarms watch for trouble, such as a rising error rate, and notify the on-call engineer.
- Step 8 · Act: Alarms and dashboards drive action: scale further, roll back a bad release, or fix the root cause. After the job fair, the autoscaler scales back down to save cost.
- Recap: That is production Kubernetes: autoscaling, storage, least-privilege security, health checks, metrics, logs and alarms, all working together. Congratulations, you have completed the Kubernetes course!
Deep dive
Key concepts, explained with examples
The control plane
The “brain” of the cluster: the API server receives every request, etcd stores the cluster state, the scheduler places pods on nodes and controllers keep reality matching the desired state. On Amazon EKS, AWS runs the control plane for you.
Example: You ask for 3 replicas; a pod crashes; the Deployment controller notices only 2 are running and starts a new one within seconds.
Nodes and the kubelet
Worker nodes are the servers that run your containers. On each node the kubelet starts and watches pods, and kube-proxy handles networking for Services.
Example: An EKS managed node group of three EC2 instances across two availability zones runs all campus-jobs pods.
Pods and Deployments
A pod is the smallest unit: one or more containers that share network and storage. A Deployment manages identical pods and performs rolling updates and rollbacks.
Example: “replicas: 3” keeps three copies of the API running; changing the image tag rolls them to v1.4 one at a time.
Services
Pods are temporary and their IPs change. A Service gives a stable name and virtual IP and load-balances across matching pods. Types: ClusterIP (internal), NodePort and LoadBalancer.
Example: Other apps call http://campus-jobs-api.production – they never need to know individual pod IPs.
Ingress
An Ingress defines HTTP routing rules – host names, paths and TLS – into Services. On EKS the AWS Load Balancer Controller turns an Ingress into an Application Load Balancer.
Example: jobs.example.com/api goes to the API service; jobs.example.com/ goes to the web front-end service.
ConfigMaps and Secrets
ConfigMaps hold non-sensitive settings; Secrets hold passwords, API keys and certificates. Both are injected into pods as environment variables or files, so the same image runs in every environment.
Example: PAGE_SIZE=20 lives in a ConfigMap; DB_PASSWORD lives in a Secret (ideally synced from AWS Secrets Manager).
Namespaces and RBAC
Namespaces separate environments and teams inside one cluster. Role-Based Access Control (RBAC) decides who may do what in each namespace.
Example: Developers can deploy to “staging” but have read-only access to “production”; the CI pipeline has a dedicated deploy role.
IRSA and Pod Identity
IAM roles for service accounts (IRSA) – and the newer EKS Pod Identity – give a pod temporary AWS credentials for exactly one role. No access keys are ever stored in code or images.
Example: The API pod may read the résumés S3 bucket – and nothing else in the AWS account.
Autoscaling
The Horizontal Pod Autoscaler changes the number of pods based on metrics; node autoscalers such as Karpenter or Cluster Autoscaler add or remove servers when pods need more room.
Example: CPU above 60% → HPA scales 3 → 9 pods → Karpenter adds two nodes to fit them.
Probes and observability
Readiness and liveness probes tell Kubernetes when a pod can take traffic or must restart. Prometheus, Grafana, Fluent Bit and CloudWatch give metrics, dashboards, logs and alerts.
Example: A pod that stops responding fails its liveness probe and is restarted automatically – before users notice.
Cheat sheet
Kubernetes objects at a glance
What each object is for, in one line.
Workloads
Deployment · ReplicaSet · Pod
Run and update stateless apps; StatefulSet for databases and queues; Job/CronJob for batch tasks.
Networking
Service · Ingress · NetworkPolicy
Stable addresses, HTTP routing from outside, and firewall rules between pods.
Configuration
ConfigMap · Secret
Settings and sensitive values, kept outside the container image.
Storage
PersistentVolume · PVC · StorageClass
Durable disks and file systems (EBS, EFS) that survive pod restarts.
Scaling
HPA · Karpenter / Cluster Autoscaler
More pods when busy, more nodes when the cluster is full – and back down to save cost.
Security
Namespace · RBAC · ServiceAccount
Isolation, permissions for people and tools, and identities for pods (IRSA / Pod Identity).
Worked examples
Real manifests and a real pipeline
The files behind the animated sessions. Placeholders such as
Example 1 – CI pipeline: test, scan and push to Amazon ECR (GitHub Actions)
# .github/workflows/build-and-deploy.yml
name: build-and-deploy
on:
push:
branches: [main]
permissions:
id-token: write # OIDC login to AWS - no stored access keys
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- run: mvn -B verify # compile + unit tests
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<account-id>:role/github-deploy
aws-region: us-east-1
- uses: aws-actions/amazon-ecr-login@v2
id: ecr
- name: Build, scan and push the image
env:
IMAGE: ${{ steps.ecr.outputs.registry }}/campus-jobs-api:${{ github.sha }}
run: |
docker build -t "$IMAGE" .
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --exit-code 1 --severity CRITICAL "$IMAGE"
docker push "$IMAGE"
Example 2 – Deployment and Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: campus-jobs-api
namespace: production
spec:
replicas: 3
selector:
matchLabels: { app: campus-jobs-api }
strategy:
rollingUpdate: { maxUnavailable: 0, maxSurge: 1 } # zero-downtime releases
template:
metadata:
labels: { app: campus-jobs-api }
spec:
serviceAccountName: campus-jobs-api # IRSA: AWS permissions for this pod
containers:
- name: api
image: <account-id>.dkr.ecr.us-east-1.amazonaws.com/campus-jobs-api:1.4.0
ports: [{ containerPort: 8080 }]
envFrom:
- configMapRef: { name: campus-jobs-config }
- secretRef: { name: campus-jobs-secrets }
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { memory: 512Mi }
readinessProbe:
httpGet: { path: /health/ready, port: 8080 }
periodSeconds: 5
livenessProbe:
httpGet: { path: /health/live, port: 8080 }
initialDelaySeconds: 20
---
apiVersion: v1
kind: Service
metadata:
name: campus-jobs-api
namespace: production
spec:
selector: { app: campus-jobs-api }
ports: [{ port: 80, targetPort: 8080 }]
Example 3 – Ingress (AWS Load Balancer Controller) and Horizontal Pod Autoscaler
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: campus-jobs
namespace: production
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:<account-id>:certificate/<certificate-id>
spec:
ingressClassName: alb
rules:
- host: jobs.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: campus-jobs-api
port: { number: 80 }
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: campus-jobs-api
namespace: production
spec:
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: campus-jobs-api }
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 60 }
Example 4 – Everyday kubectl commands for operating the app
kubectl get pods -n production -l app=campus-jobs-api # are all pods running?
kubectl rollout status deployment/campus-jobs-api -n production
kubectl describe hpa campus-jobs-api -n production # why did it scale?
kubectl logs deploy/campus-jobs-api -n production --tail=50 # recent logs
kubectl rollout undo deployment/campus-jobs-api -n production # instant rollback
Hands-on lab
Deploy campus-jobs to your own cluster
You run the full flow on a free local cluster with kind (Kubernetes in Docker) – no cloud bill required – then map each step to its EKS equivalent.
- Create a local cluster: kind create cluster –name campus
- Containerise a small API and load the image into kind
- Apply the Deployment, Service, ConfigMap and Secret manifests
- Install an ingress controller and route a host name to your Service
- Install metrics-server, add the HPA and generate load to watch it scale
- Break a liveness probe on purpose and watch Kubernetes heal the app
- Write a GitHub Actions workflow that builds, tests and scans your image
Key terms
Vocabulary to master
- Cluster
- Control plane
- etcd
- Node
- kubelet
- Pod
- Deployment
- ReplicaSet
- Service
- Ingress
- ConfigMap
- Secret
- Namespace
- RBAC
- IRSA
- HPA
- PV / PVC
- Probe
- Helm
- GitOps
- Rolling update
- ECR
- EKS
Check your understanding
Course quiz
Score 70% or more on every quiz to complete the course and unlock your certificate on My progress.
Further learning
Free official documentation & open-source references
Primary sources and free hands-on resources to go deeper.
- Kubernetes documentation – Overview – official concepts from the Kubernetes project
- Kubernetes Basics tutorial – free interactive introduction
- Amazon EKS User Guide – official AWS documentation for EKS
- Amazon EKS Best Practices Guide – security, reliability, scaling and cost guidance
- AWS Load Balancer Controller – open-source controller behind the Ingress example
- kind – Kubernetes in Docker – free local clusters for the lab
- Kubernetes The Hard Way (GitHub) – build a cluster from scratch to understand every part
- Killercoda Kubernetes playgrounds – free browser-based clusters
- GitHub Actions documentation – official CI/CD documentation
- Helm documentation – the package manager for Kubernetes
- Argo CD documentation – open-source GitOps continuous delivery
- Karpenter – open-source node autoscaler for Kubernetes
- Prometheus – Overview – open-source metrics and alerting
- Fluent Bit documentation – open-source log processor and forwarder
- Trivy (GitHub) – open-source vulnerability scanner used in the pipeline
Want to learn this with a mentor?
Join the Epitomsoft Academy Cloud & DevOps track: live sessions, real projects and career support.
