All Dockerfiles in this repository run as non-root users:
- Distroless: Uses the built-in
nonrootuser (uid 65534) - Alpine: Creates a dedicated
appuser(uid 1001) - Scratch: Runs as uid 1001
Never run containers as root in production.
| Base Image | Shell | Package Manager | Attack Surface |
|---|---|---|---|
scratch |
No | No | Minimal |
gcr.io/distroless/cc-debian13 |
No | No | Minimal |
gcr.io/distroless/java25-debian13 |
No | No | Low |
alpine |
Yes | Yes (apk) | Low |
eclipse-temurin:25-jre-alpine |
Yes | Yes (apk) | Medium |
Scan your images regularly for CVEs:
# Using Docker Scout
docker scout cves myapp-distroless
# Using Trivy
trivy image myapp-distroless
# Using Grype
grype myapp-distroless- Pin exact base image tags or digests in CI/CD when reproducibility matters (for example, prefer a fully qualified Temurin tag or image digest instead of a floating major tag)
- Pin Maven/Gradle plugin versions
- Use
--no-cachefor CI builds to avoid stale layers
- Never bake secrets into Docker images
- Use Docker secrets, environment variables at runtime, or a secrets manager
- The
.dockerignorefile excludes.envfiles from the build context
- Expose only required ports
- Prefer images without a shell or package manager for production (
distrolessorscratchvariants) - Use read-only file systems when possible:
docker run --read-only --tmpdir /tmp myapp-distroless
Always set resource limits in production:
docker run -m 512m --cpus="1.0" myapp-distroless