Docker Health Checks
How to use DISA-required Docker health checks in container images deployed to Game Warden, including Dockerfile and Kubernetes alternatives.
The Defense Information Systems Agency (DISA) requires a Docker health check to verify the health of applications running inside containers. This check validates that services are running and responsive, ensuring continued availability.
Game Warden recommends using a healthcheck command directly in your container image to meet this requirement.
You may use a Kubernetes Liveness Probe instead of a Docker healthcheck. To remain compliant, justify this exception in Findings.
DISA specification — From Container Image Creation and Deployment Guide (Section 2.6):
"Ensuring a container service is still executing and handling workloads is necessary to validate service availability. Adding the health check instruction, HEALTHCHECK, within Docker, to the container image, provides a mechanism for the container platform to periodically check the running container instance against that instruction to ensure the instance is still working. Based on the reported health status, the container platform can then exit a non-working container and instantiate a new one bringing the service back to an available state. Short lived containers that do not require a health check can be submitted for a waiver."
IA Control: SC-5 | CCI: CCI-002385
Docker healthcheck requirements
Embed a Docker healthcheck command in your container image to verify the container's health at configured intervals. If the health check fails, Docker marks the container as unhealthy and may restart it, depending on your configuration.
- The Department of War (DOW) requires a health check even though newer versions of Docker do not enforce it.
- In Game Warden, missing health checks may appear as
Healthcheck not foundin scan results due to compliance scanning. - Iron Bank base images do not include a
healthcheckby default.
Health check options in Game Warden
You can meet DISA's requirement in two ways:
- Docker
healthcheck(recommended) — Add thehealthcheckinstruction directly to your Dockerfile. - Kubernetes liveness probe (acceptable alternative) — If you use a liveness probe instead, document this in Findings:
- In Vulnerability dropdown, select Policy N/A.
- In Justification, enter:
Using Kubernetes liveness probe.
Common implementation methods
Below is a Dockerfile that includes a healthcheck command using the curl command.
FROM python:3.8-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s \
CMD curl --fail localhost:8080/health || exit 1
EXPOSE 8080
CMD ["python", "app.py"]
Run this curl command every 10 seconds to verify localhost:8000/health. Mark the container unhealthy if the command fails.
Dockerfile with wget
You can use wget to add the health check to the Dockerfile:
FROM alpine:3.12
RUN apk update && apk add --no-cache wget
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s \
CMD wget --spider http://localhost || exit 1
This method allows you to check if a URL is accessible without downloading content (--spider).
Below is a Dockerfile that includes a healthcheck command using the curl command.
FROM python:3.8-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s \
CMD curl --fail localhost:8080/health || exit 1
EXPOSE 8080
CMD ["python", "app.py"]
Run this curl command every 10 seconds to verify localhost:8000/health. Mark the container unhealthy if the command fails.
Dockerfile with wget
You can use wget to add the health check to the Dockerfile:
FROM alpine:3.12
RUN apk update && apk add --no-cache wget
HEALTHCHECK --interval=10s --timeout=5s --start-period=15s \
CMD wget --spider http://localhost || exit 1
This method allows you to check if a URL is accessible without downloading content (--spider).
A Kubernetes liveness probe monitors container health and determines when Kubernetes should restart the container.
To use a liveness probe in Kubernetes, you must define a pod that uses the image then configure a liveness probe that runs the healthcheck command.
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
containers:
- name: my-app-container
image: my-app-image
livenessProbe:
exec:
command:
- curl
- localhost:8080/health
initialDelaySeconds: 15
periodSeconds: 10
Below is an example of a liveness probe using wget:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-container
image: my-image
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
Distroless containers are minimal and lack shells or common utilities such as curl or wget. Health checks in these containers require different approaches:
- Mini Web Server in a JAR — Serve a
/healthendpoint and run a Java-based probe. - wget from BusyBox — Use a multi-stage build to copy
wgetinto the container before adding a health check.
This method performs a health check by running a small, lightweight web server inside your container.
Create a mini web server
Similar to a standard web server, it serves content over HTTP. This server will respond to requests that indicate the container's health.
Bundle the mini web server into a Java ARchive (JAR)
A JAR is similar to a .zip file—it compresses and packages several Java classes and resources into a single file. This approach allows you to reuse common features across applications without rewriting code.
For example, you can add health check logic to a Java class, include it in a JAR, and run it in any containerized application.
Build the container
Run the following commands to compile the classes, create the JAR files, and build your Docker image:
javac TheComSunNetHttpServer.java jar -c -e TheComSunNetHttpServer -v -f TheComSunNetHttpServer.jar TheComSunNetHttpServer.class javac HealthCheck.java jar -c -e HealthCheck -v -f HealthCheck.jar HealthCheck.class docker build -f Dockerfile-java . -t java-healthcheck
This method performs a health check by running a small, lightweight web server inside your container.
Create a mini web server
Similar to a standard web server, it serves content over HTTP. This server will respond to requests that indicate the container's health.
Bundle the mini web server into a Java ARchive (JAR)
A JAR is similar to a .zip file—it compresses and packages several Java classes and resources into a single file. This approach allows you to reuse common features across applications without rewriting code.
For example, you can add health check logic to a Java class, include it in a JAR, and run it in any containerized application.
Build the container
Run the following commands to compile the classes, create the JAR files, and build your Docker image:
javac TheComSunNetHttpServer.java jar -c -e TheComSunNetHttpServer -v -f TheComSunNetHttpServer.jar TheComSunNetHttpServer.class javac HealthCheck.java jar -c -e HealthCheck -v -f HealthCheck.jar HealthCheck.class docker build -f Dockerfile-java . -t java-healthcheck
In this example, you'll use a multistage Docker build to copy wget from BusyBox before running it as part of your health check.
- Why multistage builds? They allow you to separate the Docker build process into several steps, keeping the final image smaller and more secure.
- Why BusyBox? Known as the "Swiss Army knife" for Unix/Linux, BusyBox packages common Linux utilities—such as
cp,rm, andmkdir—into a single lightweight executable. These tools are not available by default in distroless containers, making BusyBox a useful source for adding them.
Build the container
Run the following command:
javac TheComSunNetHttpServer.java jar -c -e TheComSunNetHttpServer -v -f TheComSunNetHttpServer.jar TheComSunNetHttpServer.class docker build -f Dockerfile-wget . -t wget-healthcheck
The Java-based health check for Docker method demonstrates how to perform a health check without relying on additional utilities such as curl or wget.
This approach uses:
- Java 11 single-file program — allows you to run a .java file directly without compiling with
javac. - Java HttpClient — sends HTTP requests and verify responses.
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
public class HealthCheck {
public static void main(String[] args) throws InterruptedException, IOException {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080/actuator/health"))
.header("accept", "application/json")
.build();
var response = client.send(request, BodyHandlers.ofString());
if (response.statusCode() != 200 || !response.body().contains("UP")) {
throw new RuntimeException("Healthcheck failed");
}
}
}
How it works:
- Sends a
GETrequest to/actuator/health. - Checks if the HTTP status code is 200 (OK) and the response body contains "UP", indicating a healthy service.
- Throws a
RuntimeExceptionif either check fails; otherwise, it exits silently.
Docker image best practices
-
Expose a health endpoint that returns 200 only when the app is actually ready (connections open, migrations done, deps reachable). This enables safe autoscaling and zero-downtime deploys.
Example: App exposes
/healthzand returns 200 only when ready:dockerfileHEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ CMD curl -fsS http://localhost:8080/healthz || exit 1 -
Never run processes as root inside containers.
Example: Create unprivileged user:
dockerfileRUN addgroup -S app && adduser -S app -G app USER app -
Each
RUN,COPY,ADDmakes a layer. Combine related commands and clean caches to shrink images. -
Exclude anything not needed at runtime/build (node_modules, tests, .git, IDE files, secrets).
-
Use immutable, descriptive tags (for example,
1.4.3,2025.10.01-sha.abcd123). This makes rollbacks/audits reliable. -
Never bake API keys, tokens, or certs into layers or files. Inject via env vars/secret stores at deploy. Configure CI scanners (for example, Trivy) to fail the build when they detect secrets.
-
Build artifacts in one stage, then copy only the required artifacts into the final image.
-
Choose distroless, Alpine, or Chainguard images when possible, and avoid large base images unless you need them. If you only need to serve static files or a single binary, use the scratch base image (0-byte base image).
-
Smaller images lead to faster pulls and a smaller attack surface.