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:

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

✅ 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

✅ 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

✅ Perfect for microservices deployed in AKS or Azure VM.