Giter Club home page Giter Club logo

docker-javaee's Introduction

Java EE application using MySQL with WildFly Swarm

This repo has a simple Java EE application that publishes a REST endpoint at /resources/employees. The resource returns a list of employees by querying a database.

The Java EE application is deployed as a JAR built using WildFly Swarm. MySQL is used as the backend database.

The application also publishes Prometheus-style metrics at /metrics.

Build application

Build Docker image

mvn -f employees/pom.xml clean package -Pdocker

Docker image used in this application, arungupta/docker-javaee:dockerconeu17, is already published at Docker Hub.

Run application

Using Docker Compose on Swarm mode

docker stack deploy --compose-file=docker-compose.yml webapp

Verify:

$ docker stack ls
NAME                SERVICES
webapp              2
$ docker stack services webapp
ID                  NAME                MODE                REPLICAS            IMAGE                                   PORTS
9tuwp1o2sz4j        webapp_web          replicated          1/1                 arungupta/docker-javaee:dockerconeu17   *:8080->8080/tcp,*:9990->9990/tcp
jy6qyaxv5e01        webapp_db           replicated          1/1                 mysql:8                                 *:3306->3306/tcp
$ docker stack ps webapp
ID                  NAME                IMAGE                                   NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
lbnyvncsnfad        webapp_web.1        arungupta/docker-javaee:dockerconeu17   moby                Running             Running 7 seconds ago
r7j0q1nx1y1q        webapp_db.1         mysql:8                                 moby                Running             Running 9 seconds ago

Using Kubernetes

The application is available as Kubernetes Helm chart in the app directory. Install Helm client and server, and then the application.

Install Helm client and server:

brew install kubernetes-helm
helm init

Install Helm chart:

helm install --name app app

Verify:

$ kubectl get deployments
NAME                DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mysql-deployment    1         1         1            1           1m
webapp-deployment   1         1         1            1           1m
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
db           ClusterIP   100.65.195.189   <none>        3306/TCP   1m
kubernetes   ClusterIP   100.64.0.1       <none>        443/TCP    1h
webapp       ClusterIP   100.71.21.2      <none>        8080/TCP   1m
$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
mysql-deployment-1668503186-9h7lz   1/1       Running   0          1m
webapp-deployment-372583675-hlcbg   1/1       Running   0          1m

Access application

Using Docker

Access the application:

curl http://localhost:8080/resources/employees

The output is shown as:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>

JSON output can be obtained as:

curl -H"Accept: application/json" http://localhost:8080/resources/employees

The output is shown as:

[{"id":1,"name":"Penny"},{"id":2,"name":"Sheldon"},{"id":3,"name":"Amy"},{"id":4,"name":"Leonard"},{"id":5,"name":"Bernadette"},{"id":6,"name":"Raj"},{"id":7,"name":"Howard"},{"id":8,"name":"Priya"}]

Using Kubernetes

Start proxy:

kubectl proxy

Access the application:

curl http://localhost:8001/api/v1/proxy/namespaces/default/services/webapp/resources/employees

Debug

Using Docker

  1. Check the service logs

    docker service logs webapp_web
  2. Remove the application

    docker stack rm webapp

Using Kubernetes

  1. Check the service logs

    kubectl logs <pod-id>
  2. Remove the application

    helm delete app

Prometheus-style metrics

Get application metrics as:

