Configuration¶
Every knob Brewlet exposes, in one place: Helm chart values, node-provisioner
environment variables, operator/admission flags, the RuntimeClass, and how the
different layers relate. For how to install, see Installation;
for JDKs and launchers specifically, see JDK management and
Launchers.
Configuration layers (how they connect)¶
There is one source of truth for the JDK/launcher inventory: you set it once, and it flows down.
Helm values (provisioner.jdks / .launchers)
│ become operator flags
▼
Operator flags (--jdks / --launchers)
│ flow into the DaemonSet container env
▼
Provisioner env (JDKS / LAUNCHERS)
│ drive what gets installed on each node
▼
Node state: /opt/brewlet/jdks/<dist>-<feature>/ + labels/annotations
If you use Helm, set values. If you run the operator directly, set flags. If you hand-wire the DaemonSet, set env vars. Don't mix — the operator overwrites the DaemonSet it manages.
Note on defaults. The "Default" columns below are per-layer: they apply only when that layer is invoked directly. The Helm chart ships richer defaults than the bare binaries (e.g.
provisioner.jdks=temurin-21,microsoft-25andprovisioner.launchers=jaz), and passes them down explicitly, so a direct operator/DaemonSet invocation without those flags/env falls back to the leaner binary defaults (--jdks=temurin-21,--launchers/LAUNCHERSempty).
Helm chart values¶
From charts/brewlet/values.yaml. Override
with --set key=value or a values file.
| Key | Default | Meaning |
|---|---|---|
namespace |
brewlet |
Namespace all components install into (created by the chart). |
images.registry |
ghcr.io/brewlet |
Registry prefix used to generate component image references. |
images.tag |
chart appVersion |
Shared component tag. A versioned OCI chart therefore selects matching images automatically. |
images.operator |
generated | Explicit operator image override; supports tags or digests. |
images.provisioner |
generated | Explicit provisioner image override; supports tags or digests. |
images.admission |
generated | Explicit admission webhook image override; supports tags or digests. |
images.pullPolicy |
IfNotPresent |
Image pull policy for all components. |
provisioner.jdks |
temurin-21,microsoft-25 |
Comma-separated curated <dist>-<feature> roots, or a structured list with source.image and source.javaHome for custom distributions (§JDK management). |
provisioner.launchers |
jaz |
Comma-separated launcher layers (§Launchers). Empty = vanilla java only. |
provisioner.rollout.maxUnavailable |
null |
Bounds the default profile's provisioner DaemonSet rolling update. null keeps the DaemonSet default. |
provisioner.rollout.validate |
true |
Gate node readiness on the post-install JDK smoke test (java -version per root). Renders the provisioner BREWLET_VALIDATE env. |
provisioner.rollout.containerdRestart |
validated |
When/whether to reload containerd after writing its config: validated, sighup, or none. Renders BREWLET_CONTAINERD_RESTART (§5.5). |
provisioner.registry.mirrors |
{} |
<upstream-host>: <mirror-host> map applied to every copy-from-image pull for air-gapped clusters. Renders MIRRORS. |
defaultProfile.enabled |
true |
Render the chart-managed default NodeProfile from provisioner.*. Disable to manage the default profile yourself, e.g. via GitOps (§5.6). |
profiles |
[] |
Additional per-pool NodeProfile CRs, each binding node pool(s) to their own JDK/launcher inventory plus rollout/registry policy (§5.6). |
operator.replicas |
1 |
Operator replica count. |
operator.leaderElect |
true |
Enable leader election for HA. |
operator.resources |
requests 50m/64Mi, limits 200m/128Mi |
Operator pod resources. |
admission.enabled |
true |
Deploy the admission/scheduling webhook. Set false to skip it (the shim keeps its runtime JDK check). |
admission.replicas |
1 |
Webhook replica count. |
admission.failurePolicy |
Ignore |
Webhook failure policy. Ignore ensures a webhook outage never blocks workloads. |
admission.port |
9443 |
Webhook server port. |
admission.resources |
requests 50m/64Mi, limits 200m/128Mi |
Webhook pod resources. |
Example production install (own registry, no jaz):
helm install brewlet oci://ghcr.io/brewlet/charts/brewlet \
--version 0.1.0 \
--set images.operator=registry.example.com/brewlet/operator@sha256:… \
--set images.provisioner=registry.example.com/brewlet/node-provisioner@sha256:… \
--set images.admission=registry.example.com/brewlet/admission@sha256:… \
--set provisioner.jdks="temurin-21,temurin-25" \
--set provisioner.launchers=""
JDKs and launchers are always obtained copy-from-image (the vendor's official image, pulled through the host containerd). Mirror those images into your own registry for air-gapped clusters.
Operator flags¶
The source for these flags lives in
cmd/manager.
When you install via Helm, the chart populates them for you.
| Flag | Default | Meaning |
|---|---|---|
--namespace |
brewlet |
Namespace the provisioner DaemonSet is managed in. |
--provisioner-image |
ghcr.io/brewlet/node-provisioner:0.1.0 |
Image the DaemonSet runs. |
--jdks |
temurin-21 |
Comma-separated <dist>-<feature> inventory (flows to the provisioner JDKS env). |
--launchers |
(empty) | Comma-separated launcher inventory (LAUNCHERS env). |
--leader-elect |
false |
Enable leader election for HA. |
--metrics-bind-address |
:8080 |
Metrics endpoint. |
--health-probe-bind-address |
:8081 |
Health/readiness endpoint. |
./bin/operator --namespace=brewlet \
--provisioner-image=ghcr.io/brewlet/node-provisioner:0.1.0 \
--jdks=temurin-21,microsoft-25 --launchers=jaz
Node-provisioner environment variables¶
The provisioner environment contract lives in the core runtime's
provisioner/README.md.
The Kubernetes operator sets these variables on the DaemonSet it manages; you
only touch them directly if you hand-wire the DaemonSet.
| Env var | Default | Meaning |
|---|---|---|
JDKS |
temurin-21 |
Comma-separated <distribution>-<feature> roots to install. |
JDK_CUSTOM_SOURCE_COUNT |
0 |
Number of indexed custom source entries rendered by the operator. |
JDK_CUSTOM_SOURCE_<n>_{TOKEN,IMAGE,JAVA_HOME} |
(empty) | Internal operator-to-provisioner transport for custom NodeProfile JDK sources. Configure spec.jdks[].source, not these variables directly. |
LAUNCHERS |
(empty) | Comma-separated launcher layers to stage (e.g. jaz). java is implicit. |
NODE_NAME |
(downward API) | The node to label; injected from spec.nodeName. |
BREWLET_PREFIX |
/opt/brewlet |
Host install prefix (bin/, jdks/, launchers/). |
CONTAINERD_CONFIG |
/etc/containerd/config.toml |
containerd config to patch. |
CONTAINERD_ADDRESS |
/run/containerd/containerd.sock |
Host containerd socket (used for copy-from-image). |
CONTAINERD_NAMESPACE |
k8s.io |
containerd namespace for image pulls. |
BREWLET_MODE |
provision |
provision installs the runtime; cleanup reverses it (restores the containerd config backup, removes the shim, drops the runtime + capability labels) for a deleted NodeProfile. The operator sets it on the short-lived brewlet-cleanup-<profile> DaemonSet (§5.6). |
BREWLET_CONTAINERD_RESTART |
validated |
When/whether to reload containerd after writing its config: validated (smoke-test the JDK roots first, then SIGHUP), sighup (SIGHUP unconditionally), or none (never signal; a rollout/human restarts it). Rendered from spec.rollout.containerdRestart. |
BREWLET_VALIDATE |
true |
Run the post-install JDK smoke test (java -version per root) before flipping the node ready. false skips it. Rendered from spec.rollout.validate. |
MIRRORS |
(empty) | Comma-separated <upstream-host>=<mirror-host> pairs; every copy-from-image pull rewrites its registry host through this map for air-gapped clusters. Rendered from spec.registry.mirrors. |
Admission webhook¶
The brewlet-admission webhook is
mutating+validating. For every pod on CREATE with runtimeClassName: brewlet it:
- stamps
brewlet.sh/artifact-ref(andbrewlet.sh/artifact-digestwhen the ref is digest-pinned) so the shim can resolve the JAR from the content store; - matches any requested JDK/launcher against the ready fleet, denying with
NoCompatibleJDK/NoCompatibleLauncher; - steers scheduling via
nodeAffinityonto per-capability node labels.
Non-brewlet pods pass through untouched. With admission.failurePolicy: Ignore
(default) a webhook outage never blocks workloads.
Serving certificate. By default Helm generates a self-signed serving cert at
render time and injects the CA as the caBundle. Because Helm regenerates it on
each helm upgrade, the Secret and caBundle rotate together and a checksum
annotation rolls the webhook pods. For production, swap in cert-manager (a
Certificate + the cert-manager.io/inject-ca-from annotation).
Pod-side annotations the webhook reads (developer-facing) — see Deploying workloads:
| Annotation | Example | Meaning |
|---|---|---|
brewlet.sh/jdk |
21 or temurin-21 |
Request a specific JDK feature (any distro) or exact <dist>-<feature>. |
brewlet.sh/launcher |
jaz |
Request a launcher. Empty / java = vanilla OpenJDK launcher. |
brewlet.sh/artifact-container |
app |
Which container's image is the OCI artifact (defaults to the brewlet container). |
RuntimeClass¶
The operator manages the brewlet RuntimeClass; this is what it generates (mirrors
deploy/runtimeclass.yaml):
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: brewlet
handler: brewlet # matches the containerd runtime name
scheduling:
nodeSelector:
brewlet.sh/runtime: "ready" # only land on provisioned nodes
overhead:
podFixed:
memory: "64Mi" # JVM/runtime baseline overhead accounting
cpu: "50m"
overhead.podFixed is how the scheduler and LimitRange/quotas account for the
JVM/runtime baseline. Adjust it if your JVMs have a materially different fixed
footprint.
Precedence & defaults you should know¶
- JVM launch flags: artifact structured knobs carry app-intrinsic correctness
flags; deployment-descriptor
jvm.argscarries heap/GC/agent tuning and comes after those knobs. The descriptor'sjvm.launcher/brewlet.sh/launcherselectsjavaor a node-installed launcher. Brewlet injects no-XXflags itself. See Resource tuning. - JDK selection: the deployment descriptor is authoritative:
spec.jvm.version(plus optionalspec.jvm.distribution) onJavaApplication, orbrewlet.sh/jdkon raw pods, drives validation, scheduling, and shim launch selection. A bare feature matches any distribution;<distribution>-<feature>pins one. - cgroup v2 is mandatory on nodes; the provisioner refuses cgroup v1-only nodes.
- Digest-pinned artifact refs are recommended (
repo@sha256:…) so the shim can resolve straight from the content store and so supply-chain policy can apply.
Next steps¶
- JDK management — the copy-from-image mechanics and the curated distribution → image matrix.
- Launchers — installing and choosing
jaz. - Deploying workloads — put these knobs to use.