Observability & day‑2 operations¶
Because the shim is runc-backed and the workload is an ordinary pod, everything you already do to observe and operate Kubernetes workloads works unchanged. This page covers what to expect and the Brewlet-specific day‑2 tasks.
See also SPECIFICATION §12.
Networking¶
- Normal pod IP via CNI — runc owns the netns the kubelet/containerd provide.
- Services, Ingress, NetworkPolicy all behave exactly as for any pod.
- No special CNI configuration is required.
kubectl get pod <pod> -o wide # real pod IP
kubectl expose deployment hello --port 80 --target-port 8080
Logs¶
The JVM's stdout/stderr flow through containerd just like any container:
Metrics & tracing¶
- JMX, Micrometer, OpenTelemetry work as usual — the JVM is a normal process in a normal sandbox.
- JFR (Java Flight Recorder) can be enabled via
jvm.args(e.g.-XX:StartFlightRecording=...). - metrics-server / HPA work because the sandbox is a real cgroup-backed container.
Probes & exec¶
All probe types and interactive debugging work because runc backs the sandbox:
- readiness / liveness / startup probes:
httpGet,tcpSocket,exec; kubectl execinto the JVM sandbox;- ephemeral debug containers.
readinessProbe: { httpGet: { path: /actuator/health/readiness, port: 8080 } }
livenessProbe: { httpGet: { path: /actuator/health/liveness, port: 8080 } }
Signals & graceful shutdown¶
SIGTERMis forwarded to the JVM (PID 1) → shutdown hooks run; Brewlet honorsterminationGracePeriodSecondsandpreStop.- The
javaprocess's exit code is the container exit code, which drives the pod'srestartPolicy(so-XX:+ExitOnOutOfMemoryError→ clean restart).
Autoscaling¶
HPA works against CPU/memory or custom/Prometheus metrics as usual. With the
JavaApplication CRD you can declare autoscaling inline and the controller (§8.2)
creates the HorizontalPodAutoscaler for you; with raw Deployments, attach a
standard HorizontalPodAutoscaler.
Day‑2: JDK upgrades¶
JDK roots on nodes are versioned and additive. The upgrade choreography — add a new root, migrate workloads, retire the old root — is covered in detail in JDK management → Patching & upgrading.
Key properties:
- New roots install additively; running pods keep their JDK until they restart.
- Old roots are retained until no workload references them, then GC'd by the provisioner (GC is a provisioner responsibility; today, retire by removing from the inventory and cleaning the node).
- Patching one node JDK patches every workload that uses it — centralized CVE management.
Day‑2: multi-arch fleets¶
- Install one JDK root per node architecture (amd64/arm64).
- The OCI artifact is arch-independent — the same artifact runs on any provisioned arch, so multi-arch is transparent to developers.
- The provisioner image and shim are compiled per-arch; use the multi-arch
*-image-pushbuild targets. See JDK management → multi-arch. - Non-portable (JNI) JARs and arch-coupled accelerators (AppCDS archives) are the
exception — see the multi-arch note for the optional
archscheduling constraint.
Watching the fleet¶
# Node readiness and operator state:
kubectl get nodes -L brewlet.sh/runtime
kubectl get node <n> -o jsonpath='{.metadata.annotations.brewlet\.sh/provision-state}{"\n"}'
# What each node offers:
kubectl get node <n> -o jsonpath='{.metadata.annotations.brewlet\.sh/jdks}{"\n"}'
kubectl get node <n> -o jsonpath='{.metadata.annotations.brewlet\.sh/launchers}{"\n"}'
# Operator/provisioner events:
kubectl get events --field-selector reason=NodeReady
kubectl get events --field-selector reason=ProvisionFailed
# Component health:
kubectl get pods -n brewlet
The operator exposes metrics (--metrics-bind-address, default :8080) and a
health/readiness endpoint (--health-probe-bind-address, default :8081).
Next steps¶
- Troubleshooting — when something's wrong.
- Security — hardening and supply chain.
- Roadmap — planned Brewlet-specific telemetry.