Here are the best, practical, and production-grade ways to optimize Docker images — especially for .NET, Node, or microservices running in Kubernetes or Azure 👇
🚀 1. Use Multi-Stage Builds
Only copy what you need into the final image.
Example (.NET 8):
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
COPY . .
RUN dotnet publish -c Release -o out
# Stage 2: Runtime (small)
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "MyApp.dll"]
✅ Removes SDK tools and reduces image size by 70%+
⚙️ 2. Use Lightweight Base Images
Prefer:
alpine(e.g.,mcr.microsoft.com/dotnet/aspnet:8.0-alpine)distroless(Google’s minimal image, no shell)Avoid
ubuntuordebianunless needed.
✅ Saves 100–300 MB instantly.
📦 3. Copy Only What You Need
Avoid copying everything:
COPY ["MyApp.csproj", "./"]
RUN dotnet restore
COPY . .
Or use .dockerignore to skip unnecessary files (like node_modules, .git, logs, etc.)
✅ Smaller build context → faster build.
🔁 4. Leverage Layer Caching
Docker caches each layer — order matters.
Place less-frequently changing steps (like
dotnet restore) early.Frequently changing files (like source code) later.
✅ Speeds up rebuilds drastically.
🧹 5. Clean Temporary Files
After install commands, remove caches:
RUN apt-get update && apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
✅ Keeps image lean and clean.
🔒 6. Use Non-Root User
For security and lightweight permission layers:
RUN adduser --disabled-password appuser
USER appuser
✅ Prevents privilege escalation in containers.
🧱 7. Combine RUN Commands
Each RUN adds a new layer. Combine them:
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
✅ Fewer layers → smaller image.
🧰 8. Use Docker BuildKit
Enable it:
export DOCKER_BUILDKIT=1
docker build .
✅ Builds are faster, parallelized, and cache-efficient.
🧠 9. Compress and Scan
Use
docker image pruneanddocker system pruneto clean old layers.Scan with:
docker scan myapp:latest
✅ Removes vulnerabilities and bloat.
☁️ 10. Push Optimized Images
Before pushing to ACR or Docker Hub:
docker build --squash -t myapp:latest .
docker push myregistry.azurecr.io/myapp:latest
✅ “Squash” merges layers for minimal size.
🔍 Bonus Tips for .NET Core
Use ReadyToRun compilation for faster startup:
dotnet publish -c Release -p:PublishReadyToRun=trueTrim unused assemblies:
dotnet publish -c Release -p:PublishTrimmed=true
✅ Perfect for microservices deployed in AKS or Azure VM.

Join the conversation! Your thoughts help the community grow.