From 3f7bb3aec79c63b4e392a76ac69b8380ff95f635 Mon Sep 17 00:00:00 2001 From: Matt Raible Date: Thu, 1 Feb 2024 00:40:02 -0700 Subject: [PATCH] Update Helidon steps after QA --- demo.adoc | 32 +++++---- helidon/Dockerfile | 4 +- helidon/Dockerfile.jlink | 12 +++- helidon/README.md | 68 ++++++++++++++++--- helidon/app.yaml | 36 ++++++++++ helidon/pom.xml | 52 ++++++++++++-- .../rest/{HelloApplication.java => Main.java} | 10 +-- .../HelloResource.java | 2 +- .../rest}/helidon/native-image.properties | 0 .../src/main/resources/application.properties | 4 -- .../{application.yml => application.yaml} | 0 helidon/src/main/resources/logging.properties | 23 +------ ...onfig.properties => application-test.yaml} | 0 helidon/src/test/resources/application.yaml | 2 - 14 files changed, 185 insertions(+), 60 deletions(-) create mode 100644 helidon/app.yaml rename helidon/src/main/java/com/okta/rest/{HelloApplication.java => Main.java} (81%) rename helidon/src/main/java/com/okta/rest/{controller => resource}/HelloResource.java (95%) rename helidon/src/main/resources/META-INF/native-image/{com.okta.rest => com/okta/rest}/helidon/native-image.properties (100%) delete mode 100644 helidon/src/main/resources/application.properties rename helidon/src/main/resources/{application.yml => application.yaml} (100%) rename helidon/src/test/resources/{META-INF/microprofile-config.properties => application-test.yaml} (100%) delete mode 100644 helidon/src/test/resources/application.yaml diff --git a/demo.adoc b/demo.adoc index 66075d1..8f3d374 100644 --- a/demo.adoc +++ b/demo.adoc @@ -302,10 +302,19 @@ helidon init --flavor SE --groupid com.okta.rest \ + TIP: See https://blogs.oracle.com/developers/post/migrating-a-helidon-se-application-to-gradle[Migrating a Helidon SE application to Gradle] for Gradle support. -. Add MicroProfile JWT support in `pom.xml`: +. Delete the default Java classes created by the Helidon CLI: + +- On Windows: `del /s *.java` +- On Mac/Linux: `find . -name '*.java' -delete` + +. Add JWT authentication support in `pom.xml`: + [source,xml] ---- + + io.helidon.webserver + helidon-webserver-security + io.helidon.security.providers helidon-security-providers-jwt @@ -316,7 +325,7 @@ TIP: See https://blogs.oracle.com/developers/post/migrating-a-helidon-se-applica + [source,java] ---- -package com.okta.rest.controller; +package com.okta.rest.resource; import static io.helidon.http.Status.OK_200; @@ -343,24 +352,25 @@ public class HelloResource implements HttpFeature { } ---- -. Add a `HelloApplication` class in `src/main/java/com/okta/rest` to register your resource and configure JWT authentication: +. Create a `Main` class in `src/main/java/com/okta/rest` to register your resource and configure JWT authentication: + [source,java] ---- package com.okta.rest; -import com.okta.rest.controller.HelloResource; +import com.okta.rest.resource.HelloResource; import io.helidon.config.Config; -import io.helidon.config.ConfigSources; +import io.helidon.logging.common.LogConfig; import io.helidon.webserver.WebServer; import io.helidon.webserver.WebServerConfig; import io.helidon.webserver.security.SecurityHttpFeature; import java.util.concurrent.TimeUnit; -public class HelloApplication { +public class Main { public static void main(String[] args) { + LogConfig.configureRuntime(); WebServerConfig.Builder builder = WebServer.builder(); setup(builder); WebServer server = builder.port(8080).build(); @@ -375,7 +385,8 @@ public class HelloApplication { } static void setup(WebServerConfig.Builder server) { - Config config = Config.create(ConfigSources.classpath("application.yml")); + Config config = Config.create(); + Config.global(config); server.routing(routing -> routing .addFeature(SecurityHttpFeature.create(config.get("security.web-server"))) @@ -384,7 +395,7 @@ public class HelloApplication { } ---- -. Create a YAML config file at `src/main/resources/application.yml`. +. Add your security settings and routes to `src/main/resources/application.yaml`. + [source,yaml] ---- @@ -411,11 +422,6 @@ security: http :8080/hello Authorization:"Bearer $TOKEN" -. Delete the default Java classes created by the Helidon CLI: - -- On Windows: `del /s *.java` -- On Mac/Linux: `find . -name '*.java' -delete` - === Build a native Helidon app with GraalVM . Update `src/main/resources/META-INF/native-image/com.okta.rest/helidon/native-image.properties` so native compilation will work with Java 21. diff --git a/helidon/Dockerfile b/helidon/Dockerfile index 120d0d1..db7b038 100644 --- a/helidon/Dockerfile +++ b/helidon/Dockerfile @@ -16,8 +16,8 @@ WORKDIR /helidon # Create a first layer to cache the "Maven World" in the local repository. # Incremental docker builds will always resume after that, unless you update # the pom -ADD pom.xml pom.xml -RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip +ADD pom.xml . +RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip # Do the Maven build! # Incremental docker builds will resume here when you change sources diff --git a/helidon/Dockerfile.jlink b/helidon/Dockerfile.jlink index 762b8d9..41e4003 100644 --- a/helidon/Dockerfile.jlink +++ b/helidon/Dockerfile.jlink @@ -1,6 +1,16 @@ # 1st stage, build the app -FROM maven:3.8.4-openjdk-17-slim as build +FROM container-registry.oracle.com/java/openjdk:21 as build + +WORKDIR /usr/share + +# Install maven +RUN set -x && \ + curl -O https://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz && \ + tar -xvf apache-maven-*-bin.tar.gz && \ + rm apache-maven-*-bin.tar.gz && \ + mv apache-maven-* maven && \ + ln -s /usr/share/maven/bin/mvn /bin/ WORKDIR /helidon diff --git a/helidon/README.md b/helidon/README.md index 48bc1b9..82b23d0 100644 --- a/helidon/README.md +++ b/helidon/README.md @@ -1,6 +1,6 @@ # helidon -Minimal Helidon SE project suitable to start from scratch. +Sample Helidon SE project that includes multiple REST operations. ## Build and run @@ -12,11 +12,15 @@ java -jar target/helidon.jar ``` ## Exercise the application + +Basic: ``` curl -X GET http://localhost:8080/simple-greet -{"message":"Hello World!"} +Hello World! ``` + +JSON: ``` curl -X GET http://localhost:8080/greet {"message":"Hello World!"} @@ -36,30 +40,49 @@ curl -X GET http://localhost:8080/greet/Jose ``` # Prometheus Format -curl -s -X GET http://localhost:8080/metrics +curl -s -X GET http://localhost:8080/observe/metrics # TYPE base:gc_g1_young_generation_count gauge . . . # JSON Format -curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics +curl -H 'Accept: application/json' -X GET http://localhost:8080/observe/metrics {"base":... . . . ``` - ## Try health -``` -curl -s -X GET http://localhost:8080/health -{"outcome":"UP",... +This example shows the basics of using Helidon SE Health. It uses the +set of built-in health checks that Helidon provides plus defines a +custom health check. + +Note the port number reported by the application. +Probe the health endpoints: + +```bash +curl -X GET http://localhost:8080/observe/health +curl -X GET http://localhost:8080/observe/health/ready ``` ## Building a Native Image +The generation of native binaries requires an installation of GraalVM 22.1.0+. + +You can build a native binary using Maven as follows: + +``` +mvn -Pnative-image install -DskipTests +``` + +The generation of the executable binary may take a few minutes to complete depending on +your hardware and operating system. When completed, the executable file will be available +under the `target` directory and be named after the artifact ID you have chosen during the +project generation phase. + Make sure you have GraalVM locally installed: ``` @@ -97,6 +120,35 @@ docker run --rm -p 8080:8080 helidon:latest Exercise the application as described above. +## Run the application in Kubernetes + +If you don’t have access to a Kubernetes cluster, you can [install one](https://helidon.io/docs/latest/#/about/kubernetes) on your desktop. + +### Verify connectivity to cluster + +``` +kubectl cluster-info # Verify which cluster +kubectl get pods # Verify connectivity to cluster +``` + +### Deploy the application to Kubernetes + +``` +kubectl create -f app.yaml # Deploy application +kubectl get pods # Wait for quickstart pod to be RUNNING +kubectl get service helidon # Get service info +``` + +Note the PORTs. You can now exercise the application as you did before but use the second +port number (the NodePort) instead of 8080. + +After you’re done, cleanup. + +``` +kubectl delete -f app.yaml +``` + + ## Building a Custom Runtime Image Build the custom runtime image using the jlink image profile: diff --git a/helidon/app.yaml b/helidon/app.yaml new file mode 100644 index 0000000..45e0cfc --- /dev/null +++ b/helidon/app.yaml @@ -0,0 +1,36 @@ +kind: Service +apiVersion: v1 +metadata: + name: helidon + labels: + app: helidon +spec: + type: NodePort + selector: + app: helidon + ports: + - port: 8080 + targetPort: 8080 + name: http +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: helidon +spec: + replicas: 1 + selector: + matchLabels: + app: helidon + template: + metadata: + labels: + app: helidon + version: v1 + spec: + containers: + - name: helidon + image: helidon + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 diff --git a/helidon/pom.xml b/helidon/pom.xml index 76439aa..bed4d01 100644 --- a/helidon/pom.xml +++ b/helidon/pom.xml @@ -14,7 +14,7 @@ 1.0-SNAPSHOT - com.okta.rest.HelloApplication + com.okta.rest.Main @@ -26,10 +26,6 @@ io.helidon.webserver helidon-webserver-security - - io.helidon.webserver - helidon-webserver-context - io.helidon.security.providers helidon-security-providers-jwt @@ -38,10 +34,56 @@ io.helidon.config helidon-config-yaml + + io.helidon.webserver.observe + helidon-webserver-observe-health + + + io.helidon.health + helidon-health-checks + + + io.helidon.logging + helidon-logging-jul + runtime + + + jakarta.json + jakarta.json-api + io.helidon.http.media helidon-http-media-jsonp + + io.helidon.webserver.observe + helidon-webserver-observe-metrics + + + io.helidon.metrics + helidon-metrics-system-meters + runtime + + + io.helidon.webclient + helidon-webclient + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + io.helidon.webserver.testing.junit5 + helidon-webserver-testing-junit5 + test + diff --git a/helidon/src/main/java/com/okta/rest/HelloApplication.java b/helidon/src/main/java/com/okta/rest/Main.java similarity index 81% rename from helidon/src/main/java/com/okta/rest/HelloApplication.java rename to helidon/src/main/java/com/okta/rest/Main.java index 5b9609b..940bcce 100644 --- a/helidon/src/main/java/com/okta/rest/HelloApplication.java +++ b/helidon/src/main/java/com/okta/rest/Main.java @@ -1,17 +1,18 @@ package com.okta.rest; -import com.okta.rest.controller.HelloResource; +import com.okta.rest.resource.HelloResource; import io.helidon.config.Config; -import io.helidon.config.ConfigSources; +import io.helidon.logging.common.LogConfig; import io.helidon.webserver.WebServer; import io.helidon.webserver.WebServerConfig; import io.helidon.webserver.security.SecurityHttpFeature; import java.util.concurrent.TimeUnit; -public class HelloApplication { +public class Main { public static void main(String[] args) { + LogConfig.configureRuntime(); WebServerConfig.Builder builder = WebServer.builder(); setup(builder); WebServer server = builder.port(8080).build(); @@ -26,7 +27,8 @@ public static void main(String[] args) { } static void setup(WebServerConfig.Builder server) { - Config config = Config.create(ConfigSources.classpath("application.yml")); + Config config = Config.create(); + Config.global(config); server.routing(routing -> routing .addFeature(SecurityHttpFeature.create(config.get("security.web-server"))) diff --git a/helidon/src/main/java/com/okta/rest/controller/HelloResource.java b/helidon/src/main/java/com/okta/rest/resource/HelloResource.java similarity index 95% rename from helidon/src/main/java/com/okta/rest/controller/HelloResource.java rename to helidon/src/main/java/com/okta/rest/resource/HelloResource.java index a5078d9..fa8bc49 100644 --- a/helidon/src/main/java/com/okta/rest/controller/HelloResource.java +++ b/helidon/src/main/java/com/okta/rest/resource/HelloResource.java @@ -1,4 +1,4 @@ -package com.okta.rest.controller; +package com.okta.rest.resource; import static io.helidon.http.Status.OK_200; diff --git a/helidon/src/main/resources/META-INF/native-image/com.okta.rest/helidon/native-image.properties b/helidon/src/main/resources/META-INF/native-image/com/okta/rest/helidon/native-image.properties similarity index 100% rename from helidon/src/main/resources/META-INF/native-image/com.okta.rest/helidon/native-image.properties rename to helidon/src/main/resources/META-INF/native-image/com/okta/rest/helidon/native-image.properties diff --git a/helidon/src/main/resources/application.properties b/helidon/src/main/resources/application.properties deleted file mode 100644 index 9118dfc..0000000 --- a/helidon/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -#security.providers.0.jwt.atn-token.jwk.resource.uri=https://dev-06bzs1cu.us.auth0.com/.well-known/jwks.json -#security.web-server.defaults.authenticate=true -#security.web-server.paths.0.path=/hello -#security.web-server.paths.0.methods=["get"] diff --git a/helidon/src/main/resources/application.yml b/helidon/src/main/resources/application.yaml similarity index 100% rename from helidon/src/main/resources/application.yml rename to helidon/src/main/resources/application.yaml diff --git a/helidon/src/main/resources/logging.properties b/helidon/src/main/resources/logging.properties index 5157244..5177e0d 100644 --- a/helidon/src/main/resources/logging.properties +++ b/helidon/src/main/resources/logging.properties @@ -1,22 +1,5 @@ - -# Example Logging Configuration File -# For more information see $JAVA_HOME/jre/lib/logging.properties - -# Send messages to the console -handlers=io.helidon.common.HelidonConsoleHandler - -# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread -java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n - +handlers=java.util.logging.ConsoleHandler +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS.%1$tL %5$s%6$s%n # Global logging level. Can be overridden by specific loggers .level=INFO - -# Quiet Weld -org.jboss.level=WARNING - -# Component specific log levels -#io.helidon.webserver.level=INFO -#io.helidon.config.level=INFO -#io.helidon.security.level=INFO -#io.helidon.common.level=INFO -#io.netty.level=INFO +io.helidon.webserver.level=INFO diff --git a/helidon/src/test/resources/META-INF/microprofile-config.properties b/helidon/src/test/resources/application-test.yaml similarity index 100% rename from helidon/src/test/resources/META-INF/microprofile-config.properties rename to helidon/src/test/resources/application-test.yaml diff --git a/helidon/src/test/resources/application.yaml b/helidon/src/test/resources/application.yaml deleted file mode 100644 index 94f3451..0000000 --- a/helidon/src/test/resources/application.yaml +++ /dev/null @@ -1,2 +0,0 @@ -security: - enabled: false \ No newline at end of file