Clean & secure Premium Java 21 latest GA runtime on NiceOS Base — a purpose-built container OS.
3.1K
niceos/openjdk21 is a minimal OpenJDK 21 runtime built on NiceOS.Container 13 from the NiceOS openjdk21-jre RPM package.
It is intended for pre-built Java applications running in Docker, Podman, Kubernetes, and other OCI-compatible environments. Operating-system files come from NiceOS RPM packages; NiceSOFT runtime helpers and metadata are stored under /nicesoft.
This is a runtime image. Maven, Gradle, compilers, SSH, and package managers are not included in the final image.
docker.io/niceos/openjdk21:21.0.11-niceos13-r4
For production, pin the complete release tag or an image digest:
docker pull docker.io/niceos/openjdk21:21.0.11-niceos13-r4
openjdk21-jre RPM.FROM scratch.1001:1001./app./nicesoft./nicesoft/java._FILE variables./tmp./nicesoft NiceSOFT helpers and metadata
/nicesoft/java stable JAVA_HOME symlink
/nicesoft/bin/nicesoft-java-admin administrative CLI
/nicesoft/scripts/java entrypoint and runtime scripts
/app application working directory
/tmp temporary runtime data
/certificates recommended custom CA mount point
Default identity:
UID: 1001
GID: 1001
WORKDIR: /app
JAVA_HOME:/nicesoft/java
This is a native NiceOS.Container image. It does not copy the Bitnami filesystem or shell framework. Compatibility with a particular application image or Helm chart must be implemented and tested in the derived application image.
Show the Java version:
docker run --rm \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4
Run an executable JAR:
docker run --rm \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
Run with application arguments:
docker run --rm \
-p 8080:8080 \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar \
--server.port=8080 \
--spring.profiles.active=prod
Run a main class:
docker run --rm \
-v "$PWD/application:/app:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-cp '/app:/app/*' com.example.Main arg1 arg2
Run a command directly:
docker run --rm \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
/bin/sh -c 'java -version && id'
r4 command behaviorWhen the first argument starts with -, the entrypoint runs:
/nicesoft/java/bin/java <generated JVM defaults> <JAVA_OPTS> <arguments>
When the first argument is exactly java, the command is executed as supplied and generated NiceOS JVM defaults are not inserted. Add all required JVM options explicitly in that form.
Release r4 defines CMD ["java", "-version"]. Therefore, for reliable application startup, use CMD ["-jar", "/app/app.jar"] in a derived image or pass -jar /app/app.jar explicitly.
FROM docker.io/niceos/openjdk21:21.0.11-niceos13-r4
COPY --chown=1001:1001 app.jar /app/app.jar
EXPOSE 8080
CMD ["-jar", "/app/app.jar"]
Build and run:
docker build -t example/my-java-app:1.0.0 .
docker run --rm -p 8080:8080 example/my-java-app:1.0.0
Build the application in a separate stage or CI environment. Copy only runtime artifacts into the final image.
Before starting the selected command, the entrypoint:
_FILE variables./app, and writable JAVA_TMP_DIR.Without positional arguments, the implemented application selection order is:
JAVA_COMMANDJAVA_MAIN_JAR/app/app.jar, when presentJAVA_MAIN_CLASSjava -version| Variable | Default | Purpose |
|---|---|---|
NICESOFT_APP_NAME | NiceOS OpenJDK 21 Runtime | Name shown in runtime messages. |
NICESOFT_BANNER | true | Enable startup banner. |
NICESOFT_COLOR | auto | auto, always, or never. |
NICESOFT_LOG_ENABLED | true | Enable runtime logs. |
NICESOFT_LOG_LEVEL | info | trace, debug, info, warn, error, off. |
NICESOFT_LOG_FORMAT | text | text or json. |
NICESOFT_LOG_TIMESTAMP | true | Add UTC timestamps to formatted Java logs. |
NICESOFT_LOG_JAVA | true | Pipe Java stdout/stderr through nicesoft-log. |
NICESOFT_DEBUG | false | Enable shell tracing and debug logs. Do not use with secrets. |
Legacy aliases NICEOS_BANNER, NICEOS_COLOR, NICEOS_LOG_LEVEL, and NICEOS_LOG_FORMAT are accepted when the corresponding NICESOFT_* variable is not set.
| Variable | Default | Purpose |
|---|---|---|
JAVA_HOME | /nicesoft/java | Stable Java runtime path. |
JAVA_APP_DIR | /app | Application directory. |
JAVA_TMP_DIR | /tmp | Writable Java temporary directory. |
JAVA_MAIN_JAR | unset | Executable JAR for environment-driven startup. |
JAVA_MAIN_CLASS | unset | Main class for environment-driven startup. |
JAVA_CLASSPATH | /app:/app/* | Classpath for JAVA_MAIN_CLASS. |
JAVA_COMMAND | unset | Complete shell command for environment-driven startup. |
JAVA_PRESTART_SCRIPT | unset | Trusted shell file sourced before startup. |
JAVA_OPTS | unset | Additional JVM options. |
JAVA_ARGS | unset | Application arguments. |
JAVA_TOOL_OPTIONS | unset | Standard JVM environment variable. |
JDK_JAVA_OPTIONS | unset | Standard JDK launcher environment variable. |
| Variable | Default | Result |
|---|---|---|
JAVA_ENABLE_CONTAINER_SUPPORT | true | -XX:+UseContainerSupport |
JAVA_MAX_RAM_PERCENTAGE | 75 | -XX:MaxRAMPercentage=<value> |
JAVA_INITIAL_RAM_PERCENTAGE | unset | -XX:InitialRAMPercentage=<value> |
JAVA_MIN_RAM_PERCENTAGE | unset | -XX:MinRAMPercentage=<value> |
JAVA_ENABLE_HEADLESS | true | -Djava.awt.headless=true |
JAVA_FILE_ENCODING | UTF-8 | -Dfile.encoding=UTF-8 |
JAVA_USER_TIMEZONE | UTC | -Duser.timezone=UTC |
JAVA_SECURITY_EGD | file:/dev/urandom | -Djava.security.egd=... |
Example:
docker run --rm \
--memory=1g \
-e JAVA_MAX_RAM_PERCENTAGE=65 \
-e JAVA_GC=g1 \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-XshowSettings:vm -version
JAVA_MAX_RAM_PERCENTAGE only controls the Java heap. Keep headroom for metaspace, thread stacks, direct buffers, native libraries, and operating-system overhead.
Set JAVA_GC to:
| Value | JVM option |
|---|---|
auto | JVM default |
g1, g1gc | -XX:+UseG1GC |
zgc, z | -XX:+UseZGC |
shenandoah | -XX:+UseShenandoahGC |
serial | -XX:+UseSerialGC |
parallel | -XX:+UseParallelGC |
none, disabled, off | no GC option added |
Supported _FILE pairs:
JAVA_OPTS / JAVA_OPTS_FILE
JAVA_TOOL_OPTIONS / JAVA_TOOL_OPTIONS_FILE
JDK_JAVA_OPTIONS / JDK_JAVA_OPTIONS_FILE
JAVA_ARGS / JAVA_ARGS_FILE
JAVA_MAIN_JAR / JAVA_MAIN_JAR_FILE
JAVA_MAIN_CLASS / JAVA_MAIN_CLASS_FILE
JAVA_COMMAND / JAVA_COMMAND_FILE
JAVA_TRUSTSTORE_PATH / JAVA_TRUSTSTORE_PATH_FILE
JAVA_TRUSTSTORE_PASSWORD / JAVA_TRUSTSTORE_PASSWORD_FILE
NICESOFT_JAVA_TRUSTSTORE_PASSWORD / NICESOFT_JAVA_TRUSTSTORE_PASSWORD_FILE
Do not set a direct variable and its _FILE counterpart together. The container exits when both are set or when the referenced file is unreadable.
docker run --rm \
-v "$PWD/password:/run/secrets/password:ro" \
-e JAVA_TRUSTSTORE_PASSWORD_FILE=/run/secrets/password \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4
NICESOFT_DEBUG=true enables shell tracing in r4 and may expose command arguments or environment values. Do not enable it in production when secrets are present.
Mount .crt, .cer, or .pem files under /certificates:
docker run --rm \
-v "$PWD/company-root-ca.crt:/certificates/company-root-ca.crt:ro" \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
With NICESOFT_ENABLE_CERT_IMPORT=auto, the runtime copies the system Java truststore to a writable target under /tmp, imports mounted certificates, and adds the matching javax.net.ssl.trustStore properties.
| Variable | Default |
|---|---|
NICESOFT_ENABLE_CERT_IMPORT | auto |
NICESOFT_CA_CERTS_DIR | /certificates |
NICESOFT_JAVA_TRUSTSTORE | /tmp/nicesoft-java-cacerts |
NICESOFT_JAVA_TRUSTSTORE_PASSWORD | changeit |
Inspect the effective truststore:
docker run --rm \
-v "$PWD/ca:/certificates:ro" \
--entrypoint nicesoft-java-admin \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
truststore
Enable Java Flight Recorder:
docker run --rm \
-e JAVA_ENABLE_JFR=true \
-e JAVA_JFR_FILENAME=/tmp/application.jfr \
-e JAVA_JFR_SETTINGS=profile \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
JFR variables: JAVA_ENABLE_JFR, JAVA_JFR_FILENAME, JAVA_JFR_SETTINGS, JAVA_JFR_DELAY, and JAVA_JFR_DURATION.
Use a pre-generated AppCDS archive:
docker run --rm \
-e JAVA_ENABLE_APP_CDS=true \
-e JAVA_APP_CDS_ARCHIVE=/app/app-cds.jsa \
-v "$PWD/app.jar:/app/app.jar:ro" \
-v "$PWD/app-cds.jsa:/app/app-cds.jsa:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
JAVA_ENABLE_APP_CDS=auto uses the configured archive only when it exists.
Runtime messages use NICESOFT_LOG_LEVEL, NICESOFT_LOG_FORMAT, and related variables.
Release r4 defaults to NICESOFT_LOG_JAVA=true, which transforms Java stdout/stderr through nicesoft-log. Disable it when the application already emits JSON or requires exact stdout/stderr:
docker run --rm \
-e NICESOFT_LOG_JAVA=false \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
For most production applications with their own logging format, NICESOFT_LOG_JAVA=false is recommended.
The built-in helper executes JAVA_HEALTH_COMMAND; its default is java -version.
This verifies the Java runtime, not application health or readiness. Derived production images should replace it with an application-specific probe.
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD ["/bin/sh", "-c", "exec /app/healthcheck.sh"]
Values none, disabled, off, or false make the helper return success without running a check.
docker run --rm \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=256m \
-e NICESOFT_LOG_JAVA=false \
-v "$PWD/app.jar:/app/app.jar:ro" \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
-jar /app/app.jar
Mount writable volumes for every path used by the application for mutable or persistent data. The base runtime requires a writable JAVA_TMP_DIR.
services:
app:
image: docker.io/niceos/openjdk21:21.0.11-niceos13-r4
user: "1001:1001"
read_only: true
command: ["-jar", "/app/app.jar"]
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=256m
environment:
JAVA_MAX_RAM_PERCENTAGE: "65"
JAVA_USER_TIMEZONE: Europe/Amsterdam
NICESOFT_LOG_JAVA: "false"
volumes:
- ./app.jar:/app/app.jar:ro
ports:
- "8080:8080"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
spec:
replicas: 1
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
containers:
- name: app
image: docker.io/niceos/openjdk21:21.0.11-niceos13-r4
args: ["-jar", "/app/app.jar"]
env:
- name: JAVA_MAX_RAM_PERCENTAGE
value: "65"
- name: NICESOFT_LOG_JAVA
value: "false"
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: app
mountPath: /app
readOnly: true
- name: tmp
mountPath: /tmp
volumes:
- name: app
configMap:
name: java-app-files
- name: tmp
emptyDir: {}
For real applications, use an application image containing the JAR instead of storing a large artifact in a ConfigMap. Configure application-specific startup, readiness, and liveness probes.
The image provides:
/nicesoft/bin/nicesoft-java-admin
/nicesoft/bin/niceos-java-admin
Common commands:
docker run --rm --entrypoint nicesoft-java-admin IMAGE inspect
docker run --rm --entrypoint nicesoft-java-admin IMAGE opts
docker run --rm --entrypoint nicesoft-java-admin IMAGE truststore
docker run --rm --entrypoint nicesoft-java-admin IMAGE version
Replace IMAGE with a valid tag such as docker.io/niceos/openjdk21:21.0.11-niceos13-r4.
The canonical release tag is:
<java-version>-niceos<niceos-stream>-r<revision>
Example:
21.0.11-niceos13-r4
Components:
21.0.11: OpenJDK runtime version.niceos13: NiceOS.Container base stream.r4: NiceOS image revision for that exact Java version and base stream.| Tag | Type | Meaning |
|---|---|---|
21.0.11-niceos13-r4 | immutable | Exact release. Recommended for production. |
21.0.11-niceos13 | moving | Latest revision for this Java version and NiceOS stream. |
21.0.11 | moving | Latest approved image for this Java patch version. |
21 | moving | Latest supported OpenJDK 21 release. |
latest | moving | Latest default release in this repository. |
Moving tags are convenience aliases and may change without modifying their tag name.
Use one of these:
21.0.11-niceos13-r4
<registry>/<image>@sha256:<digest>
Do not rely on latest, 21, or other moving aliases for reproducible production deployments.
The rN revision increases when the Java version and NiceOS stream stay unchanged but the image must be rebuilt because of:
Examples:
21.0.11-niceos13-r4 -> 21.0.11-niceos13-r5
21.0.11-niceos13-r5 -> 21.0.12-niceos13-r1
21.0.12-niceos13-r3 -> 21.0.12-niceos14-r1
A new Java version or a new NiceOS stream resets the image revision to r1.
A complete release tag must never be overwritten. Once published, 21.0.11-niceos13-r4 must always resolve to the same image content. Corrections require a new rN tag.
Old immutable tags remain available for rollback and reproducible deployments, subject to registry retention and security policy.
NiceOS OpenJDK images follow the supported OpenJDK 21 line and the active NiceOS.Container release stream.
The following are checked at least weekly:
Critical security updates may be released outside the normal schedule.
When a new supported OpenJDK 21 patch or security release is approved:
r1;A Java version change produces a new versioned tag; the previous immutable release is not modified.
When Java stays unchanged but the NiceOS base, RPM dependencies, scripts, metadata, or container contract require an update, the image revision increases:
21.0.11-niceos13-r4 -> 21.0.11-niceos13-r5
A new NiceOS base stream produces a new tag and resets the revision:
21.0.11-niceos13-r5 -> 21.0.11-niceos14-r1
Moving aliases are updated only after the candidate image passes required build and acceptance checks. Promotion order should be:
21 and latest only when the release is the approved default.Rollback is performed by redeploying a previous immutable tag or digest. Moving aliases are not rollback points.
1001:1001 by default.readOnlyRootFilesystem: true with writable /tmp.allowPrivilegeEscalation: false, dropped capabilities, and RuntimeDefault seccomp._FILE variables.Derived applications remain responsible for their own dependencies, writable paths, network exposure, probes, and application-level security.
r4 limitationsCMD ["java", "-version"] means plain docker run IMAGE does not use environment-driven application selection.java bypasses generated NiceOS JVM defaults.NICESOFT_LOG_JAVA=true transforms application stdout/stderr and keeps the shell wrapper involved in process handling.java -version; it is not an application readiness check.NICESOFT_DEBUG=true enables shell tracing and may expose sensitive values.1001:1001.Build:
docker build \
--build-arg IMAGE_VERSION=21.0.11-niceos13-r4 \
--build-arg VCS_REF="$(git rev-parse --short HEAD)" \
--build-arg BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-t docker.io/niceos/openjdk21:21.0.11-niceos13-r4 .
Run repository checks:
./tests/release-check.sh
docker build -t niceos/openjdk21:test .
IMAGE=niceos/openjdk21:test ./tests/acceptance.sh
The image publishes standard OCI labels, including title, description, version, source, revision, creation time, vendor, licenses, base image, and documentation URL.
Inspect labels:
docker image inspect \
docker.io/niceos/openjdk21:21.0.11-niceos13-r4 \
--format '{{json .Config.Labels}}'
[email protected]When reporting a problem, include the complete image tag or digest, architecture, container runtime, startup command, relevant environment variables with secrets removed, and logs.
OpenJDK is distributed under GPL-2.0-only WITH Classpath-exception-2.0. NiceSOFT helper scripts and supporting files in this repository are licensed under Apache License 2.0 unless stated otherwise.
Content type
Image
Digest
sha256:19cc986fe…
Size
238.4 MB
Last updated
about 2 months ago
docker pull niceos/openjdk21