Building Lightweight Docker Containers for Monitoring: The `FROM scratch` Guide

How to shrink your Docker images from 1GB to 5MB. Multi-stage builds, static linking, and security benefits.

J
Jesus Paz
2 min read

In the world of microservices and edge computing, Size Matters. A 1GB Docker image takes time to pull. It costs money to store. It has thousands of packages that could hide security vulnerabilities (CVEs).

For a single-purpose tool like a Monitoring Agent, there is no excuse for a large image. At Cluster Uptime, our agent image is 5MB. Here is how we do it.

1. The Multi-Stage Build

Do not ship your compiler to production. You need gcc and go to build the app. You do not need them to run it.

# Stage 1: The Builder (Has all the heavy tools)
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Compile static binary
RUN CGO_ENABLED=0 GOOS=linux go build -o agent -ldflags="-s -w" main.go
# Stage 2: The Runner (Empty)
FROM scratch
WORKDIR /
# Copy ONLY the binary from Stage 1
COPY --from=builder /app/agent /agent
# Copy root certificates (needed for HTTPS)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/agent"]

2. scratch vs alpine vs distroless

  • Ubuntu/Debian: ~70MB base. Contains bash, apt, coreutils. (Too big).
  • Alpine: ~5MB base. Contains sh, apk. (Good).
  • Distroless (Google): ~2MB. No shell. (Better security).
  • Scratch: 0MB. Empty. (Best).

Why Scratch? If there is no shell (/bin/sh), an attacker cannot “shell into” your container. Even if they find a Remote Code Execution (RCE) vulnerability in your app, they cannot run curl or rm -rf because those tools arguably don’t exist inside the container.

3. Static Linking (CGO_ENABLED=0)

By default, Go binaries might link to system C libraries (glibc). Setting CGO_ENABLED=0 forces Go to use its own native implementations (e.g., for DNS resolution). This ensures your binary has zero external dependencies and can run on an empty scratch image.

Conclusion

Small images are:

  1. Faster: Faster CI/CD pipelines, faster autoscaling.
  2. Cheaper: Less bandwidth, less registry storage.
  3. Safer: A smaller attack surface.

Put your container on a diet.

👨‍💻

Jesus Paz

Founder

Read Next

Join 1,000+ FinOps and platform leaders

Get uptime monitoring and incident response tactics delivered weekly.