Skip to content

luszczynski/quarkus-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Quarkus Demo

This demo is based on Burr Sutter presentation on Voxxed Days.

Overview

Demo Setup

Before jumping into the demo, open:

Local Development

Backend API

Creating our backend using Quarkus

Let’s created our first quarkus application. For this, open vscode, press Ctrl + Shift + p or Command + Shift + p on Mac and select Quarkus: Generate a Maven Project.

We will be asked to fill some information about group-id, artifact-id, etc. Use the following values:

  • groupId: com.redhat.quarkusdemo

  • artifactId: todo-backend

  • version: 1.0.0-SNAPSHOT

  • package name: com.redhat.quarkusdemo

  • resource name: GreetingResource

15
Tip
You can create your quarkus application using the code generator as well.
4 7 2020 17 22 41 PM

Choosing our initial extensions

Now we need to select which extension we would like to use. For now, let’s skip this step by leaving 1 extensions selected

28

Select a folder to save your project

Choose your $HOME/Downloads as this project will be temporary and click on button Generate Here.

5 7 2020 09 12 46 AM

If you generated your code using the quarkus code generator, save your zip file and unzip it in the Downloads folder.

Showing Java Pack Extension for VSCode

Before moving on with our demo, we need to make sure if java pack extension is installed in our vscode environment. Click on Extensions icon.

02

Then search for java:

03

And make sure it is installed.

04
05

Open our Greeting REST endpoint

Open the generated Greeting REST endpoint.

5 7 2020 09 15 09 AM

Hot Reload

