Reference¶
Quick-lookup tables for the identifiers, formats, and paths Brewlet uses. Sources:
internal/brewlet/labels.go,
internal/artifact/, and
SPECIFICATION.
Labels & annotations¶
Node labels (set by the provisioner; drive scheduling)¶
| Key | Value | Meaning |
|---|---|---|
brewlet.sh/provision |
true |
Opt a node in. The platform team sets it; the operator manages the provisioner DaemonSet for matching nodes. |
brewlet.sh/runtime |
ready |
Set once the shim + a JDK are installed and the runtime is registered. The RuntimeClass nodeSelector matches on it. |
brewlet.sh/jdk.<dist>-<feature> |
(present) | Boolean-presence label: this exact JDK root is installed (e.g. brewlet.sh/jdk.temurin-21). |
brewlet.sh/jdk-feature.<feature> |
(present) | Some JDK of that feature is installed (e.g. brewlet.sh/jdk-feature.21), for distro-agnostic requests. |
brewlet.sh/launcher.<name> |
(present) | This launcher layer is installed (e.g. brewlet.sh/launcher.jaz). |
The admission webhook matches the per-capability labels with Operator: Exists when
injecting nodeAffinity.
Node annotations¶
| Key | Example | Meaning |
|---|---|---|
brewlet.sh/jdks |
temurin-21,microsoft-25 |
Advertised JDK roots (comma-separated). |
brewlet.sh/launchers |
java,jaz |
Advertised launcher layers. |
brewlet.sh/provision-state |
Provisioning | Ready | Failed |
The operator's view of the node's lifecycle (distinct from the provisioner-owned runtime=ready label). |
Pod annotations¶
| Key | Example | Set by | Meaning |
|---|---|---|---|
brewlet.sh/jdk |
21 or temurin-21 |
you | Request a JDK feature (any distro) or an exact <dist>-<feature>. Validated + scheduled by the webhook. |
brewlet.sh/launcher |
jaz |
you | Request a launcher. Empty / java = vanilla OpenJDK launcher. |
brewlet.sh/arch |
amd64 or amd64,arm64 |
you (or the JavaApplication controller from spec.arch) |
Optional architecture constraint for non-portable JARs bundling JNI natives. Injects kubernetes.io/arch nodeAffinity; if no ready node of a required arch exists → NoCompatibleArch. Omit for arch-neutral bytecode. |
brewlet.sh/artifact-container |
app |
you | Which container's image is the OCI artifact (defaults to the brewlet container). |
brewlet.sh/artifact-ref |
repo:tag |
webhook | The OCI artifact ref the shim resolves. |
brewlet.sh/artifact-digest |
sha256:… |
webhook | Stamped when the ref is digest-pinned; lets the shim read the artifact from the content store by digest. |
Event reasons¶
Recorded by the operator / admission webhook (see Troubleshooting):
| Reason | Emitted when |
|---|---|
Provisioning |
The operator has requested provisioning for a node. |
NodeReady |
A node is provisioned and advertising the brewlet runtime. |
ProvisionFailed |
The provisioner pod on a node is failing (e.g. CrashLoopBackOff). |
NoCompatibleJDK |
A pod requested a JDK no ready node provides → admission denied. |
NoCompatibleLauncher |
A pod requested a launcher no ready node provides → admission denied. |
NoCompatibleArch |
A non-portable JAR requested an arch no ready node provides → admission denied. |
Well-known names¶
| Name | Value | Notes |
|---|---|---|
| RuntimeClass / containerd handler | brewlet |
|
| Provisioner DaemonSet | brewlet-node-provisioner |
Managed by the operator. |
| Default namespace | brewlet |
Created by the Helm chart. |
| containerd runtime type | io.containerd.brewlet.v2 |
Registered in /etc/containerd/config.toml. |
| Vanilla launcher name | java |
Provided by every JDK; needs no layer. |
OCI media types¶
The Java application is an OCI Artifact (OCI Image Spec ≥ 1.1), not a runnable image.
| Component | Media type | Contents |
|---|---|---|
| Artifact type | application/vnd.brewlet.app.v1+json |
Manifest artifactType. |
| Config blob | application/vnd.brewlet.jvm.config.v1+json |
The launch config (below). |
| Payload layer | application/vnd.brewlet.jar.layer.v1+jar |
The raw self-executable JAR. |
| Optional layer | application/vnd.brewlet.classpath.layer.v1+tar |
Extra JARs (dependency layers) unpacked to /app/lib; see layered classpath deployment. |
| Optional layer | application/vnd.brewlet.modulepath.layer.v1+tar |
Library modules for a modular (JPMS) app, unpacked to /app/mods and fed to --module-path; see JPMS support. |
| Optional layer | application/vnd.brewlet.cds.layer.v1+jsa |
A single Application Class-Data Sharing archive (.jsa), mounted read-only at /app/<archive> and consumed with -Xshare:auto -XX:SharedArchiveFile; best-effort startup accelerator, see AppCDS. |
Push with oras using exactly these types — see
Building & publishing.
Layered-deployment options (CLI & Maven)¶
Opt-in flags for layered (thin JAR) deployment —
a thin app JAR plus one or more classpath.layer.v1+tar dependency layers unpacked to
/app/lib. The fat JAR (entry.mode: jar) remains the default.
| Option | Tool | Default | Meaning |
|---|---|---|---|
push --classpath-layer TAR |
CLI | (none) | Attach a pre-built tar of dependency JARs as a classpath.layer.v1+tar layer, unpacked to /app/lib. Repeatable, in stable → volatile order. |
push --module-layer TAR |
CLI | (none) | Attach a pre-built tar of library module JARs as a modulepath.layer.v1+tar layer, unpacked to /app/mods and fed to --module-path. Repeatable; see JPMS support. |
<layered> / -Dbrewlet.layered |
Maven | false |
Ship a thin app JAR plus the resolved transitive POM dependency tree packed into reproducible OCI layers. In classpath mode this produces classpath.layer.v1+tar layers and sets entry.classPath=[mainJar, "lib/*"]; in module mode the dependency modules are packed into a single modulepath.layer.v1+tar layer (unpacked to /app/mods) and entry.modulePath=[mainJar, "mods"] is set. Forces entry.mode=classpath only when the JAR is not modular. |
<splitSnapshotLayers> / -Dbrewlet.splitSnapshotLayers |
Maven | true |
When layered, pack released deps and -SNAPSHOT deps into separate deps / snapshot-deps layers (stable → volatile) for finer dedup. |
Full flag reference: CLI reference and the Maven plugin README.
Launch config schema (config blob)¶
{
"schemaVersion": 1,
"mainJar": "app.jar",
"entry": { "mode": "jar" },
"enablePreview": true,
"addOpens": ["java.base/java.lang=ALL-UNNAMED"],
"systemProperties": { "spring.aot.enabled": "true" },
"cds": { "archive": "app.jsa", "mode": "dynamic" },
"arch": ["amd64"],
"user": { "uid": 1000, "gid": 1000 },
"env": []
}
| Field | Type | Notes |
|---|---|---|
schemaVersion |
int | 1. |
mainJar |
string | Physical filename of the single primary JAR, mounted read-only at /app/<mainJar>. This is not the entrypoint (the mode selects that via the manifest Main-Class, mainClass, or module); it only names the file that classPath/modulePath entries reference by name. Defaults to app.jar. |
entry.mode |
jar | classpath | module |
jar → java -jar; classpath → java -cp <jar> <mainClass>; module → java [-cp <classPath>] -p <modulePath> -m <module>[/<mainClass>] (JPMS, optionally with a supplementary class path — the mixed form; see JPMS support and layered deployment §8). |
entry.mainClass |
string | Required iff entry.mode == classpath; optional in module mode (selects <module>/<mainClass>). |
entry.classPath |
array | Optional; ordered /app-relative class-path entries (e.g. ["app.jar","lib/*"]) for layered deployment. Used in classpath mode and, optionally, in module mode as a supplementary class path alongside the module path (the mixed form). |
entry.module |
string | Required iff entry.mode == module; the root module name for java -m. |
entry.modulePath |
array | Optional; ordered /app-relative module-path entries (e.g. ["orders.jar","mods"]) fed to java -p. Only in module mode; defaults to mainJar. |
enablePreview |
boolean | Optional; expands to --enable-preview for preview-feature code. |
addModules |
array | Optional; expands to --add-modules <comma-joined>. |
addOpens |
array | Optional; each token expands to --add-opens <module>/<package>=<target>. |
addExports |
array | Optional; each token expands to --add-exports <module>/<package>=<target>. |
systemProperties |
object | Optional string map expanded, sorted by key, as -D<key>=<value>. |
cds |
object | Optional Application Class-Data Sharing hint: {archive, mode}. archive is a bare filename (e.g. app.jsa) shipped as a cds.layer.v1+jsa layer, mounted read-only at /app/<archive>; launch prepends -Xshare:auto -XX:SharedArchiveFile=/app/<archive>. mode (dynamic|static, informational) records how it was produced. Best-effort accelerator: a build/version/classpath mismatch falls back to base CDS, never fails. See AppCDS. |
arch |
array | Optional architecture constraint (amd64, arm64). Omit for arch-neutral bytecode (the default — runs on any provisioned arch). Set only for non-portable JARs that bundle JNI native libraries or arch-specific deps; steers scheduling to matching-arch nodes via kubernetes.io/arch nodeAffinity, and denies admission with NoCompatibleArch when no ready node of a required arch exists. The CLI (brewlet push) and Maven plugin auto-detect bundled natives and default this accordingly. |
user |
object | {uid, gid}. |
env |
array | {name, value}. |
Artifact launch knobs expand first in this order: -Xshare:auto
-XX:SharedArchiveFile (when cds is set), --enable-preview, --add-modules,
--add-opens, --add-exports, sorted -D flags. Descriptor jvm.args follows
for deployment tuning/escape-hatch flags, then the entrypoint.
JDK feature/distribution and launcher are not part of this artifact config. They
are specified in the deployment descriptor (spec.jvm.version /
spec.jvm.distribution / spec.jvm.launcher) or raw pod annotations
(brewlet.sh/jdk / brewlet.sh/launcher).
Mode owns its fields (validated). Each entry.mode uses a fixed set of
fields; fields foreign to the selected mode are rejected, not silently
ignored. jar mode must not set mainClass or classPath (the manifest
Main-Class is authoritative); classpath mode requires mainClass and
forbids module/modulePath; module mode requires module and additionally
permits classPath for the mixed form (a supplementary -cp alongside the
module path — see layered deployment §8).
Unknown
modes and foreign-mode fields are errors, caught by the Maven plugin at build
time (mvn brewlet:config/build/push) and by the launch core at publish and
run time. Unknown JSON fields (e.g. a typo like maimJar) are additionally
rejected by the launch core — the CLI and shim parse configs with strict field
checking — at publish and run time.
Top-level JAR references are cross-checked. Dependency layers unpack under
/app/lib (class path) or /app/mods (module path); the single primary JAR is
the only file at the /app top level. So a bare <name>.jar entry (no /, no
*) in classPath/modulePath can only resolve to the primary JAR. When
mainJar is set, any such entry must equal it, or validation fails with a
dangling-reference error — this catches a mainJar/path-entry filename mismatch
before deploy time. Nested entries like lib/legacy.jar and wildcards like
lib/* are unaffected.
Full field semantics: Building & publishing.
Well-known host paths (on a provisioned node)¶
| Path | Contents |
|---|---|
/opt/brewlet/bin/containerd-shim-brewlet-v2 |
The shim binary (also linked into /usr/local/bin). |
/opt/brewlet/jdks/<dist>-<feature>/bin/java |
A shared, read-only JDK runtime root. |
/opt/brewlet/launchers/<name>/bin/<name> |
A shared, read-only launcher layer. |
/etc/containerd/config.toml |
Patched with the runtimes.brewlet block. |
/app/<mainJar> |
The JAR, mounted read-only inside the sandbox. |
Override the /opt/brewlet prefix with BREWLET_PREFIX
(Configuration).
containerd runtime registration¶
The provisioner appends this to /etc/containerd/config.toml:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.brewlet]
runtime_type = "io.containerd.brewlet.v2"
Glossary¶
| Term | Definition |
|---|---|
| OCI Artifact | Non-image content stored/distributed via an OCI registry using custom media types (OCI Image Spec ≥ 1.1). |
| containerd Runtime v2 shim | Pluggable per-runtime process containerd talks to (TTRPC) to manage a container/task — the integration seam SpinKube/runwasi use. |
| RuntimeClass | Kubernetes object selecting which node runtime/handler executes a pod. |
| JDK runtime root | A minimal, read-only Linux userland + JDK installed on the node and overlay-mounted into every JVM sandbox. |
| Launcher | The java-compatible program that fronts the entrypoint (java, or jaz). |
| Overlay rootfs | The sandbox filesystem: shared RO JDK lower + per-container upper/work, JAR at /app. |
| AppCDS | Application Class-Data Sharing — a class archive that cuts startup (ships as a cds.layer). |