Part 2: Build and deploy a Brewlet workload¶
Audience: Java application developers.
Goal: build a JAR, publish it as a runnable OCI image, and deploy it to a Brewlet-enabled Kubernetes cluster without creating a Dockerfile or bundling a JDK.
1. Receive the platform handoff¶
Ask the Ops participant for:
export BREWLET_CONTEXT="<kubernetes-context>"
export BREWLET_NAMESPACE="<developer-namespace>"
export BREWLET_JDK="21"
export BREWLET_VERSION="0.1.0"
export BREWLET_REGISTRY="<registry-host>/<team>"
You also need JDK 21+, Maven 3.9+, kubectl, curl, registry push credentials,
and the example source from the matching Brewlet release:
git clone --depth 1 --branch "v${BREWLET_VERSION}" \
https://github.com/brewlet/brewlet.git
cd brewlet
The registry repository must be readable by the cluster nodes.
Select the provided context and confirm your access:
kubectl config use-context "$BREWLET_CONTEXT"
kubectl auth can-i create deployments -n "$BREWLET_NAMESPACE"
kubectl auth can-i create javaapplications.apps.brewlet.sh -n "$BREWLET_NAMESPACE"
kubectl get runtimeclass brewlet
Install the released CLI and run the same readiness check used by Ops:
curl -fsSL https://brewlet.sh/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
brewlet doctor \
--context "$BREWLET_CONTEXT" \
--namespace "$BREWLET_NAMESPACE"
If your RBAC permits reading nodes, you can also inspect the available JDKs:
kubectl get nodes -l brewlet.sh/runtime=ready \
-o custom-columns=NAME:.metadata.name,JDKS:.metadata.annotations.brewlet\\.sh/jdks
2. Build the example JAR¶
The included dependency-free application exposes /hello, /healthz, and
/info.
mvn -f integration-tests/fixtures/demo-app/pom.xml clean package
jar --describe-module \
--file integration-tests/fixtures/demo-app/target/app.jar
The output is an ordinary executable JAR. It contains neither Linux nor a JDK.
3. Install and exercise the released Maven plugin¶
The plugin is attached to the GitHub release while Maven Central publication is being established. Install the released JAR and POM into your local Maven repository:
mkdir -p target/brewlet-release
curl -fL \
-o target/brewlet-release/brewlet-maven-plugin.jar \
"https://github.com/brewlet/brewlet/releases/download/v${BREWLET_VERSION}/brewlet-maven-plugin-${BREWLET_VERSION}.jar"
curl -fL \
-o target/brewlet-release/brewlet-maven-plugin.pom \
"https://github.com/brewlet/brewlet/releases/download/v${BREWLET_VERSION}/brewlet-maven-plugin-${BREWLET_VERSION}.pom"
mvn org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \
-Dfile=target/brewlet-release/brewlet-maven-plugin.jar \
-DpomFile=target/brewlet-release/brewlet-maven-plugin.pom
Build a registry-free runnable OCI layout first:
mvn -f integration-tests/fixtures/demo-app/pom.xml \
"sh.brewlet:brewlet-maven-plugin:${BREWLET_VERSION}:config" \
"sh.brewlet:brewlet-maven-plugin:${BREWLET_VERSION}:build" \
-Dbrewlet.image=demo/hello:workshop
test -f integration-tests/fixtures/demo-app/target/brewlet/jvm-config.json
test -f integration-tests/fixtures/demo-app/target/brewlet/oci/index.json
The image layout contains standard OCI layers for amd64 and arm64. Its image
config carries a Brewlet launch contract; it does not contain a base image.
4. Publish the application¶
Choose a unique tag and push it to the registry supplied by Ops:
export IMAGE="$BREWLET_REGISTRY/hello:$(date +%Y%m%d%H%M%S)"
mvn -f integration-tests/fixtures/demo-app/pom.xml \
"sh.brewlet:brewlet-maven-plugin:${BREWLET_VERSION}:push" \
-Dbrewlet.image="$IMAGE"
Use your normal registry login mechanism before this command. Private registry
authentication can be configured with spec.artifact.pullSecrets; this
workshop assumes the nodes can read the selected repository directly.
5. Deploy with JavaApplication¶
cat <<EOF | kubectl apply -n "$BREWLET_NAMESPACE" -f -
apiVersion: apps.brewlet.sh/v1alpha1
kind: JavaApplication
metadata:
name: hello
spec:
artifact:
image: ${IMAGE}
jvm:
version: ${BREWLET_JDK}
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 256Mi
ports:
- name: http
containerPort: 8080
service:
enabled: true
type: ClusterIP
probes:
readiness:
httpGet:
path: /healthz
port: 8080
EOF
Watch the higher-level resource and the Kubernetes objects it owns:
kubectl get javaapplication,deployment,pod,service -n "$BREWLET_NAMESPACE"
kubectl rollout status deployment/hello -n "$BREWLET_NAMESPACE" --timeout=5m
kubectl logs deployment/hello -n "$BREWLET_NAMESPACE"
The generated pod uses runtimeClassName: brewlet. The node-resident JDK
launches the JAR directly under the pod's CPU and memory cgroups.
6. Call the application¶
In one terminal:
In another:
The /info response shows the selected Java runtime and the CPU and memory
limits observed by the JVM.
7. Make and deploy a change¶
Change the response in
integration-tests/fixtures/demo-app/src/com/example/Hello.java, choose a new
tag, then repeat the package, push, and apply steps. Kubernetes rolls out the new
artifact like any other application update.
Cleanup¶
This removes the generated Deployment and Service but leaves the shared Brewlet platform intact. See Building and publishing and Deploying workloads for production options.