Let’s run our quarkus app. Press Ctrl + Shift + ` or Control + `` ` ` on MacOS to open the vscode integrated terminal and run:

./mvnw compile quarkus:dev
38

After running this command, we should see something like this in our integrated terminal.

07
Note
Notice the time that was necessary to start. Super fast and we are not using native mode yet.

Now open your browser on http://localhost:8080/hello

08
Tip
You can also click on the URL above the hello method.
5 7 2020 10 30 55 AM

Now change the hello method to return something else.

package com.redhat.demoquarkus;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello from quarkus"; (1)
    }
}
  1. Change from hello to hello from quarkus

Save your file and refresh your browser.

09

Now you have an app that reload as fast as a nodejs application.

Testing our endpoint

Let’s test our endpoint. For that, open GreetingResourceTest.java.

4 7 2020 13 59 15 PM

Then, click on Run Test.

11

When we run our test, it should not pass because our body content was changed in our rest endpoint but not in our test.

Note
If for some reason you find an error like Error: No delegateCommandHandler for vscode.java.checkProjectSettings, then restart your vscode and you are good to go.
12

Change the test body content according to our endpoint.

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("hello from quarkus"));(1)
    }
  1. Change from hello to hello from quarkus

Now, run again our test and you should have passed on our endpoint test.

13

Adding extensions

Press again Ctrl + Shift + p or Command + Shift + p on Mac and search for Quarkus: Add extensions to the current project.

16

Now, select:

  • Hibernate ORM with Panache

  • RESTEasy JSON-B

  • JDBC Driver - PostgreSQL

  • REST resources for Hibernate ORM with Panache

5 7 2020 11 38 19 AM

And press Enter to finish.

Your integrated terminal, should look like this after hitting enter.

31

You can also search extensions using the CLI.

# For maven
mvn quarkus:list-extensions
# or for gradle
gradle list-extensions

Add hibernate panache, jsonb, postgresql and rest datasource extensions using:

mvn quarkus:add-extension -Dextensions=quarkus-hibernate-orm-panache,quarkus-resteasy-jsonb,quarkus-jdbc-postgresql,quarkus-hibernate-orm-rest-data-panache
14

If you look at you pom.xml, you will see this last command added some new dependencies for us.

15

We should see now that new installed features are avaiable

39

Creating Todo Entity

Create a new entity Todo inside our demoquarkus folder.

Jul 09 2020 14 07 54

Now, we need to add some JPA annotations and also extends our class from PanacheEntity.

02

For now, let’s just add a single field named title to our entity.

03

Here is our entity

package com.redhat.demoquarkus;

import javax.persistence.Entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

/**
 * Todo
 */
@Entity
public class Todo extends PanacheEntity {
    public String title;
}

Postgresql

To create a database for this demo, we’ll use podman but you can also use docker if you like it.

Open a terminal and run:

# For Podman
podman run \
    --rm \
    --name postgres \
    -p 5432:5432 \
    -e POSTGRES_USER=admin \ (1)
    -e POSTGRES_PASSWORD=redhat \ (2)
    -e POSTGRES_DB=todo \ (3)
    postgres:10

# Or Docker
docker run \
    --rm \
    --name postgres \
    -p 5432:5432 \
    -e POSTGRES_USER=admin \ (1)
    -e POSTGRES_PASSWORD=redhat \ (2)
    -e POSTGRES_DB=todo \ (3)
    postgres:10
  1. Database username

  2. Database password

  3. Database name

If everything worked as expected, you should see that your database is ready to accept connections.

23

Connecting to a database

Open application.properties and generate a generic datasource configuration using the snippet qds.

23

Change the generated values to look like the following content:

%dev.quarkus.datasource.db-kind=postgresql (1)
%dev.quarkus.datasource.username=admin
%dev.quarkus.datasource.password=redhat
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/todo
%dev.quarkus.datasource.jdbc.min-size=5
%dev.quarkus.datasource.jdbc.max-size=15
%dev.quarkus.hibernate-orm.database.generation=drop-and-create

quarkus.http.cors=true (2)
  1. We are using the %dev prefix in every line. This is part of the quarkus profile and it tells quarkus to only apply this configuration when running in dev mode (mvn compile quarkus:dev)

  2. As we do not specify %dev this property will be avaiable in dev and prod mode

Note
Update these variables according to your environment.
16
Checking your database

Now, let’s refresh our page on the browser.

17

If we look now at our database, quarkus should already created a new table. You can check this out using

docker exec -it postgres /usr/bin/psql -d todo -U admin -c "\dt"

docker exec -it postgres /usr/bin/psql -d todo -U admin -c "select * from public.todo"
5 7 2020 11 25 30 AM

Let’s describe the table

docker exec -it postgres /usr/bin/psql -d todo -U admin -c "\d+ todo"
5 7 2020 11 26 34 AM

We need to add some more fields to our entity. Let’s do that.

04

The final entity should look like this

package com.redhat.demoquarkus;

import javax.persistence.Column;
import javax.persistence.Entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

/**
 * Todo
 */
@Entity
public class Todo extends PanacheEntity {
    public String title;
    public boolean completed;
    @Column(name = "ordering")
    public int order;
}
Note
We have changed our column name for the field order because it may conflict with some reserved words used by the database.

Run again the describe table command

docker exec -it postgres /usr/bin/psql -d todo -U admin -c "\d+ todo"
5 7 2020 11 28 08 AM

Syntax Errors

Let’s say that we forgot to add the semi-colon in the end of our entitys last line.

...
public class Todo extends PanacheEntity {
    public String title;
    public boolean completed;
    @Column(name = "ordering")
    public int order (1)
}
  1. Forgot to add the semi-colon

Now, open our browser and let’s see how quarkus handle this kind of situation. Refresh your page.

19

Correct your code, and hit refresh one more time.

Creating our todo resource

Create a new interface TodoResource.java.

Tip
You can use a code snippet qrc to create a new rest resource. You can see all snippets in the vscode extension repository.
Jul 10 2020 11 45 27
Jul 10 2020 11 48 36

Now, let’s make it a CRUD REST endpoint by extending it.

5 7 2020 11 51 46 AM

The final TodoResource that will be generated automatily by quarkus should be similar to this class

Warning
Do not copy the following class. It’s only an example.
package com.redhat.quarkusdemo;

import java.util.List;

import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

/**
 * TodoResource
 */
@Path("/todo")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TodoResource {

    @GET
    public List<Todo> getAll() {
        return Todo.listAll();
    }

    @POST
    @Transactional
    public Response create(Todo item){
        item.persist();
        return Response.ok(item).status(201).build();
    }

    @DELETE
    @Transactional
    @Path("/{id}")
    public Response deleteOne(@PathParam("id") Long id) {
        Todo entity = Todo.findById(id);
        entity.delete();

        return Response.status(204).build();
    }

    @PATCH
    @Transactional
    @Path("/{id}")
    public Response update(Todo item, @PathParam("id") Long id) {
        Todo entity = Todo.findById(id);
        entity.id = item.id;
        entity.title = item.title;
        entity.completed = item.completed;
        entity.order = item.order;

        return Response.status(200).build();
    }
}

Now, change your application.properties to add the prod profile.

# Dev environment
%dev.quarkus.datasource.db-kind=postgresql
%dev.quarkus.datasource.username=admin
%dev.quarkus.datasource.password=redhat
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/todo
%dev.quarkus.datasource.jdbc.min-size=5
%dev.quarkus.datasource.jdbc.max-size=15
%dev.quarkus.hibernate-orm.database.generation=drop-and-create

quarkus.http.cors=true

# Production environment
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.username=admin
%prod.quarkus.datasource.password=redhat
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://postgresql:5432/todo
%prod.quarkus.datasource.jdbc.min-size=5
%prod.quarkus.datasource.jdbc.max-size=15
%prod.quarkus.hibernate-orm.database.generation=update

Test your todo app and make sure it is working correctly.

Bean Validation

Let’s update our Todo class to avoid blank title.

13

OpenAPI, Swagger and Health Check Extensions

We can use swagger in our API. For that, we need to add a new extension:

Tip
Remember you can also add these two extensions below using Ctrl + Shift + p or Command + Shift + p on Mac
mvn quarkus:add-extension -Dextensions="quarkus-smallrye-openapi"

Restart quarkus and then open http://localhost:8080/swagger-ui/

26

Now you can test all the four CRUD operations using swagger-ui.

14

It’s important also to monitor the health check of our application. For that, add the smallrye-health-extension

mvn quarkus:add-extension -Dextensions="quarkus-smallrye-health"

Restart your quarkus and open http://localhost:8080/health to see your health check.

27

Packaging our app

Normal Jar

Now let’s package our app.

# Package
mvn package -DskipTests

# List files
ls -lha target/

As you can see, our final jar is small because its libs is in other folders.

5 7 2020 15 04 47 PM
Fat Jar

Now let’s add a new property to allow quarkus generate a uber-jar.

# Dev environment
%dev.quarkus.datasource.db-kind=postgresql
%dev.quarkus.datasource.username=admin
%dev.quarkus.datasource.password=redhat
%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/todo
%dev.quarkus.datasource.jdbc.min-size=5
%dev.quarkus.datasource.jdbc.max-size=15
%dev.quarkus.hibernate-orm.database.generation=drop-and-create

quarkus.http.cors=true

# Production environment
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.username=admin
%prod.quarkus.datasource.password=redhat
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://postgresql:5432/todo
%prod.quarkus.datasource.jdbc.min-size=5
%prod.quarkus.datasource.jdbc.max-size=15
%prod.quarkus.hibernate-orm.database.generation=update

quarkus.package.uber-jar=true (1)
  1. add this line

# Package
mvn package -DskipTests

# List files
ls -lha target/

Our jar is now bigger because it has its dependency in the same package

5 7 2020 15 10 21 PM

Test your todo app

# Run it
java -jar target/todo-backend-1.0.0-SNAPSHOT-runner.jar

We will face an error regarding UnknownHostException. This is happening because when we package our application it runs as prod profile.

0 7 2020 10 37 48 AM

We can change the profile:

java -Dquarkus.profile=dev -jar target/todo-backend-1.0.0-SNAPSHOT-runner.jar
5 7 2020 15 24 14 PM

Get java PID:

JAVA_DEMO_PID=$(ps aux | grep java | grep todo-backend | awk '{ print $2}' | head -1)

Now check how much resource it’s been used by this java process:

ps -o pid,rss -p $JAVA_DEMO_PID | awk 'NR>1 {$2=int($2/1024)"M";}{ print;}'
Native
# Without container
./mvnw package \
    -Pnative \
    -DskipTests

# Docker
./mvnw package \
    -Pnative \
    -Dquarkus.native.container-runtime=docker \
    -DskipTests

# Podman
./mvnw package \
    -Pnative \
    -Dquarkus.native.container-runtime=podman \
    -DskipTests

Run our app:

./target/todo-backend-1.0.0-SNAPSHOT-runner -Dquarkus.profile=dev
5 7 2020 18 34 34 PM

Now, let’s check how much memory our native instance is using.

JAVA_DEMO_PID=$(ps aux | grep todo-backend | grep runner | awk '{ print $2}' | head -1)
ps -o pid,rss -p $JAVA_DEMO_PID | awk 'NR>1 {$2=int($2/1024)"M";}{ print;}'
5 7 2020 18 37 46 PM

Frontend

cd /tmp && git clone https://github.com/luszczynski/quarkus-demo.git && cd quarkus-demo/todo-frontend
npm install && npm run dev

Open http://localhost:8081 to see if it is working properly.

Openshift Demo Deploy

Let’s deploy our application to Openshift.

Postgresql

First, we need to deploy postgresql on Openshift. This is very simple.

oc new-project todo

Switch to the Developer Console:

22

Now, choose the database category.

33

Choose Postgresql (Ephemeral) from the catalog.

34

Fill in the information as below

  • Memory Limit: 512Mi

  • Namespace: openshift

  • Database Service Name: postgresql

  • PostgreSQL Connection Username: admin

  • PostgreSQL Connection Password: redhat

  • PostgreSQL Database Name: todo

  • Version of PostgreSQL Image: 10

35

We should see the following screen

36

If we click on Topology on the left menu, we have the same blue circle we had on OCP v3.11.

37

Quarkus Deploy

Native mode

Native Binary deployment
# Using maven
./mvnw clean package -Dquarkus.container-image.build=true
./mvnw clean package -Dquarkus.kubernetes.deploy=true

# Using odo
odo project create todo
odo create java:11 todo-backend-native \
    --binary target/todo-backend-1.0.0-SNAPSHOT-runner \
    --app todo \
    --env QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://postgresql:5432/todo
odo url create --port 8080
odo push

# Using oc
oc new-build quay.io/quarkus/ubi-quarkus-native-binary-s2i:19.2.1 --binary --name=todo-backend -l app=todo -n todo
oc start-build todo-backend --from-file target/*-runner --follow -n todo-app
oc new-app todo-backend && oc expose svc/todo-backend -n todo-app
oc rollout status -w dc/todo-backend
Native Source-to-image deployment
oc new-build --binary --name=quarkus-project -l app=quarkus-project
oc patch bc/quarkus-project -p '{"spec":{"strategy":{"dockerStrategy":{"dockerfilePath":"src/main/docker/Dockerfile.native"}}}}'
oc start-build quarkus-project --from-dir=. --follow
oc new-app --image-stream=quarkus-project:latest
oc expose service quarkus-project
oc new-project quarkus

Deploy using JVM mode

Usando S2i
# Using maven
./mvnw clean package \
    -DskipTests \
    -Dquarkus.container-image.build=true \
    -Dquarkus.container-image.insecure=true
./mvnw clean package -DskipTests -Dquarkus.kubernetes.deploy=true

oc new-app registry.access.redhat.com/ubi8/openjdk-11:latest~https://github.com/quarkusio/quarkus-quickstarts.git --context-dir=todo-backend --name=todo-backend
oc logs -f bc/todo-backend

# To create the route
oc expose svc/todo-backend
Usando Binary Deployment
# Using odo
odo project create todo
odo create java:11 todo-backend \
    --binary target/todo-backend-1.0.0-SNAPSHOT-runner.jar \
    --app todo \
    --env QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://postgresql:5432/todo
odo url create --port 8080
odo push
odo log -f

# Using oc
#mkdir target/deployments && cp target/todo-backend-1.0.0-SNAPSHOT-runner.jar target/deployments
oc new-build --binary --image-stream=java:11 --name=todo-backend -l app=todo-backend -n todo
oc start-build todo-backend --from-file=target/todo-backend-1.0.0-SNAPSHOT-runner.jar --follow -n todo
#oc start-build todo-backend --from-dir=target/deployments --follow -n todo
oc new-app todo-backend -n todo
oc expose svc todo-backend -n todo

Frontend Deploy

cd todo-frontend
odo project set todo
odo catalog list components
odo create nodejs todo-frontend --app todo
odo url create todo-frontend
odo push
odo watch

#odo link todo-backend --port 8080

Using KNative

docker.io/luszczynski/todo-backend
docker.io/luszczynski/todo-frontend