Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion opendj-packages/opendj-docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ ENV OPENDJ_USER="opendj"
ENV BACKEND_TYPE="je"
ENV BACKEND_DB_DIRECTORY="db"
#ENV SETUP_ARGS
# written by run.sh once the bootstrap has succeeded, read by the health check below
ENV BOOTSTRAP_COMPLETE="/opt/opendj/.bootstrap-complete"

ARG OPENDJ_DIST_FILENAME=opendj.zip

Expand Down Expand Up @@ -66,6 +68,13 @@ EXPOSE $PORT/tcp $LDAPS_PORT/tcp $ADMIN_PORT/tcp

USER $OPENDJ_USER

HEALTHCHECK --interval=30s --timeout=30s --start-period=1s --retries=3 CMD opendj/bin/ldapsearch --hostname localhost --port $LDAPS_PORT --bindDN "$ROOT_USER_DN" --bindPassword "${ROOT_PASSWORD:-password}" --useSsl --trustAll --baseDN "" --searchScope base "(objectClass=*)" 1.1 || exit 1
# "healthy" has to mean the instance is ready to serve, not just that it answers: setup
# starts the server in the middle of the bootstrap, before the backend of BASE_DN is
# created and its entries imported, so probing the root DSE alone reports ready while a
# search of BASE_DN still fails with "No Such Entry". Testing the marker first also keeps
# the probe from launching a JVM every interval until the bootstrap is through. The start
# period is what a bootstrap importing SAMPLE_DATA into a small container can take; a
# probe that succeeds ends it early, and a bootstrap that failed never writes the marker.
HEALTHCHECK --interval=30s --timeout=30s --start-period=5m --retries=3 CMD test -f "$BOOTSTRAP_COMPLETE" && opendj/bin/ldapsearch --hostname localhost --port $LDAPS_PORT --bindDN "$ROOT_USER_DN" --bindPassword "${ROOT_PASSWORD:-password}" --useSsl --trustAll --baseDN "" --searchScope base "(objectClass=*)" 1.1 || exit 1

ENTRYPOINT ["/opt/opendj/run.sh"]
11 changes: 10 additions & 1 deletion opendj-packages/opendj-docker/Dockerfile-alpine
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ ENV OPENDJ_USER="opendj"
ENV BACKEND_TYPE="je"
ENV BACKEND_DB_DIRECTORY="db"
#ENV SETUP_ARGS
# written by run.sh once the bootstrap has succeeded, read by the health check below
ENV BOOTSTRAP_COMPLETE="/opt/opendj/.bootstrap-complete"

ARG OPENDJ_DIST_FILENAME=opendj.zip

Expand Down Expand Up @@ -70,6 +72,13 @@ EXPOSE $PORT/tcp $LDAPS_PORT/tcp $ADMIN_PORT/tcp

USER $OPENDJ_USER

HEALTHCHECK --interval=30s --timeout=30s --start-period=1s --retries=3 CMD opendj/bin/ldapsearch --hostname localhost --port $LDAPS_PORT --bindDN "$ROOT_USER_DN" --bindPassword "${ROOT_PASSWORD:-password}" --useSsl --trustAll --baseDN "" --searchScope base "(objectClass=*)" 1.1 || exit 1
# "healthy" has to mean the instance is ready to serve, not just that it answers: setup
# starts the server in the middle of the bootstrap, before the backend of BASE_DN is
# created and its entries imported, so probing the root DSE alone reports ready while a
# search of BASE_DN still fails with "No Such Entry". Testing the marker first also keeps
# the probe from launching a JVM every interval until the bootstrap is through. The start
# period is what a bootstrap importing SAMPLE_DATA into a small container can take; a
# probe that succeeds ends it early, and a bootstrap that failed never writes the marker.
HEALTHCHECK --interval=30s --timeout=30s --start-period=5m --retries=3 CMD test -f "$BOOTSTRAP_COMPLETE" && opendj/bin/ldapsearch --hostname localhost --port $LDAPS_PORT --bindDN "$ROOT_USER_DN" --bindPassword "${ROOT_PASSWORD:-password}" --useSsl --trustAll --baseDN "" --searchScope base "(objectClass=*)" 1.1 || exit 1