$ curl http://localhost:8080/metrics
# HELP jvm_threads_current Current thread count of a JVM
# TYPE jvm_threads_current gauge
jvm_threads_current 105.0
# HELP jvm_threads_daemon Daemon thread count of a JVM
# TYPE jvm_threads_daemon gauge
jvm_threads_daemon 12.0
# HELP jvm_threads_peak Peak thread count of a JVM
# TYPE jvm_threads_peak gauge
jvm_threads_peak 105.0
# HELP jvm_threads_started_total Started thread count of a JVM
# TYPE jvm_threads_started_total counter
jvm_threads_started_total 138.0
# HELP jvm_threads_deadlocked Cycles of JVM-threads that are in deadlock waiting to acquire object monitors or ownable synchronizers
# TYPE jvm_threads_deadlocked gauge
jvm_threads_deadlocked 0.0
# HELP jvm_threads_deadlocked_monitor Cycles of JVM-threads that are in deadlock waiting to acquire object monitors
# TYPE jvm_threads_deadlocked_monitor gauge
jvm_threads_deadlocked_monitor 0.0
# HELP requests_get_one Total GET /{id} requests.
# TYPE requests_get_one counter
requests_get_one 7.0
# HELP requests_get_all Total GET / requests.
# TYPE requests_get_all counter
requests_get_all 14.0
# HELP jvm_memory_bytes_used Used bytes of a given JVM memory area.
# TYPE jvm_memory_bytes_used gauge
jvm_memory_bytes_used{area="heap",} 1.01012128E8
jvm_memory_bytes_used{area="nonheap",} 1.00972688E8
# HELP jvm_memory_bytes_committed Committed (bytes) of a given JVM memory area.
# TYPE jvm_memory_bytes_committed gauge
jvm_memory_bytes_committed{area="heap",} 2.87309824E8
jvm_memory_bytes_committed{area="nonheap",} 1.08756992E8
# HELP jvm_memory_bytes_max Max (bytes) of a given JVM memory area.
# TYPE jvm_memory_bytes_max gauge
jvm_memory_bytes_max{area="heap",} 4.66092032E8
jvm_memory_bytes_max{area="nonheap",} -1.0
# HELP jvm_memory_pool_bytes_used Used bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_used gauge
jvm_memory_pool_bytes_used{pool="Code Cache",} 1.7550848E7
jvm_memory_pool_bytes_used{pool="Metaspace",} 7.3989384E7
jvm_memory_pool_bytes_used{pool="Compressed Class Space",} 9432456.0
jvm_memory_pool_bytes_used{pool="PS Eden Space",} 3191200.0
jvm_memory_pool_bytes_used{pool="PS Survivor Space",} 2408464.0
jvm_memory_pool_bytes_used{pool="PS Old Gen",} 9.5412464E7
# HELP jvm_memory_pool_bytes_committed Committed bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_committed gauge
jvm_memory_pool_bytes_committed{pool="Code Cache",} 1.769472E7
jvm_memory_pool_bytes_committed{pool="Metaspace",} 7.9740928E7
jvm_memory_pool_bytes_committed{pool="Compressed Class Space",} 1.1321344E7
jvm_memory_pool_bytes_committed{pool="PS Eden Space",} 7.602176E7
jvm_memory_pool_bytes_committed{pool="PS Survivor Space",} 4.8234496E7
jvm_memory_pool_bytes_committed{pool="PS Old Gen",} 1.63053568E8
# HELP jvm_memory_pool_bytes_max Max bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_max gauge
jvm_memory_pool_bytes_max{pool="Code Cache",} 2.5165824E8
jvm_memory_pool_bytes_max{pool="Metaspace",} -1.0
jvm_memory_pool_bytes_max{pool="Compressed Class Space",} 1.073741824E9
jvm_memory_pool_bytes_max{pool="PS Eden Space",} 7.8118912E7
jvm_memory_pool_bytes_max{pool="PS Survivor Space",} 4.8234496E7
jvm_memory_pool_bytes_max{pool="PS Old Gen",} 3.49700096E8
# HELP jvm_classes_loaded The number of classes that are currently loaded in the JVM
# TYPE jvm_classes_loaded gauge
jvm_classes_loaded 13797.0
# HELP jvm_classes_loaded_total The total number of classes that have been loaded since the JVM has started execution
# TYPE jvm_classes_loaded_total counter
jvm_classes_loaded_total 13797.0
# HELP jvm_classes_unloaded_total The total number of classes that have been unloaded since the JVM has started execution
# TYPE jvm_classes_unloaded_total counter
jvm_classes_unloaded_total 0.0
# HELP jvm_info JVM version info
# TYPE jvm_info gauge
jvm_info{version="1.8.0_141-8u141-b15-1~deb9u1-b15",vendor="Oracle Corporation",} 1.0
# HELP app_metrics The time taken fulfilling servlet requests
# TYPE app_metrics histogram
app_metrics_bucket{path="/resources",method="GET",le="0.005",} 13.0
app_metrics_bucket{path="/resources",method="GET",le="0.01",} 17.0
app_metrics_bucket{path="/resources",method="GET",le="0.025",} 20.0
app_metrics_bucket{path="/resources",method="GET",le="0.05",} 20.0
app_metrics_bucket{path="/resources",method="GET",le="0.075",} 20.0
app_metrics_bucket{path="/resources",method="GET",le="0.1",} 20.0
app_metrics_bucket{path="/resources",method="GET",le="0.25",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="0.5",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="0.75",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="1.0",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="2.5",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="5.0",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="7.5",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="10.0",} 21.0
app_metrics_bucket{path="/resources",method="GET",le="+Inf",} 21.0
app_metrics_count{path="/resources",method="GET",} 21.0
app_metrics_sum{path="/resources",method="GET",} 0.3544065799999999
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 44.43
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.508062328635E9
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 500.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1048576.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 4.289380352E9
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 5.36694784E8
# HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc="PS Scavenge",} 28.0
jvm_gc_collection_seconds_sum{gc="PS Scavenge",} 0.373
jvm_gc_collection_seconds_count{gc="PS MarkSweep",} 6.0
jvm_gc_collection_seconds_sum{gc="PS MarkSweep",} 0.565

