A 1.2GB Node.js Docker image became 180MB with three changes. Here is exactly what was changed, why it worked, and how to apply the same fixes to any production image.
Kubernetes pulls images on every new node that schedules a pod. A 1.2GB image takes 45-90 seconds to pull on a cold node versus 8-12 seconds for a 180MB image. During a rollout, if a pod lands on a node that has not cached the image, the pull time directly adds to your deployment latency. In EKS clusters with auto-scaling, new nodes are cold by definition — every scale-out event pays the full pull cost. Smaller images also reduce the ECR egress charges when pulling across availability zones.
They solve different problems and are most effective combined. A multi-stage build removes build-time dependencies — compilers, test frameworks, package managers — from the final image by copying only the built artifact into a clean runtime image. An Alpine base image replaces a 180MB Debian/Ubuntu base with a 5MB musl-libc base. Multi-stage builds typically save 200-800MB by dropping build tools. Alpine saves another 150-175MB on the base layer. Used together they are multiplicative — a Node.js build that would be 1.2GB becomes 30-50MB. The trade-off with Alpine is musl-libc compatibility: some npm packages with native bindings behave differently under musl than glibc. Test Alpine builds thoroughly before deploying to production.
Discussion0