Containerize Monoliths to EKS: Real Guide

Tired of flawless Docker demos that never match reality? This engineer tackled five monoliths – Node, Python, React, Go, NestJS – and deployed them to EKS, exposing the raw chaos and triumphs.

I Containerized 5 Monoliths for EKS – The Messy Truth Tutorials Hide — theAIcatchup

Key Takeaways

  • Use .dockerignore religiously to slash Node.js build contexts by 80%.
  • Ditch Alpine for Python slim images – reliability over 'tiny'.
  • Multi-stage builds are non-negotiable for TS/JS; distroless for Go perfection.

Everyone’s been promised containerization as this effortless leap to cloud-native bliss – drop your monolith in a Docker box, kubectl apply, and watch it scale like magic. But here’s the twist: that’s pure fantasy. This engineer’s gritty saga of wrestling five diverse monoliths into EKS shatters that illusion, revealing the platform shift where monoliths finally get wings without pretending it’s easy.

Look, AI’s reshaping dev tools into something godlike – auto-generating apps even – but the grunt work of containerizing legacy stacks? That’s still us humans, sleeves rolled up. And this post? It’s the unfiltered chronicle we crave.

There’s a blog post I’ve always found frustrating: the kind that shows you a perfect Dockerfile, a clean terraform apply, and a screenshot of everything working on the first try. No errors. No wrong turns.

Damn right. The author, a battle-hardened DevOps/SRE pro, didn’t settle for one app. Nope – five archetypes, each a monolith mirror from the wild: Node/Express bloat-fest, Python/Flask with its libc nightmares, NestJS TypeScript compile dance, React SPA static quirks, and Go’s sleek static bliss.

Why Containerize Monoliths Now?

Picture the 1980s mainframe era. Cobol behemoths ruled, until Unix boxes and C let teams splinter code into services. Sound familiar? That’s us today – monoliths as yesterday’s mainframes, containers as the Unix revolution. But with EKS, it’s turbocharged: Kubernetes orchestration on AWS steroids.

This isn’t hype. It’s the bridge. My bold call: in three years, AI agents will refactor these containers into microservices overnight, but only if we nail the container step first. Ignore it, and you’re roadkill in the platform wars.

The setup’s genius – simple apps with /health endpoints, AI-spun code to sideline app dev. Full repo: eks-monolith-migration. IaC, manifests, CI/CD. All there.

App Stack Lesson
app-node-api Node.js + Express node_modules, .dockerignore
app-python-api Python + Flask Slim vs Alpine
app-nestjs-api NestJS (TS) Three-stage builds
app-react-spa React + Nginx Static serving
app-go-service Go Distroless

Short. Brutal. Effective.

Node.js: Your .dockerignore Is Bleeding You Dry

First blood: Node. Everyone copies the whole project context – boom, gigabytes of node_modules clogging builds. The fix? .dockerignore like a bouncer at the door.

node_modules npm-debug.log .env git

Two-stage Dockerfile magic: deps stage with npm ci –production, runtime copies lean node_modules + src. USER node – non-root, because who wants container escapes?

Image? 235MB vs 1.1GB. That’s 80% gutted. Feels like shedding winter fat for a sprint.

But wait – tutorials skip the pain of prod-only deps. npm ci enforces it, no dev fluff. One forgetful build, and you’re debugging ghosts.

Python Flask: Alpine’s Sexy Lie

Alpine screams ‘tiny!’, right? 5MB base. Heroic.

Wrong. musl libc laughs at C extensions – cryptography, psycopg2 compile eternally or explode. Builds drag from 30s to 5min.

Switch to python:3.12-slim. glibc wheels galore. Builder stage: pip install –no-cache –prefix=/install -r requirements.txt. Runtime copies /install.

Size: 150MB-ish. Reliable. The trap? Chasing ‘tiny’ blinds you to ‘works’.

Here’s my unique jab: Pythonistas, this is your Wake-on-LAN moment. Slim’s the pragmatic base; Alpine’s for masochists or Go purists.

NestJS: TypeScript’s Three-Act Drama

NestJS – Angular vibes in backend land. TS compile? Multi-stage epic.

Stage 1: node:alpine deps, npm ci. Stage 2: Compile – npm run build, tsc spits dist/. Stage 3: Runtime – copy dist/, node_modules. Boom.

Forgets one stage? Builds balloon, cold starts crawl. Pro tip: .dockerignore swallows .next or build artifacts.

Energy surge here – it’s like prepping a shuttle launch. Tedious, but orbit awaits.

React SPA: Nginx, Don’t Break the Routes

Static assets. Easy? Ha.

Multi-stage: Node build (npm run build), then nginx:alpine copies /build to /usr/share/nginx/html. Custom nginx.conf for SPA routing – try_files $uri /index.html;

Pitfall: Forgetting EXPOSE 80 or health checks. EKS ingress hates surprises.

Size: 50MB. Lightning. Analogy: Wrapping your app in unintrusive glass – serves fast, scales free.

Go: Distroless Dreams Come True

Go’s static binaries – chef’s kiss.

FROM golang:1.23-alpine AS builder. go mod download, go build -ldflags=’-s -w’.

Runtime: gcr.io/distroless/static-debian12. COPY binary /app. USER nonroot.

10MB. Immortal. No shell, no escape vectors. Go feels like the future – compile once, deploy forever.

Why Does EKS Deployment Actually Hurt?

Dockerfiles done? Kubernetes awaits.

Manifests: Deployments with resources (CPU 100m, mem 128Mi), Services ClusterIP, Ingress with ALB.

Terraform spins EKS: eksctl create cluster –name monolith-lab. Node groups, IRSA for pod IAM.

CI/CD: GitHub Actions – docker build/push to ECR, helm upgrade or kustomize.

Broke on: Node taints (NoSchedule), Python OOMKills (bump mem), React path mismatches.

But wins: HorizontalPodAutoscaler on CPU, rolling updates zero-downtime.

The Big Shift: Monoliths to Kubernetes Reality

This saga? Proof containers unlock AI’s promise. Imagine agents scanning these images, proposing splits.

Lessons cascade: Ignore ignores at peril. Base images matter. Stages slim. Non-root always.

Prediction: EKS-like managed K8s eats bare EC2. Monolith migration? Table stakes by 2026.

Repo’s gold – fork it, break it yourself.

Thrilling, messy, transformative.


🧬 Related Insights

Frequently Asked Questions

What’s the best Dockerfile for Node.js monoliths?

Two-stage with .dockerignore excluding node_modules; use node:alpine, npm ci –production, USER node.

How to deploy containerized monoliths to EKS?

Terraform/eksctl for cluster, manifests for Deployments/Services/Ingress, GitHub Actions for CI/CD to ECR.

Python Docker: Alpine or Slim?

Slim – glibc wheels prevent compile hell; Alpine’s too brittle for C extensions.

Marcus Rivera
Written by

Tech journalist covering AI business and enterprise adoption. 10 years in B2B media.

Frequently asked questions

What’s the best Dockerfile for Node.js monoliths?
Two-stage with .dockerignore excluding node_modules; use node:alpine, npm ci --production, USER node.
How to deploy containerized monoliths to EKS?
Terraform/eksctl for cluster, manifests for Deployments/Services/Ingress, GitHub Actions for CI/CD to ECR.
Python Docker: Alpine or Slim?
Slim – glibc wheels prevent compile hell; Alpine’s too brittle for C extensions.

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by dev.to

Stay in the loop

The week's most important stories from theAIcatchup, delivered once a week.