Back to path
IntermediateTaskFlow · Project 7 of 13 ~12h· 6 milestones

Deploy to Kubernetes (EKS) with raw manifests

Continues from the last build: TaskFlow runs resiliently on EC2/ASG behind an ALB.

In the last rung you made TaskFlow survive a node failure: an Auto Scaling Group kept N EC2 instances alive behind an ALB, and a dead instance got replaced automatically.

Provisioning an EKS cluster with eksctl and a managed node groupWriting raw Kubernetes Deployment and Service manifestsConfiguring ConfigMaps and Secrets and knowing build-time vs runtime configDefining liveness and readiness probes plus resource requests and limitsExposing apps over HTTPS with an Ingress and ACM via the AWS Load Balancer ControllerOperating pods: self-healing, scaling, and rolling updates with kubectl

What you'll build

TaskFlow runs on an EKS cluster as Deployments and Services, fronted by an HTTPS ALB provisioned through an Ingress with an ACM certificate, with the backend reading DATABASE_URL from a Secret, health-gated rolling updates, and self-healing pods. RDS remains the database.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

taskflow/k8s/cluster.yamlyaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: taskflow
  region: eu-west-1
  version: "1.30"

iam:
  withOIDC: true

managedNodeGroups:
  - name: ng-default
    instanceType: t3.medium
    desiredCapacity: 2
    minSize: 2
    maxSize: 4
    volumeSize: 20
    labels: { role: worker }

Reading this file

  • kind: ClusterConfigTells eksctl this file describes a whole cluster, not a single Kubernetes object.
  • withOIDC: trueTurns on the OIDC identity provider so pods can assume IAM roles, which the load balancer controller needs.
  • desiredCapacity: 2eksctl starts the node group with two EC2 worker machines to run your pods.
  • instanceType: t3.mediumEach worker node is a t3.medium, big enough for the TaskFlow pods plus system add-ons.

eksctl ClusterConfig: one managed node group, OIDC enabled so the LB Controller and IRSA work.

That's 1 of 7 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Provision an EKS cluster and confirm kubectl access

    4 guided steps

    On EC2/ASG you owned the OS. On EKS the control plane is managed by AWS and you only own the worker nodes and your workloads. Getting a clean, OIDC-enabled cluster with Ready nodes is the foundation every later milestone stands on, and doing it from a declarative ClusterConfig (not a pile of CLI flags) keeps the cluster reproducible.

  2. 2

    Record VITE_API_URL in a ConfigMap and create the DATABASE_URL Secret

    4 guided steps

    Config and secrets must live outside the image so the same backend image runs against dev and prod RDS by swapping a Secret. Splitting non-sensitive config (ConfigMap) from sensitive config (Secret) lets you treat them differently. Just as important on this rung is understanding what a ConfigMap can and cannot do: it can inject runtime env vars into a pod, but it cannot retroactively change a value that was already compiled into a static bundle, which is why the frontend's API URL is a build-time concern, not a runtime ConfigMap one.

  3. 3

    Deploy the backend: Deployment, probes, limits, and Service

    4 guided steps

    This is the heart of the rung. A Deployment encodes desired state (3 healthy replicas of this Pod template) and the control plane continuously reconciles toward it: that is what gives you self-healing and rolling updates for free. Requests and limits let the scheduler place pods sensibly and protect a node from one runaway pod. The Service gives the backend a stable virtual IP so the frontend and Ingress never chase individual pod IPs.

  4. 4

    Deploy the frontend (nginx) wired to the same-origin API path

    4 guided steps

    The frontend is stateless static content, so it deploys like any other Deployment but is even simpler: no Secret, no env injection, fewer replicas. This is also where the build-time vs runtime distinction becomes concrete: notice the frontend Deployment references neither the ConfigMap nor any VITE_ variable, because those were already compiled into the image. Doing it as a second Deployment plus Service is also where you start to feel the YAML duplication, two near-identical files differing mostly in name, image, and port, which is exactly the sprawl Helm will template away next rung.

  5. 5

    Expose TaskFlow over HTTPS with an Ingress via the AWS Load Balancer Controller

    4 guided steps

    Pods and ClusterIP Services are cluster-internal; something has to bridge the public internet to them, and it should do so over TLS. The LB Controller watches Ingress objects and creates a real AWS ALB with target groups pointing at your pods and an HTTPS listener backed by an ACM certificate, so you get a familiar, production-grade, encrypted entrypoint driven declaratively. Path-based routing (/ to frontend, /api to backend) is what lets the baked-in same-origin /api work and dodge CORS.

  6. 6

    Operate it: self-heal, scale, and roll a new image

    4 guided steps

    Declarative desired state is only valuable if you can see it working. Self-healing (a deleted pod returns), horizontal scaling (one command, no launch templates), and health-gated rolling updates with instant rollback are the concrete payoffs of moving from ASG to Kubernetes. Feeling these is what justifies the cluster's added complexity, and feeling the YAML sprawl across all these files is what justifies Helm next.

What's inside when you start

3 starter files, ready to clone
6 guided milestones
4 full reference solutions
7 code blocks explained line-by-line
6 "is it working?" checks
5 interview questions it prepares you for

You'll walk away with

A k8s/ directory of raw manifests (namespace, ConfigMap, backend and frontend Deployments and Services, Ingress, kustomization) that deploys TaskFlow with one kubectl apply -k, with the DATABASE_URL Secret created imperatively and intentionally excluded from kustomize
An EKS cluster running TaskFlow as 3 backend and 2 frontend pods, reachable over the internet through an HTTPS ALB (ACM certificate) created by the Ingress
Liveness and readiness probes on /healthz plus resource requests and limits on every workload, with the backend reading DATABASE_URL from a Secret and the frontend's same-origin /api path baked in at build time (recorded as VITE_API_URL in a ConfigMap)
A short runbook (in the README) showing the self-heal, scale, rolling-update, and rollback commands you exercised

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building