Fixes #6819: harden Dockerfiles for example and integrated test images - #7152
BobSong-dev wants to merge 9 commits into
Conversation
| useradd --system --gid shenyu --create-home --home-dir /home/shenyu shenyu && \ | ||
| chown -R shenyu:shenyu ${LOCAL_PATH} | ||
| USER shenyu | ||
| HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 CMD ["sh", "-c", "kill -0 1"] |
There was a problem hiding this comment.
kill -0 1 asserts nothing about the application.
PID 1 is by definition the container main process, so while the container is up this probe can never fail; it reports "the process exists", which Docker guarantees anyway. I verified this locally (Docker 29.4.0) with the same USER + HEALTHCHECK pattern on a busybox image:
$ docker inspect hc1 --format '{{.State.Health.Status}}'
healthy
$ docker exec hc1 sh -c 'nc -z 127.0.0.1 8189 || echo "port 8189 NOT listening (app not ready/broken)"'
port 8189 NOT listening (app not ready/broken)
The container reports healthy while nothing is listening on the service port, and it stays healthy through startup, a deadlock, or a refusing JVM.
That is a false signal rather than no signal, because this repository already consumes health status: docker compose up --wait is being adopted as a readiness gate (#7151 for the storage e2e scripts) and healthcheck.sh gates the integrated tests. Once one of these images is pulled into a --wait-based pipeline, this probe declares it ready ~30s after start regardless of what the JVM is doing.
Please either make it a real readiness probe (the actuator health endpoint where the image exposes one, otherwise a TCP connect against the application port using whatever the base image provides), or drop the HEALTHCHECK line and land only the non-root user + labels. Note that the custom-plugin image uses test -s /opt/shenyu-custom-plugin.jar, which is a build-time invariant - same tautology, different flavour.
Aias00
left a comment
There was a problem hiding this comment.
Running these images as a non-root user and adding OCI metadata labels is a genuine improvement, and doing it consistently across all 22 example and integrated-test images (addgroup/adduser on the alpine bases, groupadd/useradd on the centos7 ones) is what a hardening PR should look like. Ownership of ${LOCAL_PATH} looks complete, the copied entries is chowned where relevant, and every exposed port is > 1024 so nothing needs root.
I am requesting changes on exactly one point.
[blocking] HEALTHCHECK ... CMD ["sh", "-c", "kill -0 1"] asserts nothing
PID 1 is the container main process by definition, so this probe can never fail while the container is up - it says "a process exists", which Docker already guarantees. Locally (Docker 29.4.0) with the same USER + HEALTHCHECK pattern:
$ docker inspect hc1 --format '{{.State.Health.Status}}'
healthy
$ docker exec hc1 sh -c 'nc -z 127.0.0.1 8189 || echo "port 8189 NOT listening (app not ready/broken)"'
port 8189 NOT listening (app not ready/broken)
Healthy while nothing is listening on the service port, and equally healthy through startup, a deadlock or a refusing JVM.
That matters because this repository already reads health status: docker compose up --wait is being adopted as the readiness gate (#7151 for the storage e2e scripts) and healthcheck.sh gates the integrated tests. The moment one of these images enters such a pipeline it is declared ready ~30s after start whatever the JVM is doing - a false signal, which is worse than none.
Please choose one:
(a) a real readiness probe per image - the actuator health endpoint where the image exposes one, otherwise a TCP connect against the application port using whatever the base image provides (and keep it working under USER shenyu);
(b) drop the HEALTHCHECK lines and land only the non-root user + labels.
Same issue in a different flavour in shenyu-integrated-test-upload-plugin/shenyu-custom-plugin: test -s /opt/shenyu-custom-plugin.jar is a build-time invariant and cannot fail at runtime either.
[nit] The two alpine images (shenyu-examples-apache-dubbo-service-xml and shenyu-examples-apache-dubbo-service) create the user with adduser -S shenyu -G shenyu without a home directory, while the centos7 variants use --create-home --home-dir /home/shenyu. Please add -h /home/shenyu so $HOME is not / and behaviour matches across images.
CI note (not a blocker): the integrated-test jobs are red here, but not because of these changes. The failure is
Unable to build image [apache/shenyu-integrated-test-upload-plugin-case:latest]:
"invalid from flag value apache/shenyu-integrated-test-custom: pull access denied for
apache/shenyu-integrated-test-custom, repository does not exist or may require 'docker login'"
plus fail-fast cancellation of the remaining cases - an image publishing/environment problem, please just re-run. The e2e-case jobs that do not depend on that base image are green.
…o fix/6819-dockerfile-hardening
Background
The Dockerfiles under shenyu-examples and shenyu-integrated-test run as root and do not provide OCI image metadata or container liveness checks. This makes the example and integration-test images harder to operate safely and consistently.
Fixes #6819
Changes
Verification