distroless README

The project's README from github.com/GoogleContainerTools/distroless. As one markdown file: README.md.

"Distroless" Container Images.

CI Build Status

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

For more information, see this talk (video).

Why should I use distroless images?

Restricting what's in your runtime container to precisely what's necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.

Distroless images are very small. The smallest distroless image, gcr.io/distroless/static-debian13, is around 2 MiB. That's about 50% of the size of alpine (~5 MiB), and less than 2% of the size of debian (124 MiB).

How do I use distroless images?

These images are built using bazel, but they can also be used through other Docker image build tooling.

What images are available?

The following images are currently published and updated by the distroless project (see SUPPORT_POLICY.md for support timelines)

These images refer to image indexes with references to all supported architectures. Architecture specific images can be directly referenced using an additional architecture suffix on the tag, like gcr.io/distroless/static-debian13:latest-amd64

Any other tags are considered deprecated and are no longer updated

Debian 13

Debian 13 distroless images use the debian UsrMerge scheme. If you use rules_distroless to add packages to an image, set mergedusr = True in apt.install.

Image Tags Architecture Suffixes
gcr.io/distroless/static-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, arm, s390x, ppc64le, riscv64
gcr.io/distroless/base-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, arm, s390x, ppc64le, riscv64
gcr.io/distroless/base-nossl-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, arm, s390x, ppc64le, riscv64
gcr.io/distroless/cc-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, arm, s390x, ppc64le, riscv64
gcr.io/distroless/java-base-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le, riscv64
gcr.io/distroless/java17-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le, riscv64
gcr.io/distroless/java21-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le, riscv64
gcr.io/distroless/java25-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le, riscv64
gcr.io/distroless/nodejs22-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, arm, s390x, ppc64le
gcr.io/distroless/nodejs24-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le
gcr.io/distroless/nodejs26-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, s390x, ppc64le
gcr.io/distroless/python3-debian13 latest, nonroot, debug, debug-nonroot amd64, arm64, riscv64

Why is distroless still using gcr.io instead of pkg.dev?

Distroless's serving infrastructure has moved to artifact registry but we still use the gcr.io domain. Users will get the benefits of the newer infrastructure without changing their builds.

How do I verify distroless images?

All distroless images are signed by cosign with ephemeral keys (keyless). We recommend verifying any distroless image you use before building your image. You can verify the keyless signature of any distroless image with:

cosign verify $IMAGE_NAME --certificate-oidc-issuer https://accounts.google.com --certificate-identity [email protected]

Entrypoints

Note that distroless images by default do not contain a shell. That means the Dockerfile ENTRYPOINT command, when defined, must be specified in vector form, to avoid the container runtime prefixing with a shell.

This works:

ENTRYPOINT ["myapp"]

But this does not work:

ENTRYPOINT "myapp"

For the same reasons, if the entrypoint is set to the empty vector, the CMD command should be specified in vector form (see examples below). Note that by default static, base and cc images have the empty vector entrypoint. Images with an included language runtime have a language specific default (see: java, nodejs, python3).

Docker

Docker multi-stage builds make using distroless images easy. Follow these steps to get started:

Examples with Docker

Here's a quick example for go:

# Start by building the application.
FROM golang:1.18 as build

WORKDIR /go/src/app
COPY . .

RUN go mod download
RUN CGO_ENABLED=0 go build -o /go/bin/app

# Now copy it into our base image.
FROM gcr.io/distroless/static-debian13
COPY --from=build /go/bin/app /
CMD ["/app"]

You can find other examples here:

To run any example, go to the directory for the language and run:

docker build -t myapp .
docker run -t myapp

To run the Node.js Express example app and expose the container's ports:

npm install # Install express and its transitive dependencies
docker build -t myexpressapp . # Normal build command
docker run -p 3000:3000 -t myexpressapp

This should expose the Express application to your localhost:3000

Bazel

For full documentation on how to use bazel to generate Container images, see the bazel-contrib/rules_oci repository.

For documentation and example on how to create custom container images, see the GoogleContainerTools/rules_distroless repository.

Examples can be found in the GoogleContainerTools/rules_distroless repository.

Examples with Bazel

We have some examples on how to run some common application stacks in the /examples directory. See here for:

See here for examples on how to complete some common tasks in your image:

See here for more information on how these images are built and released.

Base Operating System

Distroless images are based on Debian 13 (trixie). Images are explicitly tagged with Debian version suffixes (e.g. -debian13). Specifying an image without the distribution will currently select -debian13 images, but that will change in the future to a newer version of Debian. It can be useful to reference the distribution explicitly, to prevent breaking builds when the next Debian version is released.