ENTRYPOINT ["/opt/opendj/run.sh"]
25 changes: 25 additions & 0 deletions opendj-packages/opendj-docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,36 @@ Run image
docker run -d -p 1389:1389 -p 1636:1636 -p 4444:4444 --name opendj openidentityplatform/opendj
```

## Health check

The image reports itself `healthy` once the server answers on `LDAPS_PORT` *and* the whole
bootstrap has succeeded - the instance, the `userRoot` backend over `BASE_DN`, whatever
`ADD_BASE_ENTRY` and `SAMPLE_DATA` asked to be imported into it, and the replication asked
for by `MASTER_SERVER`. Waiting for that status is therefore enough before the first search
of what the bootstrap was told to create:

```bash
docker run -d --name opendj -e ADD_BASE_ENTRY=--addBaseEntry openidentityplatform/opendj
timeout 5m bash -c 'until [ "$(docker inspect -f "{{.State.Health.Status}}" opendj)" = healthy ]; do sleep 5; done'
```

In Compose the same is `depends_on: { opendj: { condition: service_healthy } }`. Note that
without `ADD_BASE_ENTRY` nothing creates the base entry, so `BASE_DN` is an empty suffix on
a healthy container - the health check itself searches the root DSE, which every instance
serves whatever it was set up to hold.

A bootstrap that imports `SAMPLE_DATA` can take minutes on a small container, which is what
the start period allows for. A bootstrap that fails - or an upgrade that fails when starting
over an instance that is already there - never reports healthy: what failed is in `docker
logs`, and where the server is up at all the container is left running to be looked at,
turning `unhealthy` once the start period is over.

## Environment Variables

| Variable | Default Value | Description |
|-------------------------|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ADD_BASE_ENTRY | | if set --addBaseEntry , creates base DN entry |
| SAMPLE_DATA | - | with ADD_BASE_ENTRY set, imports that many generated users under BASE_DN instead of the base entry alone |
| PORT | 1389 | LDAP Listener Port |
| LDAPS_PORT | 1636 | LDAPS Listener Port |
| BASE_DN | dc=example,dc=com | OpenDJ Base DN |
Expand Down
29 changes: 24 additions & 5 deletions opendj-packages/opendj-docker/bootstrap/setup.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
#!/usr/bin/env bash
# The contents of this file are subject to the terms of the Common Development and
# Distribution License (the License). You may not use this file except in compliance with the
# License.
#
# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
# specific language governing permission and limitations under the License.
#
# When distributing Covered Software, include this CDDL Header Notice in each file and include
# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
# Header, with the fields enclosed by brackets [] replaced by your own identifying
# information: "Portions copyright [year] [name of copyright owner]".
#
# Portions copyright 2026 3A Systems, LLC.

# Default setup script
#
# What the instance is made of - the server itself, the backend, the entries the backend was
# asked to hold - is left to fail this script, which is what run.sh reads to decide whether
# the container may report itself healthy. The optional schema and data LDIFs below keep the
# tolerance they were written with.

echo "Setting up default OpenDJ instance"

Expand Down Expand Up @@ -30,29 +49,29 @@ fi
--acceptLicense \
--no-prompt \
--noPropertiesFile \
$SETUP_ARGS
$SETUP_ARGS || exit 1

BACKEND_TYPE=${BACKEND_TYPE:-je}
BACKEND_DB_DIRECTORY=${BACKEND_DB_DIRECTORY:-db}
echo "creating backend: $BACKEND_TYPE db-directory: ${BACKEND_DB_DIRECTORY}"

/opt/opendj/bin/dsconfig create-backend -h localhost -p $ADMIN_PORT --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD" \
--backend-name=userRoot --type $BACKEND_TYPE --set base-dn:$BASE_DN --set "db-directory:$BACKEND_DB_DIRECTORY" \
--set enabled:true --no-prompt --trustAll
--set enabled:true --no-prompt --trustAll || exit 1

if [ "$ADD_BASE_ENTRY" = "--addBaseEntry" ]; then
BASE_TEMPLATE=$(mktemp)
if [ ! -z ${SAMPLE_DATA} ]; then
echo "generating sample data..."
/opt/opendj/bin/makeldif -o $BASE_TEMPLATE -c suffix="$BASE_DN" -c numusers=$SAMPLE_DATA /opt/opendj/template/config/MakeLDIF/example.template
/opt/opendj/bin/makeldif -o $BASE_TEMPLATE -c suffix="$BASE_DN" -c numusers=$SAMPLE_DATA /opt/opendj/template/config/MakeLDIF/example.template || exit 1
/opt/opendj/bin/import-ldif --ldifFile $BASE_TEMPLATE \
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD"
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD" || exit 1
else
echo "creating base entry..."
BASE_TEMPLATE=$(mktemp)
echo "branch: $BASE_DN" > $BASE_TEMPLATE
/opt/opendj/bin/import-ldif --templateFile $BASE_TEMPLATE \
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD"
--backendID=userRoot --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD" || exit 1
fi
rm $BASE_TEMPLATE
fi
Expand Down
36 changes: 33 additions & 3 deletions opendj-packages/opendj-docker/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@

cd /opt/opendj

# The health check probes the server only once this marker is there, so that "healthy"
# means the instance is bootstrapped rather than merely listening: setup starts the
# server in the middle of the bootstrap, before the backend holding BASE_DN has been
# created. Nothing below writes it unless the step it stands for reported success, so a
# bootstrap that failed leaves the container running to be looked at, but never healthy.
# It is kept outside ./data because it records what this container has done, not what
# the volume holds - and a restart of a container replays this script over the writable
# layer the previous run left behind, so it is cleared before anything else.
BOOTSTRAP_COMPLETE=${BOOTSTRAP_COMPLETE:-/opt/opendj/.bootstrap-complete}
rm -f "$BOOTSTRAP_COMPLETE"

#if default data folder exists do not change it
if [ ! -d ./db ]; then
echo "/opt/opendj/data" >/opt/opendj/instance.loc && \
Expand All @@ -31,7 +42,13 @@ fi

# Instance dir does exist? We start opendj without detach
if [ -d ./data/config ]; then
sh ./upgrade -n
# nothing is bootstrapped here, the instance is already there - but a half-migrated one
# is not ready to serve either, so the marker follows the upgrade
if sh ./upgrade -n; then
touch "$BOOTSTRAP_COMPLETE"
else
echo "Upgrade failed, this container will not report itself healthy"
fi
exec ./bin/start-ds --nodetach
exit
fi
Expand All @@ -46,11 +63,18 @@ export ROOT_PASSWORD=${ROOT_PASSWORD:-password}

BOOTSTRAP=${BOOTSTRAP:-/opt/opendj/bootstrap/setup.sh}
echo "Running $BOOTSTRAP"
sh "${BOOTSTRAP}"
BOOTSTRAPPED=true
if ! sh "${BOOTSTRAP}"; then
BOOTSTRAPPED=false
echo "$BOOTSTRAP failed, this container will not report itself healthy"
fi

# Check if OPENDJ_REPLICATION_TYPE var is set. If it is - replicate to that server
if [ -n "${MASTER_SERVER}" ] && [ -n "${OPENDJ_REPLICATION_TYPE}" ]; then
/opt/opendj/bootstrap/replicate.sh
if ! /opt/opendj/bootstrap/replicate.sh; then
BOOTSTRAPPED=false
echo "Replication setup failed, this container will not report itself healthy"
fi
fi

# Check if keystores are mounted as a volume, and if so
Expand All @@ -63,6 +87,12 @@ if [ -d "${SECRET_VOLUME}" ]; then
cp -f ${SECRET_VOLUME}/key* ${SECRET_VOLUME}/trust* ./data/config 2>/dev/null
fi

# Everything the instance was asked to be set up with - its backend, its base entry, its
# replication - is in place from here on, so the health check may start probing the server
if [ "$BOOTSTRAPPED" = true ]; then
touch "$BOOTSTRAP_COMPLETE"
fi

# Opendj is probably already started in detach mode at the install
if (bin/status -n | grep Started); then
echo "OpenDJ is started"
Expand Down
Loading