Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

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

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.…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

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:




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:




# 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:




# 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:




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:




.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:




# 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:




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









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 Dockerfile validator — it catches a lot of the structural mistakes above (missing --no-install-recommends, secrets in ENV, unpinned bases) before they ever reach a build.






The before/after, end to end



Putting the habits together on a Node service:




# Before — ~1.1 GB
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]









# After — often well under 200 MB
# syntax=docker/dockerfile:1
FROM node:20-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]






Multi-stage to leave the build tooling behind, a -slim base, dependency install split from source COPY for cache friendliness, dev dependencies pruned, and a .dockerignore keeping the context clean. Then confirm it with docker history myapp:1.4.2 and watch the fat layers disappear.






Wrapping up



Slim images come from a short, repeatable checklist: measure with docker history first, use multi-stage builds to drop the toolchain, pick a base you understand the tradeoffs of and pin it, keep a real .dockerignore, clean caches in the same RUN, and never bake a secret into a layer. Do those and the size problem mostly takes care of itself — and the security surface shrinks along with the bytes.



If you want worked reference setups to copy from rather than assemble by hand, there's a Docker stack toolkit with patterns for the common languages. Grab one as a starting point and adapt it to your service.

Ä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 ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94030 | A security vulnerability has been detected in SerenityOS up to 3d83e4509…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick