Docker images can specify a HEALTHCHECK
command to run a test to determine if the container is healthy. Docker compose also has a similar feature. This however is executed in the container itself, and not on the host. This creates a problem for Distroless images, as they do not have common binaries like curl
or wget
installed by design. There have been many requests to expand on this functionality (#183, #316, #4296), but until official support is added by either Google, Docker or Microsoft, this utility is here to help.
This is a simple pre-compiled .Net app, that is able to run a health check against a list of URIs. It runs on the minimal runtime-deps:*-chiseled-aot
image, so it will run on any chiseled as well.
It works with any .NET 8
or .NET 9
base image (even those that are not chiseled). For example
FROM mcr.microsoft.com/dotnet/aspnet:8.0-noble-chiseled AS final
# Get the executable and copy it to /healthchecks
COPY --from=ghcr.io/alexaka1/distroless-dotnet-healthchecks:1 / /healthchecks
# Setup the healthcheck using the EXEC array syntax
HEALTHCHECK CMD ["/healthchecks/Distroless.HealthChecks", "--uri", "http://localhost:8080/healthz"]
# Start your app as normal
WORKDIR /app
ENTRYPOINT ["dotnet", "My.Awesome.Webapp.dll"]
The published docker image contains only the executable of the health check at root. This is so it can be conveniently copied inside a Dockerfile. But you can also get the binary from GitHub and copy it manually into your image.
It takes in a single argument named uri
, which is a URI that the app will check. If the URI returns a 200 status code, the health check will pass.
If you don't want to use GitHub Container Registry, the image is also available on Docker Hub.
Note
You can only use loopback address for the URIs. Using a URI that does not resolve to the container will result in a failure.
Health check is compiled as AOT, so it can run on the most bare runtime-deps:*-chiseled-aot
images with no issues. These aot images are only published on the nightly channel as of .NET 9.
It uses a generic host, so you have the full .NET Configuration system available to you. For example, you don't have to bake in your healthcheck uri into your image, you can use DISTROLESS_HEALTHCHECKS_
prefixed environment variables to specify the runtime settings.
FROM mcr.microsoft.com/dotnet/nightly/runtime-deps:8.0-noble-chiseled-aot
# Get the executable and copy it to any path you want
COPY --from=ghcr.io/alexaka1/distroless-dotnet-healthchecks:1 / /iamspecial
# Setup your healthcheck endpoints via environment variable in Dockerfile, or at runtime via `docker run -e DISTROLESS_HEALTHCHECKS_URIS__0="http://localhost/healthz" -e DISTROLESS_HEALTHCHECKS_URIS__1="http://localhost/some/other/endpoint"`
ENV DISTROLESS_HEALTHCHECKS_URI="http://localhost/healthz"
# Setup the healthcheck using the EXEC array syntax
HEALTHCHECK CMD ["/iamspecial/Distroless.HealthChecks"]
# Start your app as normal
WORKDIR /app
ENTRYPOINT ["./My.Awesome.Aot.WebApp"]
Important
For simplicity's sake the health check uses the generic host from Host.CreateApplicationBuilder(settings)
. This means that if your app uses DOTNET_
prefixed environment variables, they will interfere with the health check as they will be read by the host.
Note
The DISTROLESS_HEALTHCHECKS_
prefix environment variables are read after the DOTNET_
prefixed environment variables, so if DOTNET_
prefixed environment variables are defined, they will take precedence for certain defaults of the generic host. This may not be ideal for all use cases. Feel free to open an issue with your use case.
The image uses semver. It is recommended that you pin it to at least a major version, instead of latest
. I.e. ghcr.io/alexaka1/distroless-dotnet-healthchecks:1
.
The Uri
parameter is just a convenience input for baking in the url to the Dockerfile. You can however set logic to your builds to configure the underlying Uri array instead. Such as: DISTROLESS_HEALTHCHECKS_Uris__0=http://localhost:8080/healthz
and DISTROLESS_HEALTHCHECKS_Uris__1=http://localhost/some/other/path
.
You will need the .Net 9 SDK installed, along with docker and buildx. You don't need Node, unless you plan to open PRs, in which case it is recommended you also add changesets to your PRs.
On Windows you must use WSL2 as the docker backend.
To run the tests, first build the test image:
docker build -f src/Distroless.HealthChecks/Dockerfile -t distroless-dotnet-healthchecks:test --target binary .
Then run the tests (it can take a long time):
dotnet test