🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 8 Min Lesezeit
0

Why Your Docker Images Are Huge (and How I Slim Them Down)

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

A 1.2 GB image for a service that's a few megabytes of compiled code is one of those things everyone accepts until someone actually looks at it. Slow pulls, slow deploys, a bigger attack surface, and a registry bill that creeps up quietly. The good news is that bloated images are almost always the result of a handful of specific, fixable habits — not some deep property of Docker.



I want to walk through how I actually slim an image down, in the order I'd do it, with a before-and-after you can map onto your own Dockerfile. Nothing here is exotic. It's mostly about not shipping things you don't need, and knowing how to see what you are shipping.






First, look before you cut



You can't slim what you can't see, so the two commands I reach for first are:




CODE
docker history myapp:1.4.2
docker image inspect myapp:1.4.2






docker history breaks the image down layer by layer with the instruction and size of each. This is where the offenders reveal themselves — a RUN that installed a compiler, an apt cache nobody cleaned up, a COPY that swept in a local node_modules or a .git directory. docker image inspect gives you the full metadata, including environment variables and the layer digests.



Measure before you tune. I've watched people spend an afternoon switching base images to save 30 MB while a stray 400 MB build-tools layer sat right there in docker history. Read the layer list first, then decide where the real weight is.






The big lever: multi-stage builds



For anything compiled or bundled, multi-stage builds are the single biggest win, so I'll start there. The idea: use one stage with the full toolchain to build your artifact, then copy only the finished artifact into a clean, minimal final stage. All the compilers, headers, and dev dependencies stay behind in the build stage and never reach the shipped image.



Here's a Go service done the naive way:




CODE
# Before — ships the entire Go toolchain
FROM golang:1.22
WORKDIR /src
COPY . .
RUN go build -o /bin/app ./cmd/app
CMD ["/bin/app"]






That image carries the whole golang toolchain — easily 700+ MB — to run a single static binary. Now the multi-stage version:




CODE
# After — build stage stays behind, final image ships only the binary
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app ./cmd/app

FROM gcr.io/distroless/static-debian12
COPY --from=build /bin/app /bin/app
USER nonroot:nonroot
CMD ["/bin/app"]






The final image contains the binary and almost nothing else. The same pattern applies to Node (build/bundle in one stage, copy dist and production node_modules into a slim runtime), Java, Rust, Python with wheels — anything with a build step that produces an artifact you can hand off.






Pick a smaller base — and be honest about the tradeoffs



Your base image is often most of your size, so it's worth choosing deliberately. There's a rough ladder from biggest to smallest:





  • Full distro (debian, ubuntu, node:20) — everything included, largest.


  • -slim variants (debian:12-slim, node:20-slim) — the same familiar userland with docs, man pages, and extras stripped. Usually my default. You keep glibc and a normal package manager, you just carry less.


  • Alpine (alpine, node:20-alpine) — tiny, but built on musl libc instead of glibc.


  • Distroless / scratch — no shell, no package manager, minimal or zero OS. Smallest and lowest attack surface, but hardest to debug interactively.



Let me be honest about Alpine, because "just use alpine" gets repeated as if it's free. It's genuinely small, but musl is not glibc, and that difference is real. Some Python wheels won't have musl builds and fall back to compiling from source; occasionally you hit subtle DNS-resolution or locale differences; and there have been well-documented cases of performance quirks under musl for certain workloads. None of that makes Alpine wrong — plenty of production runs happily on it — but "smaller image" isn't the whole equation. If you're on glibc everywhere else and don't want surprises, -slim is the boring, safe middle ground. The boring answer is usually the right one here.



And whatever you choose, pin it. Prefer a digest for reproducibility:




CODE
FROM debian:12-slim@sha256:2a1f...b8e0






A floating tag like latest means the image can change under you between builds, which is exactly the kind of non-determinism you don't want in a runtime base.






.dockerignore — stop shipping your repo



This one is almost free and constantly overlooked. Every COPY . . sends your entire build context to the daemon, and whatever isn't ignored can end up baked into a layer — .git, local node_modules, test fixtures, .env files, build output. A tight .dockerignore prevents all of that:




CODE
.git
node_modules
*.log
.env
.env.*
dist
coverage
Dockerfile
README.md






Beyond size, this also protects your build cache: if .git is in the context, your COPY . . layer busts every single commit even when no source file changed. Excluding .env* is a nice belt-and-suspenders against secrets, too — which brings me to the next point.






Clean package caches in the same RUN layer



Remember that every RUN creates a layer, and a layer is a permanent diff. If you install packages in one RUN and delete the cache in a later RUN, the cached files still live in the earlier layer forever. The final image only hides them; it doesn't shrink. Deleting a file in a later layer can actually make the image slightly larger, because now you're storing both the file and the record of its deletion.



So do the install and the cleanup in one instruction:




CODE
# Wrong — cache lives on in the earlier layer
RUN apt-get update && apt-get install -y curl ca-certificates
RUN rm -rf /var/lib/apt/lists/*

# Right — install and clean in the same layer
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*






The --no-install-recommends flag matters more than it looks — it skips the pile of "suggested" packages apt would otherwise drag in. Same principle for other tools: pip install --no-cache-dir, npm ci && npm cache clean --force, apk add --no-cache.






Don't bake secrets into layers



While we're on layers being permanent: never COPY a secret in, use it, and RM it in a later step. It's still sitting in the earlier layer, fully readable to anyone who pulls the image and runs docker history or unpacks the tar. Same goes for putting secrets in ENV — they're baked into the image metadata.



If you need a credential at build time (a private registry token, an SSH key for a private dependency), use BuildKit secret mounts so it's never written to a layer at all:




CODE
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci --omit=dev









CODE
docker build --secret id=npmrc,src=$HOME/.npmrc -t myapp:1.4.2 .






The secret is available only during that RUN and leaves no trace in the final image. For runtime secrets, inject them as environment variables or mounted files when the container starts — never at build.



While you're tightening things up, it's worth running the finished Dockerfile through the free with patterns for the common languages. Grab one as a starting point and adapt it to your service.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Why Your Docker Images Are Huge (and How I Slim Them Down)

Thematisch verwandte Begriffe: Your, Docker, Images, Huge · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...