Application Deployment Guide
Overview
Developing and deploying an application to Verrazzano consists of:
- Packaging the application as a Docker image.
- Publishing the application’s Docker image to a container registry.
- Applying the application’s Verrazzano components to the cluster.
- Applying the application’s Verrazzano applications to the cluster.
This guide does not provide the full details for the first two steps. An existing example application Docker image has been packaged and published for use.
Verrazzano supports application definition using Open Application Model (OAM). Verrrazzano applications are composed of components and application configurations. This document demonstrates creating OAM resources that define an application as well as the steps required to deploy those resources.
What you need
-
About 10 minutes.
-
Access to an existing Kubernetes cluster with Verrazzano installed.
-
Access to the application’s image in GitHub Container Registry.
Confirm access using this command to pull the example’s Docker image:
$ docker pull ghcr.io/verrazzano/example-helidon-greet-app-v1:0.1.12-1-20210218160249-d8db8f3
Application development
This guide uses an example application which was written with Java and Helidon. For the implementation details, see the Helidon MP tutorial. See the application source code in the Verrazzano examples repository.
The example application is a JAX-RS service and implements the following REST endpoints:
/greet
- Returns a default greeting message that is stored in memory. This endpoint accepts theGET
HTTP request method./greet/{name}
- Returns a greeting message including the name provided in the path parameter. This endpoint accepts theGET
HTTP request method./greet/greeting
- Changes the greeting message to be used in future calls to the other endpoints. This endpoint accepts thePUT
HTTP request method and a JSON payload.
The following code shows a portion of the application’s implementation.
The Verrazzano examples repository contains the complete implementation.
An important detail here is that the application contains a single resource exposed on path /greet
.
package io.helidon.examples.quickstart.mp;
...
@Path("/greet")
@RequestScoped
public class GreetResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public JsonObject getDefaultMessage() {
...
}
@Path("/{name}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public JsonObject getMessage(@PathParam("name") String name) {
...
}
@Path("/greeting")
@PUT
@Consumes(MediaType.APPLICATION_JSON)
...
public Response updateGreeting(JsonObject jsonObject) {
...
}
}
A Dockerfile is used to package the completed application JAR file into a Docker image. The following code shows a portion of the Dockerfile. The Verrazzano examples repository contains the complete Dockerfile. Note that the Docker container exposes a single port 8080.
FROM ghcr.io/oracle/oraclelinux:7-slim
...
CMD java -cp /app/helidon-quickstart-mp.jar:/app/* io.helidon.examples.quickstart.mp.Main
EXPOSE 8080
Application deployment
When you deploy applications with Verrazzano, the platform sets up connections, network policies, and ingresses in the service mesh, and wires up a monitoring stack to capture the metrics, logs, and traces. Verrazzano employs OAM Components to define the functional units of a system that are then assembled and configured by defining associated application configurations.
Verrazzano components
A Verrazzano OAM Component is a Kubernetes Custom Resource describing an application’s general composition and environment requirements. The following code shows the component for the example application used in this guide. This resource describes a component which is implemented by a single Docker image containing a Helidon application exposing a single endpoint.
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: hello-helidon-component
namespace: hello-helidon
spec:
workload:
apiVersion: oam.verrazzano.io/v1alpha1
kind: VerrazzanoHelidonWorkload
metadata:
name: hello-helidon-workload
labels:
app: hello-helidon
spec:
deploymentTemplate:
metadata:
name: hello-helidon-deployment
podSpec:
containers:
- name: hello-helidon-container
image: "ghcr.io/verrazzano/example-helidon-greet-app-v1:0.1.10-3-20201016220428-56fb4d4"
ports:
- containerPort: 8080
name: http
A brief description of each field of the component:
apiVersion
- Version of the component custom resource definitionkind
- Standard name of the component custom resource definitionmetadata.name
- The name used to create the component’s custom resourcemetadata.namespace
- The namespace used to create this component’s custom resourcespec.workload.kind
-VerrazzanoHelidonWorkload
defines a stateless workload of Kubernetesspec.workload.spec.deploymentTemplate.podSpec.metadata.name
- The name used to create the stateless workload of Kubernetesspec.workload.spec.deploymentTemplate.podSpec.containers
- The implementation containersspec.workload.spec.deploymentTemplate.podSpec.containers.ports
- Ports exposed by the container
Verrazzano application configurations
A Verrazzano application configuration is a
Kubernetes Custom Resource
which provides environment specific customizations.
The following code shows the application configuration for the example used in this guide.
This resource specifies the deployment of the application to the hello-helidon
namespace. Additional runtime features are
specified using traits, or runtime overlays that augment the workload. For example, the ingress trait specifies the
ingress host and path, while the metrics trait optionally provides the Prometheus scraper used to obtain the
application related metrics. If no metrics trait is specified, the Verrazzano-supplied Prometheus component is used by default.
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
name: hello-helidon-appconf
namespace: hello-helidon
annotations:
version: v1.0.0
description: "Hello Helidon application"
spec:
components:
- componentName: hello-helidon-component
traits:
- trait:
apiVersion: oam.verrazzano.io/v1alpha1
kind: MetricsTrait
spec:
scraper: <optionally specify custom scraper>
- trait:
apiVersion: oam.verrazzano.io/v1alpha1
kind: IngressTrait
metadata:
name: hello-helidon-ingress
spec:
rules:
- paths:
- path: "/greet"
pathType: Prefix
A brief description of each field in the application configuration:
apiVersion
- Version of theApplicationConfiguration
custom resource definitionkind
- Standard name of the application configuration custom resource definitionmetadata.name
- The name used to create this application configuration resourcemetadata.namespace
- The namespace used for this application configuration custom resourcespec.components
- Reference to the application’s components leveraged to specify runtime configurationspec.components[].traits
- The traits specified for the application’s components
To explore traits, we can examine the fields of an ingress trait:
apiVersion
- Version of the OAM trait custom resource definitionkind
-IngressTrait
is the name of the OAM application ingress trait custom resource definitionspec.rules.paths
- The context paths for accessing the application
Deploy the application
The following steps are required to deploy the example application.
Steps similar to the apply
steps would be used to deploy any application to Verrazzano.
-
Create a namespace for the example application and add labels identifying the namespace as managed by Verrazzano and enabled for Istio.
$ kubectl create namespace hello-helidon $ kubectl label namespace hello-helidon verrazzano-managed=true istio-injection=enabled
-
Apply the application’s component.
$ kubectl apply -f https://raw.githubusercontent.com/verrazzano/verrazzano/v1.4.8/examples/hello-helidon/hello-helidon-comp.yaml -n hello-helidon
This step causes the validation and creation of the Component resource. No other resources or objects are created as a result. Application configurations applied in the future may reference this Component resource.
-
Apply the application configuration.
$ kubectl apply -f https://raw.githubusercontent.com/verrazzano/verrazzano/v1.4.8/examples/hello-helidon/hello-helidon-app.yaml -n hello-helidon
This step causes the validation and creation of the application configuration resource. This operation triggers the activation of a number of Verrazzano operators. These operators create other Kubernetes objects (for example, Deployments, ReplicaSets, Pods, Services, Ingresses) that collectively provide and support the application.
-
Configure the application’s DNS resolution.
After deploying the application, configure DNS to resolve the application’s ingress DNS name to the application’s load balancer IP address. The generated host name is obtained by querying Kubernetes for the gateway:
$ kubectl get gateways.networking.istio.io hello-helidon-hello-helidon-gw \ -n hello-helidon \ -o jsonpath='{.spec.servers[0].hosts[0]}'
The load balancer IP is obtained by querying Kubernetes for the Istio ingress gateway status:
$ kubectl get service \ -n istio-system istio-ingressgateway \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
DNS configuration steps are outside the scope of this guide. For DNS infrastructure that can be configured and used, see the Oracle Cloud Infrastructure DNS documentation. In some small non-production scenarios, DNS configuration using
/etc/hosts
or an equivalent may be sufficient.
Verify the deployment
Applying the application configuration initiates the creation of several Kubernetes objects. Actual creation and initialization of these objects occurs asynchronously. The following steps provide commands for determining when these objects are ready for use.
Note: Many other Kubernetes objects unrelated to the example application may also exist. Those have been omitted from the lists.
-
Verify the Helidon application pod is running.
$ kubectl get pods -n hello-helidon -l app=hello-helidon # Sample output NAME READY STATUS RESTARTS AGE hello-helidon-deployment-8664954995-wcb9d 2/2 Running 0 5m5s
-
Verify that the Verrazzano application operator pod is running.
$ kubectl get pod -n verrazzano-system -l app=verrazzano-application-operator # Sample output NAME READY STATUS RESTARTS AGE verrazzano-application-operator-79849b89ff-lr9w6 1/1 Running 0 13m
The namespace
verrazzano-system
is used by Verrazzano for non-application objects managed by Verrazzano. A singleverrazzano-application-operator
manages the life cycle of all OAM based applications within the cluster. -
Verify the Verrazzano monitoring infrastructure is running.
$ kubectl get pods -n verrazzano-system | grep '^NAME\|vmi-system' # Sample output NAME READY STATUS RESTARTS AGE vmi-system-es-master-0 2/2 Running 0 47m vmi-system-grafana-799d79648d-wsdp4 2/2 Running 0 47m vmi-system-kiali-574c6dd94d-f49jv 2/2 Running 0 51m vmi-system-kibana-77f8d998f4-zzvqr 2/2 Running 0 47m
$ kubectl get pods -n verrazzano-monitoring # Sample output NAME READY STATUS RESTARTS AGE prometheus-node-exporter-fstc7 1/1 Running 0 14h prometheus-operator-kube-p-operator-857fb66b74-szv4h 1/1 Running 0 14h prometheus-prometheus-operator-kube-p-prometheus-0 3/3 Running 0 14h
These pods in the
verrazzano-system
andverrazzano-monitoring
namespaces constitute a monitoring stack created by Verrazzano for the deployed applications.The monitoring infrastructure comprises several components:
vmi-system-es
- OpenSearch for log collectionvmi-system-grafana
- Grafana for metric visualizationvms-system-kiali
- Kiali for management console ofistio
service meshvmi-system-kibana
- OpenSearch Dashboards for log visualizationprometheus-prometheus-operator-kube-p-prometheus
- Prometheus for metric collection
-
Diagnose failures.
View the event logs of any pod not entering the
Running
state within a reasonable length of time, such as five minutes.$ kubectl describe pod -n hello-helidon -l app=hello-helidon
Use the specific namespace and name for the pod being investigated.
Explore the application
Follow these steps to explore the application’s functionality. If DNS was not configured, then use the alternative commands.
-
Save the host name and IP address of the load balancer exposing the application’s REST service endpoints for later.
$ HOST=$(kubectl get gateways.networking.istio.io hello-helidon-hello-helidon-gw \ -n hello-helidon \ -o jsonpath='{.spec.servers[0].hosts[0]}') $ ADDRESS=$(kubectl get service \ -n istio-system istio-ingressgateway \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
NOTE:
- The value of
ADDRESS
is used only if DNS has not been configured. - The following alternative commands may not work in conjunction
with firewalls that validate
HTTP Host
headers.
- The value of
-
Get the default message.
$ curl -sk \ -X GET \ "https://${HOST}/greet" # Expected response {"message":"Hello World!"}
If DNS has not been configured, then use this command.
$ curl -sk \ -X GET \ "https://${HOST}/greet" \ --resolve ${HOST}:443:${ADDRESS}
-
Get a message for Robert.
$ curl -sk \ -X GET \ "https://${HOST}/greet/Robert" # Expected response {"message":"Hello Robert!"}
If DNS has not been configured, then use this command.
$ curl -sk \ -X GET "https://${HOST}/greet/Robert" \ --resolve ${HOST}:443:${ADDRESS}
-
Update the default greeting.
$ curl -sk \ -X PUT \ "https://${HOST}/greet/greeting" \ -H 'Content-Type: application/json' \ -d '{"greeting" : "Greetings"}'
If DNS has not been configured, then use this command.
$ curl -sk \ -X PUT \ "https://${HOST}/greet/greeting" \ -H 'Content-Type: application/json' \ -d '{"greeting" : "Greetings"}' \ --resolve ${HOST}:443:${ADDRESS}
-
Get the new message for Robert.
$ curl -sk \ -X GET \ "https://${HOST}/greet/Robert" # Expected response {"message":"Greetings Robert!"}
If DNS has not been configured, then use this command.
$ curl -sk \ -X GET \ "https://${HOST}/greet/Robert" \ --resolve ${HOST}:443:${ADDRESS}
Access the application’s logs
Deployed applications have log collection enabled. These logs are collected using OpenSearch and can be accessed using OpenSearch Dashboards. OpenSearch and OpenSearch Dashboards are examples of infrastructure Verrazzano creates in support of an application as a result of applying an application configuration. For more information on creating an index pattern and visualizing the log data collected in OpenSearch, see OpenSearch Dashboards.
Determine the URL to access OpenSearch Dashboards:
$ OSD_HOST=$(kubectl get ingress \
-n verrazzano-system vmi-system-kibana \
-o jsonpath='{.spec.rules[0].host}')
$ OSD_URL="https://${OSD_HOST}"
$ echo "${OSD_URL}"
$ open "${OSD_URL}"
The user name to access OpenSearch Dashboards defaults to verrazzano
during the Verrazzano installation.
Determine the password to access OpenSearch Dashboards:
$ echo $(kubectl get secret \
-n verrazzano-system verrazzano \
-o jsonpath={.data.password} | base64 \
--decode)
Access the application’s metrics
Deployed applications have metric collection enabled. Grafana can be used to access these metrics collected by Prometheus. Prometheus and Grafana are additional components Verrazzano creates as a result of applying an application configuration. For more information on visualizing Prometheus metrics data, see Grafana.
Determine the URL to access Grafana:
$ GRAFANA_HOST=$(kubectl get ingress \
-n verrazzano-system vmi-system-grafana \
-o jsonpath='{.spec.rules[0].host}')
$ GRAFANA_URL="https://${GRAFANA_HOST}"
$ echo "${GRAFANA_URL}"
$ open "${GRAFANA_URL}"
The user name to access Grafana is set to the default value verrazzano
during the Verrazzano installation.
Determine the password to access Grafana:
$ echo $(kubectl get secret \
-n verrazzano-system verrazzano \
-o jsonpath={.data.password} | base64 \
--decode)
Alternatively, metrics can be accessed directly using Prometheus. Determine the URL for this access:
$ PROMETHEUS_HOST=$(kubectl get ingress \
-n verrazzano-system vmi-system-prometheus \
-o jsonpath='{.spec.rules[0].host}')
$ PROMETHEUS_URL="https://${PROMETHEUS_HOST}"
$ echo "${PROMETHEUS_URL}"
$ open "${PROMETHEUS_URL}"
The user name and password for both Prometheus and Grafana are the same.
Suppress Kiali console warnings
For some applications, the Kiali console may show warnings for VirtualService and Gateway objects that replicate hostname/port configurations across multiple IngressTraits. These warnings do not impact functionality and can be suppressed with the following component override:
kiali:
overrides:
- values:
kiali_feature_flags:
validations:
ignore: ["KIA1106", "KIA0301"]
Remove the application
Run the following commands to delete the application configuration, and optionally the component and namespace.
-
Delete the application configuration.
$ kubectl delete -f https://raw.githubusercontent.com/verrazzano/verrazzano/v1.4.8/examples/hello-helidon/hello-helidon-app.yaml
The deletion of the application configuration will result in the destruction of all application-specific Kubernetes objects.
-
(Optional) Delete the application’s component.
$ kubectl delete -f https://raw.githubusercontent.com/verrazzano/verrazzano/v1.4.8/examples/hello-helidon/hello-helidon-comp.yaml
Note: This step is not required if other application configurations for this component will be applied in the future.
-
(Optional) Delete the namespace.
$ kubectl delete namespace hello-helidon
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.