mp.guides.mp-tutorial.adoc Maven / Gradle / Ivy
///////////////////////////////////////////////////////////////////////////////
Copyright (c) 2018, 2024 Oracle and/or its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
///////////////////////////////////////////////////////////////////////////////
= Helidon MP Tutorial
:description: Helidon MP Tutorial
:keywords: helidon
:rootdir: {docdir}/../..
include::{rootdir}/includes/mp.adoc[]
This tutorial describes how to build a Helidon MicroProfile (MP) application from scratch
including JSON REST endpoints, metrics, health check, and configuration.
== What You Need
For this 30 minute tutorial, you will need the following:
include::{rootdir}/includes/prerequisites.adoc[tag=prerequisites-curl]
== Create the Maven Project
This tutorial demonstrates how to create the application from scratch, without
using the Maven archetypes as a quickstart.
Create a new empty directory for the project (for example, `helidon-mp-tutorial`). Change into this directory.
Create a new Maven POM file (called `pom.xml`) and add the following
content:
[source,xml,subs="attributes+"]
.Initial Maven POM file
----
4.0.0
io.helidon.applications
helidon-mp
{helidon-version}
io.helidon.examples
helidon-mp-tutorial
${project.artifactId}
io.helidon.examples.Main
io.helidon.microprofile.bundles
helidon-microprofile
org.apache.maven.plugins
maven-dependency-plugin
copy-libs
io.smallrye
jandex-maven-plugin
make-index
----
The POM file contains the basic project information and configurations
needed to get started and does the following:
<1> Includes the Helidon MP application parent pom. This parent pom
contains dependency and plugin management to keep your application's
pom simple and clean.
<2> Establishes the Maven coordinates for the new project.
<3> Sets the `mainClass` which will be used later
when building a JAR file. The class will be created later in this
tutorial.
<4> Adds a dependency for the MicroProfile bundle which allows the
use of MicroProfile features in the application. The helidon-mp
parent pom includes dependency management, so you don't need to
include a version number here. You will automatically use the
version of Helidon that matches the version of the parent pom
({helidon-version} in this case).
<5> Adds plugins to be executed during the build. The `maven-dependency-plugin`
is used to copy the runtime dependencies into your target directory. The
`jandex-maven-plugin` builds an index of your class files for faster
loading. The Helidon parent pom handles the details of configuring
these plugins. But you can modify the configuration here.
TIP: MicroProfile contains features like Metrics, Health Check,
Streams Operators, Open Tracing, OpenAPI, REST client, and fault
tolerance. You can find detailed information about MicroProfile on the
https://projects.eclipse.org/projects/technology.microprofile[Eclipse MicroProfile] site.
With this `pom.xml`, the application can be built successfully with Maven:
[source,bash]
----
mvn clean package
----
This will create a JAR file in the `target` directory.
TIP: The warning message `JAR will be empty - no content was marked for inclusion!`
can be ignored for now because there is no actual content in the
application yet.
== Start Implementing the MicroProfile Application
The actual application logic can be created now.
Create a directory for your source code, and then create
directories for the package hierarchy:
[source,bash]
.Create directories for source code
----
mkdir -p src/main/java/io/helidon/examples
----
The application will be a simple REST service that will return a
greeting to the caller. The first iteration of the application will
contain a resource class and a Main class which will be used to
start up the Helidon server and the application.
TIP: Technically, your own main class is not needed unless you want to control
the startup sequence. You can set the `mainClass` property to
`io.helidon.microprofile.cdi.Main` and it will use Helidon's default
main class.
The `GreetResource` is defined in the `GreetResource.java` class as shown
below:
[source,java]
.src/main/java/io/helidon/examples/GreetResource.java
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_1, indent=0]
----
<1> This class is annotated with `Path` which sets the path for this resource
as `/greet`.
<2> The `RequestScoped` annotation defines that this bean is
request scoped. The request scope is active only for the duration of
one web service invocation, and it is destroyed at the end of that
invocation. You can learn more about scopes and contexts, and how they are used
from the link:{jakarta-cdi-spec-url}[Specification].
<3> A `public JsonObject getDefaultMessage()` method is defined
which is annotated with `GET`, meaning it will accept the HTTP GET method.
It is also annotated with `Produces(MediaType.APPLICATION_JSON)` which
declares that this method will return JSON data.
<4> The method body creates
a JSON object containing a single object named "message" with the content
"Hello World". This method will be expanded and improved
later in the tutorial.
TIP: So far this is just a JAX-RS application, with no Helidon or MicroProfile
specific code in it. There are many JAX-RS tutorials available if you
want to learn more about this kind of application.
A main class is also required to start up the server and run the
application. If you don't use Helidon's built-in main class you can
define your own:
[source,java]
.src/main/java/io/helidon/examples/Main.java
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_2, indent=0]
----
In this class, a `main` method is defined which starts the Helidon MP
server and prints out a message with the listen address.
<1> Notice that
this class has an empty no-args constructor to make sure this class
cannot be instantiated.
<2> The MicroProfile server is started with the default configuration.
Helidon MP applications also require a `beans.xml` resource file to
tell Helidon to use the annotations discussed above to discover Java
beans in the application.
Create a `beans.xml` in the `src/main/resources/META-INF` directory
with the following content:
[source,xml]
.src/main/resources/META-INF/beans.xml
----
----
<1> The `bean-discovery-mode` tells Helidon to look for the annotations
to discover Java beans in the application.
== Build the Application
Helidon MP applications are packaged into a JAR file and the dependencies
are copied into a `libs` directory.
You can now build the application.
[source,bash]
.Build the Application
----
mvn package
----
This will build the application jar and save all runtime
dependencies in the `target/libs` directory. This means you can easily start the
application by running the application jar file:
[source,bash]
.Run the application
----
java -jar target/helidon-mp-tutorial.jar
----
At this stage, the application is a very simple "Hello World" greeting service.
It supports a single GET request for generating a greeting message.
The response is encoded using JSON.
For example:
[source,bash]
.Try the Application:
----
curl -X GET http://localhost:7001/greet
----
[source, json]
.JSON response:
----
{"message":"Hello World!"}
----
In the output you can see the JSON output from the `getDefaultMessage()`
method that was discussed earlier. The server has used a default port
`7001`. The application can be stopped cleanly by pressing Ctrl+C.
== Configuration
Helidon MP applications can use the `META-INF/microprofile-config.properties`
file to specify configuration data. This file (resource) is read by default
if it is present on the classpath. Create this file in
`src/main/resources/META-INF` with the following content:
[source,bash]
.Initial microprofile-config.properties
----
# Microprofile server properties
server.port=8080
server.host=0.0.0.0
----
Rebuild the application and run it again. Notice that it now uses port
8080 as specified in the configuration file.
TIP: You can learn more about options for configuring the Helidon Server on the
xref:../server.adoc[Server Configuration] page.
In addition to predefined server properties, application-specific
configuration information can be added to this file. Add the `app.greeting`
property to the file as shown below. This property will be used to set the
content of greeting message.
[source,bash]
.Updated META-INF/microprofile-config.properties
----
# Microprofile server properties
server.port=8080
server.host=0.0.0.0
# Application properties
app.greeting=Hello
----
Add a new "provider" class to read this property and make it available
to the application. The class will be called `GreetingProvider.java`
and have the following content:
[source,java]
.src/main/java/io/helidon/examples/GreetingProvider.java
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_3, indent=0]
----
<1> This class also has the `ApplicationScoped` annotation, so it will persist
for the life of the application.
<2> The class contains an `AtomicReference`
to a `String` where the greeting will be stored. The `AtomicReference`
provides lock-free thread-safe access to the underlying `String`.
<3> The `public GreetingProvider(...)` constructor is annotated with `Inject`
which tells Helidon to use Contexts and Dependency Injection to provide
the needed values. In this case, the `String message` is annotated with
`ConfigProperty(name = "app.greeting")` so Helidon will inject the
property from the configuration file with the key `app.greeting`.
This method demonstrates how to read configuration information into
the application. A getter and setter are also included in this class.
The `GreetResource` must be updated to use this value instead of the
hard coded response. Make the following updates to that class:
[source,java]
.Updated GreetResource class
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_4, indent=0]
----
<1> This updated class adds a `GreetingProvider` and uses constructor injection
to get the value from the configuration file.
<2> The logic to create the
response message is refactored into a `createResponse` method and the
`getDefaultMessage()` method is updated to use this new method.
<3> In `createResponse()` the message is obtained from the `GreetingProvider`
which in turn got it from the configuration files.
Rebuild and run the application. Notice that it now uses the greeting
from the configuration file. Change the configuration file and restart
the application, notice that it uses the changed value.
////
==== Dynamic configuration
Helidon also allows applications to consume configuration from multiple
sources and to consume changes to the configuration dynamically, without requiring a restart. Update the main class as follows:
[source,java]
.Updated main class
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_5, indent=0]
----
These updates introduce a new configuration file `conf/mp.yaml` which
can be kept outside the JAR file, and which can be used to provide
additional configuration data and/or to override the data in the
`microprofile-config.properties` which will be packaged in the JAR file.
Layered configuration like this, where the configuration is read from
more than one source with overrides, is commonly used in cases where
you want to have different configurations for different environments
like development, test and production.
TIP: Learn much more about configuration in xref:{rootdir}/se/config/advanced-configuration.adoc[Advanced Configuration Topics].
Create this file with the following content:
[source,yaml]
.Initial mp.yaml configuration file
----
app:
greeting: "Hallo"
----
<1> The new `buildConfig()` method defines two sources for configuration information, first the
new `mp.yaml` file, and this is marked as optional, and has a "polling strategy" of "watch".
The polling strategy tells Helidon to watch for
any updates to this file and to dynamically update the configuration.
The second entry is the `microprofile-config.properties` file from the
classpath.
<2> Notice that the `startServer()` method has been updated to use a
Config Builder, which is implemented in the new method `buildConfig()`.
Rebuild the application and run it. After making some requests, update
the greeting in the `mp.yaml` and observe that new requests pick up
the new value without the need for a restart of the application.
////
TIP: To learn more about Helidon MP configuration please see the
xref:../config/introduction.adoc[Config] section of the documentation.
== Extending the Application
In this section, the application will be extended to add a PUT
resource method which will allow users to update the greeting and a
second GET resource method which will accept a parameter.
Here are the two new methods to add to `GreetResource.java`:
[source,java]
.New methods for GreetResource.java
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_6, indent=0]
----
<1> The first of these two methods implements a new HTTP GET service
that returns JSON, and it has a path parameter. The `Path` annotation
defines the next part of the path to be a parameter named `name`.
In the method arguments the `PathParam("name")` annotation on
`String name` has the effect of passing the parameter from the
URL into this method as `name`.
<2> The second method implements a new HTTP PUT service which produces
and consumes JSON, note the `Consumes` and `PUT` annotations.
It also defines a path of "/greeting". Notice that the method
argument is a `JsonObject`. Inside the method body there is code
to check for the expected JSON, extract the value and update the
message in the `GreetingProvider`.
Rebuild and run the application. Test the new services using curl
commands similar to those shown below:
[source,bash]
.Testing the new services
----
curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}
curl -X GET http://localhost:8080/greet/Joe
{"message":"Hello Joe!"}
curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting
curl -X GET http://localhost:8080/greet/Jose
{"message":"Hola Jose!"}
----
Helidon MP provides many other features which can be added to the application.
== Logging
The application logging can be customized. The default logging provider
is `java.util.logging`, however it is possible to use other providers.
In this tutorial the default provider is used.
Create a `logging.properties` file in `src/main/resources` with
the following content:
[source,properties]
.Example logging.properties file
----
# Send messages to the console
handlers=io.helidon.logging.jul.HelidonConsoleHandler # <1>
# 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 # <2>
# Global logging level. Can be overridden by specific loggers
.level=INFO # <3>
----
<1> The Helidon console logging handler is configured. This handler writes to `System.out`, does not filter by level
and uses a custom `SimpleFormatter` that supports thread names.
<2> The format string is set using the standard options to include the timestamp,
thread name and message.
<3> The global logging level is set to `INFO`.
The Helidon MicroProfile server will detect the new `logging.properties` file and configure
the LogManager for you.
Rebuild and run the application and notice the new logging format takes effect.
[source,bash]
.Log output
----
// before
Aug 22, 2019 11:10:11 AM io.helidon.webserver.LoomWebServer lambda$start$8
INFO: Channel '@default' started: [id: 0xd0afba31, L:/0:0:0:0:0:0:0:0:8080]
Aug 22, 2019 11:10:11 AM io.helidon.microprofile.server.ServerImpl lambda$start$10
INFO: Server started on http://localhost:8080 (and all other host addresses) in 182 milliseconds.
http://localhost:8080/greet
// after
2019.08.22 11:24:42 INFO io.helidon.webserver.LoomServer Thread[main,5,main]: Version: 1.2.0
2019.08.22 11:24:42 INFO io.helidon.webserver.LoomServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0x8f652dfe, L:/0:0:0:0:0:0:0:0:8080]
2019.08.22 11:24:42 INFO io.helidon.microprofile.server.ServerImpl Thread[nioEventLoopGroup-2-1,10,main]: Server started on http://localhost:8080 (and all other host addresses) in 237 milliseconds.
http://localhost:8080/greet
----
== Metrics
Helidon provides built-in support for metrics endpoints.
[source,bash]
.Metrics in Prometheus Format
----
curl -s -X GET http://localhost:8080/metrics
----
[source,bash]
.Metrics in JSON Format
----
curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
----
It is possible to disable metrics by adding properties to the
`microprofile-config.properties` file, for example:
[source,bash]
.Disable a metric
----
metrics.base.classloader.currentLoadedClass.count.enabled=false
----
Call the metrics endpoint before adding this change to confirm that the metric
is included, then add the property to disable the metric, rebuild and restart
the application and check again:
[source,bash]
.Checking metrics before and after disabling the metric
----
# before
curl -s http://localhost:8080/metrics | grep classloader_current
# TYPE base:classloader_current_loaded_class_count counter
# HELP base:classloader_current_loaded_class_count Displays the number of classes that are currently loaded in the Java virtual machine.
base:classloader_current_loaded_class_count 7936
# after
curl -s http://localhost:8080/metrics | grep classloader_current
# (no output)
----
Helidon also support custom metrics. To add a new metric, annotate the
JAX-RS resource with one of the metric annotations as shown in the example
below:
TIP: You can find details of the available annotations in the
link:{microprofile-metrics-spec-url}[MicroProfile Metrics Specification]
[source,java]
.Updated GreetResource.java with custom metrics
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_7, indent=0]
----
<1> The `Timed` annotation is added to the `getDefaultMessage()` method.
Rebuild and run the application. Make some calls to the endpoint
(http://localhost:8080/greet) so there will be some data to report.
Then obtain the application metrics as follows:
[source,bash]
.Checking the application metrics
----
curl -H "Accept: application/json" http://localhost:8080/metrics/application
{
"io.helidon.examples.GreetResource.getDefaultMessage": {
"count": 2,
"meanRate": 0.036565171873527716,
"oneMinRate": 0.015991117074135343,
"fiveMinRate": 0.0033057092356765017,
"fifteenMinRate": 0.0011080303990206543,
"min": 78658,
"max": 1614077,
"mean": 811843.8728029992,
"stddev": 766932.8494434259,
"p50": 78658,
"p75": 1614077,
"p95": 1614077,
"p98": 1614077,
"p99": 1614077,
"p999": 1614077
}
}
----
Learn more about using Helidon and MicroProfile metrics in the xref:metrics.adoc[Metrics Guide].
== Health Check
Helidon provides built-in support for health check endpoints. Obtain
the built-in health check using the following URL:
[source,bash]
.Health check
----
curl -s -X GET http://localhost:8080/health
{
"outcome": "UP",
"status": "UP",
"checks": [
{
"name": "deadlock",
"state": "UP",
"status": "UP"
},
{
"name": "diskSpace",
"state": "UP",
"status": "UP",
"data": {
"free": "381.23 GB",
"freeBytes": 409340088320,
"percentFree": "43.39%",
"total": "878.70 GB",
"totalBytes": 943491723264
}
},
{
"name": "heapMemory",
"state": "UP",
"status": "UP",
"data": {
"free": "324.90 MB",
"freeBytes": 340682920,
"max": "3.46 GB",
"maxBytes": 3715629056,
"percentFree": "97.65%",
"total": "408.00 MB",
"totalBytes": 427819008
}
}
]
}
----
Endpoints for readiness and liveness checks are also provided by default.
Obtain the default results using these URLs, which return the same result as the previous example.:
[source,bash]
.Default readiness and liveness endpoints
----
# readiness
curl -i -X GET http://localhost:8080/health/ready
# liveness
curl -i -X GET http://localhost:8080/health/live
----
Helidon allows the addition of custom health checks to applications.
Create a new class `GreetHealthcheck.java` with the following content:
[source,java]
.src/main/java/io/helidon/examples/GreetHealthcheck.java
----
include::{sourcedir}/mp/guides/MpTutorialSnippets.java[tag=snippet_8, indent=0]
----
<1> This class has the MicroProfile `Liveness` annotation which tells
Helidon that this class provides a custom health check. You can
learn more about the available annotations in the
link:{microprofile-health-spec-url}##_protocol_and_wireformat[MicroProfile Health Protocol and Wireformat] document.
<2> This class also has the `ApplicationScoped` annotation, as seen previously.
<3> The `GreetingProvider` is injected using Context and Dependency
Injection. This example will use the greeting to determine whether
the application is healthy, this is a contrived example for demonstration
purposes.
<4> Health checks must implement the `HealthCheck` functional interface, which
includes the method `HealthCheckResponse call()`. Helidon will invoke the
`call()` method to verify the healthiness of the application.
<5> In this example, the application is deemed to be healthy if the
`GreetingProvider,getMessage()` method returns the string `"Hello"`
and unhealthy otherwise.
Rebuild the application, make sure that the `mp.conf` has the `greeting` set
to something other than `"Hello"` and then run the application and check
the health:
[source,bash]
.Custom health check reporting unhealthy state
----
curl -i -X GET http://localhost:8080/health/live
HTTP/1.1 503 Service Unavailable <1>
Content-Type: application/json
Date: Fri, 23 Aug 2019 10:07:23 -0400
transfer-encoding: chunked
connection: keep-alive
{"outcome":"DOWN","status":"DOWN","checks":[{"name":"deadlock","state":"UP","status":"UP"},{"name":"diskSpace","state":"UP","status":"UP","data":{"free":"381.08 GB","freeBytes":409182306304,"percentFree":"43.37%","total":"878.70 GB","totalBytes":943491723264}},{"name":"greeting","state":"DOWN","status":"DOWN","data":{"greeting":"Hey"}},{"name":"heapMemory","state":"UP","status":"UP","data":{"free":"243.81 MB","freeBytes":255651048,"max":"3.46 GB","maxBytes":3715629056,"percentFree":"98.58%","total":"294.00 MB","totalBytes":308281344}}]} <2>
----
<1> The HTTP return code is now 503 Service Unavailable.
<2> The status is reported as "DOWN" and the custom check is included in
the output.
Now update the greeting to `"Hello"` using the following request, and then
check health again:
[source,bash]
.Update the greeting and check health again
----
# update greeting
curl -i -X PUT -H "Content-Type: application/json" -d '{"greeting": "Hello"}' http://localhost:8080/greet/greeting
HTTP/1.1 204 No Content <1>
Date: Thu, 22 Aug 2019 13:29:57 -0400
connection: keep-alive
# check health
curl -i -X GET http://localhost:8080/health/live
HTTP/1.1 200 OK <2>
Content-Type: application/json
Date: Fri, 23 Aug 2019 10:08:09 -0400
connection: keep-alive
content-length: 536
{"outcome":"UP","status":"UP","checks":[{"name":"deadlock","state":"UP","status":"UP"},{"name":"diskSpace","state":"UP","status":"UP","data":{"free":"381.08 GB","freeBytes":409179811840,"percentFree":"43.37%","total":"878.70 GB","totalBytes":943491723264}},{"name":"greeting","state":"UP","status":"UP","data":{"greeting":"Hello"}},{"name":"heapMemory","state":"UP","status":"UP","data":{"free":"237.25 MB","freeBytes":248769720,"max":"3.46 GB","maxBytes":3715629056,"percentFree":"98.40%","total":"294.00 MB","totalBytes":308281344}}]} <3>
----
<1> The PUT returns an HTTP 204.
<2> The health check now returns an HTTP 200.
<3> The status is now reported as "UP" and the details are provided in the
checks.
Learn more about health checks in the xref:health.adoc[Health Check Guide].
== Build a Docker Image
To run the application in Docker (or Kubernetes), a `Dockerfile` is needed
to build a Docker image. To build the Docker image, you need to have Docker installed and running on your system.
Add a new `Dockerfile` in the project root directory with the following content:
[source,bash]
.Dockerfile content
----
FROM container-registry.oracle.com/java/openjdk:21 as build <1>
# Install maven
WORKDIR /usr/share
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
ADD pom.xml .
RUN mvn package -DskipTests <2>
ADD src src
RUN mvn package -DskipTests <3>
RUN echo "done!"
FROM container-registry.oracle.com/java/openjdk:21
WORKDIR /helidon
COPY --from=build /helidon/target/helidon-mp-tutorial.jar ./ <4>
COPY --from=build /helidon/target/libs ./libs
CMD ["java", "-jar", "helidon-mp-tutorial.jar"] <5>
EXPOSE 8080
----
<1> This Dockerfile uses Docker's multi-stage build feature. The `FROM`
keyword creates the first stage. In this stage, the base container has
the build tools needed to build the application. These are not required
to run the application, so the second stage uses a smaller container.
<2> Add the `pom.xml` and running an "empty" maven build will download
all the dependencies and plugins in this layer. This will make future
builds faster because they will use this cached layer rather than downloading
everything again.
<3> Add the source code and do the real build.
<4> Copy the binary and libraries from the first stage.
<5> Set the initial command and expose port 8080.
To create the Docker image, use the following command:
[source,bash]
.Docker build
----
docker build -t helidon-mp-tutorial .
----
Make sure the application is shutdown if it was still running
locally so that port 8080 will not be in use, then start the application
in Docker using the following command:
[source,bash]
.Run Docker Image
----
docker run --rm -p 8080:8080 helidon-mp-tutorial:latest
----
Try the application as before.
[source,bash]
.Try the application
----
curl http://localhost:8080/greet/bob
{"message":"Howdee bob!"}
curl http://localhost:8080/health/ready
{"outcome":"UP","status":"UP","checks":[]}
----
== Deploy the application to Kubernetes
If you don't have access to a Kubernetes cluster, you can
xref:../../about/kubernetes.adoc[install one on your desktop].
Then deploy the example:
[source,bash]
.Verify connectivity to cluster
----
kubectl cluster-info
kubectl get nodes
----
To deploy the application to Kubernetes, a Kubernetes YAML file that
defines the deployment and associated resources is needed. In this
case all that is required is the deployment and a service.
Create a file called `app.yaml` in the project's root directory with
the following content:
[source,yaml]
.Kubernetes YAML file
----
---
kind: Service # <1>
apiVersion: v1
metadata:
name: helidon-mp-tutorial
labels:
app: helidon-mp-tutorial
spec:
type: NodePort # <2>
selector:
app: helidon-mp-tutorial
ports:
- port: 8080
targetPort: 8080
name: http
---
kind: Deployment # <3>
apiVersion: apps/v1
metadata:
name: helidon-mp-tutorial
spec:
replicas: 1 # <4>
selector:
matchLabels:
app: helidon-mp-tutorial
template:
metadata:
labels:
app: helidon-mp-tutorial
version: v1
spec:
containers:
- name: helidon-mp-tutorial
image: helidon-mp-tutorial # <5>
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
----
<1> Define a Service to provide access to the application.
<2> Define a NodePort to expose the application outside the Kubernetes
cluster.
<3> Define a Deployment of the application.
<4> Define how many replicas of the application to run.
<5> Define the Docker image to use - this must be the one that was built
in the previous step. If the image was built on a different machine to the
one where Kubernetes is running, or if Kubernetes is running on multiple
machines (worker nodes) then the image must either be manually copied to
each node or otherwise pushed to a Docker registry that is accessible to
the worker nodes.
This Kubernetes YAML file can be used to deploy the application to Kubernetes:
[source,bash]
.Deploy the application to Kubernetes
----
kubectl create -f app.yaml
kubectl get pods # Wait for quickstart pod to be RUNNING
----
TIP: Remember, if Kubernetes is running on a different machine, or inside
a VM (as in Docker for Desktop) then the Docker image must either be manually
copied to the Kubernetes worker nodes or pushed to a Docker registry that
is accessible to those worker nodes. Update the `image` entry in the
example above to include the Docker registry name. If the registry is
private a Docker registry secret will also be required.
The step above created a service that is exposed using any available node
port. Kubernetes allocates a free port. Lookup the service to find the port.
[source,bash]
.Lookup the service
----
kubectl get service helidon-mp-tutorial
----
Note the PORTs. The application can be exercised as before but use
the second port number (the NodePort) instead of 8080. For example:
[source,bash]
.Access the application
----
curl -X GET http://localhost:31431/greet
----
If desired, the Kubernetes YAML file can also be used to remove the
application from Kubernetes as follows:
[source,bash]
.Remove the application from Kubernetes
----
kubectl delete -f app.yaml
----
== Summary
This tutorial demonstrated how to build
a new Helidon MP application, how to use Helidon and MicroProfile
configuration, logging, metrics, and health checks. It also demonstrated
how to package the application in a Docker image and run it in Kubernetes.
There were several links to more detailed information included in the
tutorial. These links are repeated below and can be explored to learn
more details about Helidon application development.
== Related links
* https://projects.eclipse.org/projects/technology.microprofile[Eclipse MicroProfile]
* link:{jakarta-cdi-spec-url}[Contexts and Dependency Injection Specification]
* xref:../server.adoc[Server Configuration]
* xref:../config/introduction.adoc[Config]
* link:{microprofile-metrics-spec-url}[MicroProfile Metrics Specification]
* xref:metrics.adoc[Metrics Guide]
* link:{microprofile-health-spec-url}##_protocol_and_wireformat[MicroProfile Health Protocol and Wireformat]
* xref:../../about/kubernetes.adoc[Install Kubernetes on your desktop]
© 2015 - 2025 Weber Informatics LLC | Privacy Policy