Problem
On the first start of a container (empty data volume), run.sh does not exec the server. Setup has already started OpenDJ in the background, so the script ends with (run.sh#L97-L102):
# Opendj is probably already started in detach mode at the install
if (bin/status -n | grep Started); then
echo "OpenDJ is started"
# Use tail instead of sleep to allow the container to be stopped with SIGTERM
tail -f /dev/null
fi
PID 1 of the container is then bash, which installs no handler for SIGTERM. The kernel does not deliver a signal without a handler to the init process of a PID namespace (pid_namespaces(7)), and tail never receives it. So docker stop / pod termination has no effect until the grace period runs out, and then everything is SIGKILLed. The server is never stopped cleanly: the JE environment is not closed, and nothing is flushed.
Measured with openidentityplatform/opendj:latest (2026-07-17):
| start |
processes |
docker stop -t 20 |
exit code |
| first start (bootstrap) |
1 bash, java, tail |
20 s (the whole timeout) |
137 (SIGKILL) |
restart of the same container (./data/config exists, exec ./bin/start-ds --nodetach) |
1 java |
4 s |
143 (SIGTERM handled) |
On Kubernetes the first pod lifetime therefore always ends with a kill after terminationGracePeriodSeconds (30 s by default).
Expected
The container stops cleanly on SIGTERM whether or not it bootstrapped the instance. For example, after the bootstrap stop the server that setup started (bin/stop-ds) and exec ./bin/start-ds --nodetach, as the restart branch already does, so the server becomes PID 1 in both cases. (A trap 'bin/stop-ds' TERM plus wait would also work, but it keeps two code paths.)
Notes
The comment above tail -f /dev/null states the opposite intent ("to allow the container to be stopped with SIGTERM"). It does not hold for PID 1.
Found while evaluating the Helm chart proposal (discussion #1079).
Prior art
The Wren:DS image, another community fork of the same code, does this already (docker-entrypoint.sh, bootstrap/setup.sh). On the first start it:
- runs
setup --doNotStart;
- starts the server;
- applies its init scripts;
- stops the server;
exec ./bin/start-ds --nodetach, on the first start and on every later one alike.
Gluu's image (gluufederation/opendj) also ends its entrypoint with exec /opt/opendj/bin/start-ds -N, and runs the replication join in the background next to it (#1086).
Problem
On the first start of a container (empty data volume),
run.shdoes notexecthe server. Setup has already started OpenDJ in the background, so the script ends with (run.sh#L97-L102):PID 1 of the container is then
bash, which installs no handler forSIGTERM. The kernel does not deliver a signal without a handler to the init process of a PID namespace (pid_namespaces(7)), andtailnever receives it. Sodocker stop/ pod termination has no effect until the grace period runs out, and then everything isSIGKILLed. The server is never stopped cleanly: the JE environment is not closed, and nothing is flushed.Measured with
openidentityplatform/opendj:latest(2026-07-17):docker stop -t 201 bash,java,tail./data/configexists,exec ./bin/start-ds --nodetach)1 javaOn Kubernetes the first pod lifetime therefore always ends with a kill after
terminationGracePeriodSeconds(30 s by default).Expected
The container stops cleanly on
SIGTERMwhether or not it bootstrapped the instance. For example, after the bootstrap stop the server that setup started (bin/stop-ds) andexec ./bin/start-ds --nodetach, as the restart branch already does, so the server becomes PID 1 in both cases. (Atrap 'bin/stop-ds' TERMpluswaitwould also work, but it keeps two code paths.)Notes
The comment above
tail -f /dev/nullstates the opposite intent ("to allow the container to be stopped with SIGTERM"). It does not hold for PID 1.Found while evaluating the Helm chart proposal (discussion #1079).
Prior art
The Wren:DS image, another community fork of the same code, does this already (docker-entrypoint.sh, bootstrap/setup.sh). On the first start it:
setup --doNotStart;exec ./bin/start-ds --nodetach, on the first start and on every later one alike.Gluu's image (
gluufederation/opendj) also ends its entrypoint withexec /opt/opendj/bin/start-ds -N, and runs the replication join in the background next to it (#1086).