OpenTracing/Jaeger

The application traces all requests to Jaeger (https://uber.github.io/jaeger/) and the result can be viewed on http://127.0.0.1:8090.

jaeger screenshot

docker-javaee's People

Contributors

arun-gupta avatar enbohm avatar mikesir87 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

docker-javaee's Issues

OpenJDK 9 JRE Slim base image throws NoClassDefFoundError

Using openjdk:9-b181-jre-slim throws the following exception. 8-jre-slim works fine.

webapp_web.1.lgprfpvebods@moby    | WARNING: An illegal reflective access operation has occurred
webapp_web.1.lgprfpvebods@moby    | WARNING: Illegal reflective access by org.jboss.modules.ClassLoaderLocalLoader$1 (file:/opt/docker-javaee-swarm.jar) to method java.lang.ClassLoader.getPackage(java.lang.String)
webapp_web.1.lgprfpvebods@moby    | WARNING: Please consider reporting this to the maintainers of org.jboss.modules.ClassLoaderLocalLoader$1
webapp_web.1.lgprfpvebods@moby    | WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
webapp_web.1.lgprfpvebods@moby    | WARNING: All illegal access operations will be denied in a future release
webapp_web.1.lgprfpvebods@moby    | Exception in thread "main" java.lang.reflect.InvocationTargetException
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.bootstrap.Main.invoke(Main.java:84)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.bootstrap.Main.run(Main.java:48)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.bootstrap.Main.main(Main.java:43)
webapp_web.1.lgprfpvebods@moby    | Caused by: java.lang.NoClassDefFoundError: jdk/internal/reflect/ConstructorAccessorImpl
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.misc.Unsafe.defineClass0(Native Method)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.misc.Unsafe.defineClass(Unsafe.java:1173)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.ClassDefiner.defineClass(ClassDefiner.java:63)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:400)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/java.security.AccessController.doPrivileged(Native Method)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.MethodAccessorGenerator.generateConstructor(MethodAccessorGenerator.java:92)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:55)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
webapp_web.1.lgprfpvebods@moby    | 	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.api.SecurityActions.newInstance(SecurityActions.java:132)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.api.ArchivePaths.createInstance(ArchivePaths.java:125)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.api.ArchivePaths.create(ArchivePaths.java:63)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.impl.base.importer.zip.ZipImporterImpl.importFrom(ZipImporterImpl.java:125)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.impl.base.importer.zip.ZipImporterImpl.importFrom(ZipImporterImpl.java:103)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.shrinkwrap.impl.base.importer.zip.ZipImporterImpl.importFrom(ZipImporterImpl.java:49)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.spi.api.DefaultDeploymentFactory.setupUsingAppArtifact(DefaultDeploymentFactory.java:120)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.spi.api.DefaultDeploymentFactory.setup(DefaultDeploymentFactory.java:50)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.jaxrs.internal.DefaultJAXRSWarDeploymentFactory.create(DefaultJAXRSWarDeploymentFactory.java:41)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.createDefaultDeployment(Container.java:491)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.getDefaultDeployment(Container.java:503)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.getDefaultDeploymentURL(Container.java:516)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.getDefaultDeploymentClassLoader(Container.java:531)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.setupXmlConfig(Container.java:364)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.start(Container.java:330)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.start(Swarm.java:97)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.start(Swarm.java:45)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.container.Container.start(Container.java:324)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.start(Swarm.java:107)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.start(Swarm.java:45)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.simpleMain(Swarm.java:149)
webapp_web.1.lgprfpvebods@moby    | 	at org.wildfly.swarm.Swarm.main(Swarm.java:141)
webapp_web.1.lgprfpvebods@moby    | 	... 7 more
webapp_web.1.lgprfpvebods@moby    | Caused by: java.lang.ClassNotFoundException: jdk.internal.reflect.ConstructorAccessorImpl from [Module "org.jboss.shrinkwrap:impl" from BootModuleLoader@4f2b503c for finders [BootstrapClasspathModuleFinder, BootstrapModuleFinder(org.wildfly.swarm.bootstrap:main), ClasspathModuleFinder, ApplicationModuleFinder(swarm.application:main), FlattishApplicationModuleFinder(swarm.application:flattish)]]
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:363)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:351)
webapp_web.1.lgprfpvebods@moby    | 	at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:93)
webapp_web.1.lgprfpvebods@moby    | 	... 40 more

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.