Install with Docker
Eliya publishes multi-arch OCI images (amd64 + arm64) to GitHub Container Registry. Use them as a base for your Java application containers, as a builder image in multi-stage Dockerfiles, or as a diagnostic image for inspecting JVMs running in other containers.
Pull the image
Available tags
Pick the tag based on your operational policy:
-
25-ltsis a moving tag: Asymm pushes a new image to it on each quarterly CPU. A deployment-time pull (CI/CD redeploy, Kubernetes rolling update withimagePullPolicy: Always, or explicitdocker pull) is required to pick up the new image. With the defaultimagePullPolicy: IfNotPresent, a pod that already has the old image will keep running it indefinitely. To ensure each pod restart picks up the latest CPU, setimagePullPolicy: Alwayson the container spec, or pin to a specific25.0.3tag and bump explicitly on each CPU. -
25.0.3for environments that pin to a specific version; the tag is immutable, sodocker pullreturns the same image every time. -
-slim(smaller Debian base),-jre, and-jre-distrolessvariants ship in a post-GA refresh (Wave 7, Q4 2026); today the full-JDK multi-arch25-lts/25.0.3image is the published tag. - Full (non-slim) variants when your application uses AWT or Java2D for server-side rendering (PDF generation, chart images, font-metric calculations): the full Debian base provides the native
fontconfig,freetype, and X11 libraries those paths call into. Also the right choice for diagnostic sidecar containers (see Production diagnostic patterns).
Eliya will ship images on two orthogonal axes: base image (Debian full vs slim vs distroless) and Java content (full JDK vs Eliya JRE). First GA publishes the full-JDK multi-arch image (25-lts / 25.0.3, plus per-arch -amd64 / -arm64); the -slim, -jre, and -jre-distroless variants ship in a post-GA refresh (Wave 7, Q4 2026).
| Tag | Base image | Java content | Size (approx) | When to use | Status |
|---|---|---|---|---|---|
25-lts / 25.0.3 | debian:12 | Full JDK | ~550 MB compressed (~1.9 GB on disk) | Server-side AWT/Java2D rendering; multi-stage builder images; diagnostic sidecars needing jcmd/jmap | Available |
25-lts-slim / 25.0.3-slim | debian:12-slim | Full JDK | TBD | Headless apps that still need javac/jlink at runtime (rare); slim-base CI runners | Coming (post-GA refresh) |
25-lts-jre / 25.0.3-jre | debian:12-slim | Eliya JRE | ~110 MB | Recommended default for application containers: production headless servers | Coming Q4 2026 (Wave 7) |
25-lts-jre-distroless / 25.0.3-jre-distroless | gcr.io/distroless/java-base:nonroot | Eliya JRE | ~80 MB | Hardened production: no shell, no package manager, minimal CVE attack surface. For compliance-conscious deployments. | Coming Q4 2026 (Wave 7) |
The Eliya JRE is jlinked from the JDK at build time per JEP 220 with the Java SE aggregator (full standard library) + production-server essentials (jdk.unsupported, jdk.crypto.cryptoki, jdk.jfr, jdk.management.agent, jdk.attach, jdk.naming.dns, jdk.localedata, jdk.zipfs). Compatible with any standard-Java-SE application; the Production-profile observability (JFR + JMX) works on the JRE image, not just the JDK.
JavaFX is not bundled. If your application uses JavaFX, add OpenJFX as an explicit Maven/Gradle dependency or use a JDK distribution that bundles it (e.g. BellSoft Liberica Full). Eliya stays aligned with upstream OpenJDK 25's module set; JavaFX has been a separate project since JDK 11.
Why Debian?
Eliya's Docker base image uses Debian 12 because of JDK runtime correctness, not because of toolchain richness.
glibc vs musl. The JDK has known compatibility issues on musl libc (used by Alpine): DNS resolution edge cases, thread stack size defaults that differ from glibc, some JNI native libraries that fail to load without glibc symbols, and performance characteristics that disadvantage allocation-heavy Java workloads. Upstream OpenJDK treats the musl port (JEP 386) as a separate platform with its own caveats, not as equivalent to glibc Linux. For a JDK distribution positioned for compliance-conscious production, the glibc base is the safer default.
Per-arch glibc floor. Eliya pins glibc per architecture to match upstream OpenJDK's reference build: x86_64 ≥ glibc 2.12 (Oracle Linux 6.4 sysroot) and aarch64 ≥ glibc 2.17 (Oracle Linux 7.6 sysroot). The x86_64 floor is deliberately wider than Temurin's unified 2.17, so an x86_64 Eliya container runs on every glibc ≥ 2.12 host, including older RHEL / CentOS / SLES bases when corporate policy requires them. Full reach matrix is on the Linux install guide.
Predictable operations. Most Linux production deployments are Debian/Ubuntu or RHEL-derived. Operators inspecting an Eliya container find the same ps, top, kill, bash, and package management conventions they use on host systems: no busybox flag differences or musl-specific surprises. This matters less for routine work (JDK tools like jcmd, jstack, and the asymm CLI come from the JDK and work regardless of base image) and more for the small fraction of incidents that require below-the-JVM investigation: strace, lsof, gdb, and the like. For workloads that need AWT/Java2D rendering on the slim image, install the runtime libs explicitly: apt-get install -y fontconfig libfreetype6.
Predictable lifecycle. Debian 12 (bookworm) enters its Long Term Support phase on 2026-06-10 and receives LTS security updates through 2028-06-30 for amd64 and arm64, both architectures Eliya targets. The Debian LTS team continues security updates during this window. ELTS (Extended LTS) is a commercial offering from Freexian, not an official Debian project, and is not load-bearing for Eliya's support story. Eliya tracks Debian's release cycle and will migrate base images to Debian 13 (trixie) when it stabilises.
An Alpine variant is not planned. A distroless Eliya variant ships Wave 7 (target Q4 2026) per the published tag matrix above; the details and trade-offs are below.
Why no Alpine, and what about distroless?
Distroless is a separate question from Debian vs Alpine. A distroless image contains only the JDK and its runtime dependencies: no shell, no package manager, no diagnostic utilities. The image starts from an effectively empty filesystem (FROM scratch) and adds only the binaries and libraries the application strictly needs. Like all containers, distroless images share the host's Linux kernel; the "minimal" refers to the userspace filesystem, not the kernel.
Distroless reduces attack surface significantly: an attacker who achieves remote code execution in the container cannot drop into a shell, install tools, or perform reconnaissance with standard utilities. For some compliance frameworks, this matters.
But distroless is not universal. The standard distroless Java pattern assumes the application:
- Is self-contained in a JAR or directory tree.
- Does not shell out to external commands (no
ProcessBuildertogit,imagemagick, etc.). - Does not need fontconfig or imaging libraries at runtime.
- Does not need locale support beyond UTF-8.
- Does not need custom CA certificate handling beyond what the JDK provides.
- Does not require in-container diagnostic capability.
Many modern Java microservices fit these constraints; many enterprise Java applications do not. Operators adopting distroless typically pair it with the sidecar pattern (where diagnostic tooling lives in a separate container) and validate their specific application thoroughly before production rollout.
A distroless Eliya variant ships Wave 7 (target Q4 2026), after the first signed Linux GA lands on the storefront repo. Beyond a single Dockerfile, it requires supply-chain control over the included libraries, validation against representative Java application classes, and documentation of application-fit constraints. If your environment requires this level of minimisation (or a Red Hat UBI variant for procurement), sign up at downloads; your demand signal helps Wave 7 prioritisation.
Use as a base image
The common pattern is to use the Eliya image as the runtime base for your application container. The example below shows a minimal Dockerfile that runs a fat JAR with the EliyaProfile=Production profile active by default:
FROM ghcr.io/asymmsystems/eliya-jdk:25-lts
COPY target/myapp.jar /app/myapp.jar
WORKDIR /app
ENV JAVA_TOOL_OPTIONS="-XX:EliyaProfile=Production"
ENTRYPOINT ["java", "-jar", "myapp.jar"] The image sets JAVA_HOME and puts $JAVA_HOME/bin on the PATH, so java, javac, jcmd, and the asymm CLI all resolve directly. JAVA_TOOL_OPTIONS is read automatically by the JVM, so the entrypoint is a clean java -jar with no shell wrapper.
Why direct exec (not sh -c)
The entrypoint uses direct exec (ENTRYPOINT ["java", "-jar", "myapp.jar"]) rather than wrapping in a shell (ENTRYPOINT ["sh", "-c", "java -jar myapp.jar"]). This matters for forensic data capture during orchestrated shutdowns.
When Kubernetes or Docker stops a container, it sends SIGTERM to PID 1 (the process the container was started with). The JVM is designed to handle SIGTERM cleanly: it triggers shutdown hooks, which include flushing in-memory JFR buffers to disk and writing a final heap dump on exit if configured.
If you wrap the entrypoint in sh -c, the shell becomes PID 1 instead of the JVM. The shell receives SIGTERM but doesn't propagate it to the Java process. The JVM gets killed by SIGKILL after the grace period, too late for the shutdown hooks to fire. Result: the JFR events captured immediately before the shutdown, precisely the data most likely to explain why the orchestrator killed the container, never reach disk. Heap-dump-on-exit (if configured) also doesn't fire.
Direct exec keeps the JVM as PID 1. SIGTERM reaches the JVM. Shutdown hooks run. JFR data flushes to disk. The forensic evidence survives the restart.
This is why EliyaProfile=Production sets dumponexit=true on the JFR recording: the design assumes the JVM will receive its shutdown signals cleanly. The entrypoint pattern matters.
The asymm CLI inside the container
Every Eliya image bundles the asymm CLI on $PATH. Phase 1 ships three commands (asymm, asymm --version, asymm --help) documented in the asymm CLI reference: the same surface, same behaviour, inside or outside a container.
Phase 2 will add diagnostic-tooling subcommands that wrap Eclipse MAT headless and async-profiler (both Phase 2 bundled tools), and Phase 3 will add Asymm Forensics subcommands. Three operational patterns for running diagnostics against a containerised JVM are documented below under Production diagnostic patterns.
Multi-stage builds
For cases that need a JDK at build time (Maven, Gradle, javac) but only a JRE at runtime, use Eliya's full image as the builder stage and the slim image as the runtime stage:
# Stage 1: build the application
FROM ghcr.io/asymmsystems/eliya-jdk:25-lts AS builder
WORKDIR /build
COPY pom.xml .
COPY mvnw .
COPY .mvn ./.mvn
COPY src ./src
RUN chmod +x mvnw && ./mvnw clean package -DskipTests
# Stage 2: run the application
FROM ghcr.io/asymmsystems/eliya-jdk:25-lts
COPY --from=builder /build/target/myapp.jar /app/myapp.jar
WORKDIR /app
ENV JAVA_TOOL_OPTIONS="-XX:EliyaProfile=Production"
ENTRYPOINT ["java", "-jar", "myapp.jar"] The final image contains the Eliya runtime plus your application JAR. Build artifacts, Maven cache, and source files don't ship to runtime. The chmod +x mvnw step protects against the Maven wrapper losing its executable bit on cross-platform checkouts (typically Windows-originated commits).
If you use jlink to produce a minimal custom runtime image, the Eliya image is a suitable runtime base: jlink output works the same way it does with upstream OpenJDK.
Mount diagnostic paths
By default, EliyaProfile=Production writes diagnostic artifacts (JFR recordings, heap dumps, GC logs, crash logs) to /var/log/eliya/ inside the container. For these to survive container restarts and be inspectable from the host, mount the path as a volume.
Docker:
docker-compose:
services:
my-app:
image: my-app:latest
environment:
ELIYA_SERVICE_NAME: my-app
JAVA_TOOL_OPTIONS: "-XX:EliyaProfile=Production"
volumes:
- eliya-diagnostics:/var/log/eliya
volumes:
eliya-diagnostics: By default, Docker stores the named volume in /var/lib/docker/volumes/. For host-visible paths, use a bind mount instead:
volumes:
- ./eliya-diagnostics:/var/log/eliya Kubernetes:
apiVersion: v1
kind: Pod
spec:
containers:
- name: my-app
image: my-app:latest
env:
- name: ELIYA_SERVICE_NAME
value: my-app
volumeMounts:
- name: eliya-diagnostics
mountPath: /var/log/eliya
volumes:
- name: eliya-diagnostics
persistentVolumeClaim:
claimName: eliya-diagnostics-pvc Diagnostic paths use a three-level layout that gives both service grouping and per-replica attribution by default:
/var/log/eliya/${service_name}/${replica_name}/${category}/ Service name resolution: ELIYA_SERVICE_NAME env var → -Deliya.service.name= system property → HOSTNAME → literal default.
Replica name resolution: ELIYA_REPLICA_NAME env var → -Deliya.replica.name= system property → HOSTNAME → suppressed when equal to service name.
In Kubernetes, the orchestrator-provided HOSTNAME (pod name) becomes the replica subdirectory automatically. A deployment with three replicas of billing-service produces:
/var/log/eliya/billing-service/billing-service-7d4b9c-xk29p/jfr/
/var/log/eliya/billing-service/billing-service-7d4b9c-mk44q/jfr/
/var/log/eliya/billing-service/billing-service-7d4b9c-zr88l/jfr/ Each pod gets its own subdirectory. Per-replica attribution is filesystem-encoded: auditors and engineers can list /var/log/eliya/billing-service/ to see the full replica history; each subdirectory's name identifies the pod that produced its contents. With docker compose up --scale my-app=3, each container instance receives a distinct HOSTNAME from the Docker runtime, so the same per-replica attribution applies.
For multiple distinct services sharing the same volume, each service gets its own top-level subdirectory: /var/log/eliya/billing-service/, /var/log/eliya/order-service/, etc.
Replica suppression. When the resolved replica name equals the resolved service name (e.g. bare-metal multi-JVM hosts where HOSTNAME matches ELIYA_SERVICE_NAME for each systemd service, or single-JVM hosts where service falls through to HOSTNAME), the replica level is suppressed and paths collapse to two levels (/var/log/eliya/billing-service/jfr/). This avoids redundant ${service}/${service}/ nesting on hosts where the hostname carries no per-replica information.
For deployments wanting deterministic replica names across pod restarts (uncommon, but useful for stateful workloads), set ELIYA_REPLICA_NAME explicitly; in Kubernetes, valueFrom: fieldRef: fieldPath: metadata.name works.
For full path strategy documentation including all resolution scenarios, see flags reference Diagnostic paths section.
Production diagnostic patterns
Eliya supports three operational patterns for diagnosing running JVMs in containerised environments. Pick the one that matches your security posture and operational tooling.
For environments running APM alongside Eliya, the patterns below complement (rather than replace) APM dashboards. APM tools capture distributed traces and real-time metrics; Eliya captures forensic artefacts on disk that APM structurally cannot produce. See JVM forensics vs APM for the architectural distinction.
1. Interactive exec: development and small-scale production
The simplest pattern: enter the running container, run diagnostic commands directly. Suitable for development, staging, and production environments without strict app-container minimisation requirements.
Docker:
Kubernetes:
Works because the Eliya image includes the asymm CLI and standard JDK tooling (jcmd, jstack, jmap, jfr) on every container. The trade-off: the application container ships these tools as part of its runtime, increasing the image surface area.
2. Ephemeral diagnostic containers: recommended for production incident response
For Kubernetes 1.23+ clusters (the typical production cluster as of 2024+), the right pattern for occasional diagnostic access is ephemeral containers: on-demand diagnostic containers injected into a running pod for the duration of an investigation, then removed. This avoids the cost of an always-running diagnostic sidecar while preserving the security posture benefit (the app container ships no diagnostic tooling).
When an incident occurs, inject an Eliya diagnostic container into the target pod:
--target=app shares the PID namespace with the named container, so the ephemeral container can see and inspect the application's JVM via standard JDK tools. Inside the ephemeral container, find the JVM PID and run diagnostic commands:
When you exit, the ephemeral container is removed; the original pod is unchanged and no restart is required. The diagnostic session shows up in the pod's event timeline with a timestamp, giving a clean audit trail.
Requirements:
- Kubernetes 1.23+ (ephemeral containers reached stable in 1.25).
- RBAC permission for the
pods/ephemeralcontainersresource. - The Eliya image must be reachable from the cluster, typically pre-cached on nodes via image-pull policy or pre-pulled by a DaemonSet.
Benefits over an always-on sidecar: zero baseline resource cost (no idle container consuming memory per pod), no deployment-manifest changes, human-initiated diagnostic access with auditable creation events. Trade-off: requires Kubernetes 1.23+ and the appropriate RBAC; clusters that don't support ephemeral containers fall back to the always-on sidecar pattern below.
3. Always-on diagnostic sidecar: for scheduled tasks or restricted clusters
The always-on sidecar pattern runs a diagnostic Eliya container alongside each application pod for the lifetime of the pod. Prefer the ephemeral-containers pattern above for incident-driven diagnostics; reach for the always-on sidecar when:
- Your cluster doesn't support ephemeral containers (Kubernetes <1.23 or policy restrictions).
- You need scheduled diagnostic tasks: periodic heap dumps, JFR rotation, continuous analysis on a cron schedule.
- Your operational model requires pre-provisioned diagnostic surfaces rather than ad-hoc engineer access (sealed compliance environments, multi-tenant production where
kubectl debugRBAC is restricted).
Resource cost: ~40 MB memory for the idle JVM (plus container base-image overhead) and negligible CPU per pod for an idle Eliya sidecar. A service with 10 replicas pays roughly half a gigabyte always-on for occasional diagnostic capability. For incident-driven diagnostics in clusters that support ephemeral containers, the ephemeral pattern is cheaper and cleaner.
The sidecar uses the full Eliya image (25-lts), the only published image today. Its fontconfig and freetype libraries are needed when Phase 2 diagnostic tools generate visual reports: flame graphs from async-profiler, leak-suspects HTML from Eclipse MAT, and JFR rendering from headless analysis. A smaller -slim sidecar base (Wave 7) will suit Phase 1 sidecars running only jcmd and jstack; the full image future-proofs the deployment as the bundled tooling expands in Phase 2.
Example Kubernetes pod spec:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
shareProcessNamespace: true
containers:
- name: app
image: my-app:latest
env:
- name: ELIYA_SERVICE_NAME
value: my-app
- name: JAVA_TOOL_OPTIONS
value: "-XX:EliyaProfile=Production"
volumeMounts:
- name: eliya-diagnostics
mountPath: /var/log/eliya
- name: eliya-sidecar
image: ghcr.io/asymmsystems/eliya-jdk:25-lts
command: ["sleep", "infinity"]
volumeMounts:
- name: eliya-diagnostics
mountPath: /var/log/eliya
volumes:
- name: eliya-diagnostics
emptyDir: {} The sidecar container does nothing by default. Operators exec into the sidecar to run diagnostic commands against the shared volume or the live application JVM:
With shareProcessNamespace: true, inspect the live JVM and capture artefacts:
Copy a captured artifact out for offline analysis:
About shareProcessNamespace: true. By default in Kubernetes, each container in a pod has its own PID namespace: the sidecar's ps aux sees only the sidecar's own processes (the sleep infinity), not the application JVM in the other container. With shareProcessNamespace: true set at the pod level, all containers in the pod share one PID namespace; the sidecar can now see the JVM and target it with jcmd <jvm-pid>. Find the JVM in the shared namespace with pgrep -f java first; under shared-namespace, the JVM is not PID 1 (the sidecar's sleep process or whichever container started first is PID 1).
| Without shareProcessNamespace (default) | With shareProcessNamespace: true | |
|---|---|---|
Sidecar ps aux | Sees only sidecar's own processes | Sees app's JVM in the listing |
jcmd <pid> VM.flags against app's JVM | Cannot target the JVM | Works |
jstack / jmap against app's JVM | Not possible | Works |
| Sidecar usefulness | Post-incident artefact analysis on the shared volume only | Live JVM inspection + artefact analysis |
| Process isolation between containers | Strong | Weakened (containers can see each other's processes) |
The trade-off is intentional for diagnostic sidecars (the whole point of the sidecar is to inspect the app's JVM), but it's worth understanding that the trust boundary has widened. Without shareProcessNamespace, the sidecar is still useful for offline analysis of heap dumps, JFR recordings, and GC logs that landed on the shared volume; it just can't talk to the live JVM.
Use the always-on sidecar pattern when its niche fits: scheduled diagnostic tasks (periodic heap dumps, JFR rotation, custom analysis scripts) and sealed compliance environments where ephemeral containers are disabled by policy. For ad-hoc incident response in clusters that support it, prefer ephemeral containers above.
Phase 1 vs Phase 2 in this pattern. Today, the sidecar runs standard JDK utilities (jcmd, jstack, jmap) plus the asymm launcher for version and metadata. Heap analysis on captured dumps happens offline using Eclipse MAT or similar tools. Phase 2 will bundle Eclipse MAT (headless) and async-profiler in the Eliya image, with wrapping subcommands documented in the asymm CLI reference. The sidecar pattern does not change between phases: the same pod spec works; the available diagnostic commands inside the sidecar expand as Phase 2 ships.
Wave 7 (Q4 2026) with distroless app container. When the distroless Eliya variant ships (Wave 7, target Q4 2026), this pattern lets you split the two containers' image sources:
containers:
- name: app
image: ghcr.io/asymmsystems/eliya-jdk:25-lts-jre-distroless # Wave 7 (Q4 2026)
# no shell, no diagnostic tools, just runs the JVM
- name: eliya-sidecar
image: ghcr.io/asymmsystems/eliya-jdk:25-lts # full diagnostic toolchain
# unchanged The distroless app container has no diagnostic surface area; all diagnostics happen in the parallel Debian-based sidecar. In Phase 1, both containers use the same Debian-based image (with the slim variant for the app, full for the sidecar).
4. JMX over secure channel: legacy enterprise
Some traditional deployments expose the JVM's Management Extensions (JMX) over a secure port, allowing remote inspection from tools like VisualVM, JConsole, or JDK Mission Control (JMC) on engineer workstations. Some compliance frameworks specifically require JMX-style remote management endpoints for audit and inventory purposes.
Eliya supports JMX through standard upstream OpenJDK mechanisms, no Eliya-specific configuration required. Enable JMX in a containerised deployment by setting the standard flags in JAVA_TOOL_OPTIONS:
ENV JAVA_TOOL_OPTIONS="\
-XX:EliyaProfile=Production \
-Dcom.sun.management.jmxremote.port=9010 \
-Dcom.sun.management.jmxremote.rmi.port=9010 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.password.file=/etc/jmx/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=/etc/jmx/jmxremote.access \
-Dcom.sun.management.jmxremote.ssl=true \
-Dcom.sun.management.jmxremote.ssl.config.file=/etc/jmx/jmxssl.properties \
-Djava.rmi.server.hostname=<external-hostname>"
EXPOSE 9010 The jmxssl.properties file contains standard Java SSL system properties (javax.net.ssl.keyStore, javax.net.ssl.keyStorePassword, javax.net.ssl.trustStore, etc.). It's a Java configuration file, not an Eliya file; refer to Oracle's JMX documentation for the full format.
Critical compliance guidance:
- JMX over TLS with authentication is acceptable for compliance audits and remote management.
- JMX without authentication (
jmxremote.authenticate=false) is a critical exposure; never enable in production. - JMX without TLS (
jmxremote.ssl=false) leaks credentials and management traffic in cleartext; never enable in production. - Password and access files must be readable only by the JVM process user (
chmod 400); JMX startup fails otherwise. -
java.rmi.server.hostnamemust match the externally-reachable hostname for clients behind NAT or in Kubernetes.
For most Eliya deployments, the sidecar pattern above is preferable to JMX because it does not expose a remote management endpoint at all. JMX remains documented because some enterprise environments require it for compliance audit, inventory, or established tooling integration.
Choosing a pattern
| Pattern | Best for | Trade-off |
|---|---|---|
| Interactive exec | Development, staging, small production | App container ships diagnostic tools |
| Ephemeral diagnostic containers | Production incident response (recommended) | Requires Kubernetes 1.23+ with appropriate RBAC |
| Always-on diagnostic sidecar | Scheduled diagnostic tasks; clusters without ephemeral container support | Continuous resource cost (~40 MB JVM + container overhead per pod); sidecar uses full image |
| JMX over secure channel | Legacy enterprise; frameworks requiring remote management endpoints | Remote management surface area; TLS + auth configuration burden |
Recommendation: ephemeral diagnostic containers for production incident response; always-on sidecar for scheduled diagnostic tasks or clusters that can't run ephemeral containers; interactive exec for development; JMX where the environment specifically requires it.
Quick smoke test
Confirm the image launches and the JVM recognises Eliya's EliyaProfile flag:
Expected output (Phase 1, no profile set on this invocation):
ccstr EliyaProfile = None {product} {default}
bool EliyaConflictCheck = true {product} {default} Verify the asymm launcher is on the image PATH:
This confirms the image launches, the asymm launcher is present, and prints the Eliya version banner via the sibling java binary.
Multi-arch support
Images support linux/amd64 and linux/arm64 via the manifest list. Docker and Kubernetes automatically pick the correct architecture at pull time. No explicit arch selection required for the common case.