Operating System Updates for Security Fixes and CVEs

Distroless tracks the upstream Debian releases, using Github actions to automatically generate a pull request when there are updates.

Debug Images

Distroless images are minimal and lack shell access. The :debug image set for each language provides a busybox shell to enter.

For example:

cd examples/python3/

edit the Dockerfile to change the final image to :debug:

FROM gcr.io/distroless/python3-debian13:debug
COPY . /app
WORKDIR /app
CMD ["hello.py", "/etc"]

then build and launch with a shell entrypoint:

docker build -t my_debug_image .
$ docker run --entrypoint=sh -ti my_debug_image

/app # ls
BUILD       Dockerfile  hello.py

Note: If the image you are using already has a tag, for example gcr.io/distroless/java17-debian13:nonroot, use the tag debug-<existing tag> instead, for example gcr.io/distroless/java17-debian13:debug-nonroot.

Note: ldd is not installed in the base image as it's a shell script, you can copy it in or download it.

Who uses Distroless?

If your project uses Distroless, send a PR to add your project here!

Community Discussion

distroless (GoogleContainerTools/distroless)

Searching Database…

这是什么?一套极简的容器基础镜像,里面只包含你的应用及其运行时依赖——没有包管理器、shell,也没有普通 Linux 发行版里你会见到的其他程序。
所以这不是能安装的东西——我实际拉取的是什么?发布在 gcr.io 上的预构建基础镜像(例如 gcr.io/distroless/static-debian13),你把它用作构建的最后一个阶段。项目本身用 Bazel 来构建这些镜像,但普通的 Docker 工具也完全够用。
怎么把我的应用跑在一个镜像上?写一个 Docker 多阶段构建(需要 Docker 17.05+):一个阶段负责编译你的应用,最后一个阶段把产物复制进 distroless 镜像。用 Bazel 的人可以配合 rules_oci 和 rules_distroless,仓库里还有 Go、Java、Python、Node.js 和 Rust 的可运行示例。
这些镜像覆盖了哪些语言运行时?基于 Debian 13 的镜像覆盖静态二进制文件、C/C++(cc)、Java 17/21/25、Node.js 22/24/26 和 Python 3,另外还有一个纯基础镜像和一个 base-nossl 变体。每个都发布为 latest、nonroot、debug 和 debug-nonroot 四个版本。
里面没有 shell,那我的 Dockerfile 要改什么?ENTRYPOINT 必须写成向量(exec)形式,例如 ENTRYPOINT ['/app/server'],否则运行时会尝试在前面加一个并不存在的 shell。static、base 和 cc 镜像默认是空的 entrypoint;语言镜像则自带各自语言专属的 entrypoint。
这是只有大厂才用的玩法,小团队也能用吗?谁都可以用——把运行时容器限制到应用真正需要的东西,正是 Google 等科技巨头遵循的最佳实践,Kubernetes、Knative、Tekton 和 Teleport 这些项目也都构建在这些镜像之上。
支持哪些 CPU 架构?多架构镜像索引覆盖 amd64、arm64、arm、s390x、ppc64le 和 riscv64,不过各个运行时发布的架构列表略有不同。可以用类似 :latest-amd64 的标签后缀来固定某一个架构。
为什么选 distroless 而不是 Alpine 或精简版 Debian 镜像?看体积和扫描器的噪音:最小的静态镜像约 2 MiB,大概是 Alpine(~5 MiB)的一半,不到 Debian(124 MiB)的 2%。里面没有 shell 和包管理器,CVE 扫描器报出的噪音更少,来源追溯也更容易。
容器里没有 shell,我怎么调试?把镜像标签换成对应的 :debug 变体(或 debug-nonroot)——这些版本带了一个可以进入的 busybox shell。有个坑:基础镜像里没有 ldd,因为它本身是个 shell 脚本。
镜像为什么还放在 gcr.io 下面?服务基础设施已经迁到了 Artifact Registry,但 distroless 保留了 gcr.io 域名,这样现有的构建不用做任何改动就能用上新的基础设施。
这些镜像如何保持可信并及时更新?每个镜像都用 cosign 配合临时(无密钥)密钥签名,项目建议你在基于镜像构建之前先做验证。安全修复紧跟上游 Debian 的发布,还有 GitHub Actions 自动提交更新 PR。
Size
9.9 MB
Stars
23.1K
Updated
CommitOct 15
Age
9y
Commits · 90 Days