On March 7, 2019, Red Hat announced the Kubernetes native Java framework "Quarkus".
Introducing Quarkus: a next-generation Kubernetes native Java framework https://developers.redhat.com/blog/2019/03/07/quarkus-next-generation-kubernetes-native-java-framework/
With the increasing use of Kubernetes and the shift to microservices and serverless applications, containerization of applications is becoming more common, and slow startup compared to other languages was a major disadvantage for Java. On the other hand, Quarkus has a catch phrase "Supersonic Subatomic Java (Java smaller than atom)" by booting the Linux Native binary created using GraalVM on the container. It dramatically reduces Java startup time.
I think that various people have already written blogs about Quarkus, so in this article I will also write about "Background of Quarkus appearance" and "Deploying applications using Quarkus to Kubernetes". ..
Due to the trend of Docker / Kubernetes and the trend toward microservices / serverless, containerization of applications is becoming common. For the development of these container applications, languages such as Golang and Ruby that are lightweight, have a short startup time, and use a small amount of memory are often adopted, and the use of Java, which has a slow startup time and a large amount of memory usage, has been avoided. I did.
However, the Java ecosystem has been around for over 20 years, and I think it's still one of the most popular languages used by many developers as of 2019.
"Quarkus" was introduced to deploy Kubernetes native container applications using Java while utilizing the knowledge and skills that Java developers have cultivated so far. Quarkus can significantly reduce startup time, reduce memory usage, and achieve small-sized container images.
We believe that Quarkus was released in an attempt to bring many Java developers into the Kubernetes ecosystem, make container applications more general, and make the Kubernetes ecosystem bigger. ..
GraalVM is a general-purpose runtime released by Oracle as open source in April 2018 that executes multiple languages such as Java, JavaScript, Ruby, and Python on a single integrated runtime.
Quote: https://www.graalvm.org/docs/img/architecture.png
For Java application developers, the new Just-In-Time compilation technology enables Java applications to run faster. GraalVM also has the ability to create Nativ e binaries, which can be run immediately by using static analysis to find reachable code and perform Ahead-Of-Time (AOT) compilation. You can include the code in a Native binary.
Quarkus can use CDI (Contexts and Dependency Injection), but not all CDI specifications can be implemented. The supported and unsupported features are as follows.
Reference: https://quarkus.io/guides/cdi-reference.html
Quarkus uses GraalVM to create a Linux Native binary, but in my environment it takes about "9 minutes" from executing the Maven command to completing it, even though it is a simple application. It's gone. Since "development mode" that realizes hot deployment is provided, when developing in a local environment, we will not do containerization, but for the time being, we will develop using "development mode".
For now, let's create a simple JAX-RS application by following the Get Started at the following URL:
QUARKUS - GET STARTED https://quarkus.io/get-started/
To deploy an application to Kubernetes using Quarkus, you need to prepare the following environment in advance.
To develop an application using Quarkus, create a Maven project using the following command example.
mvn io.quarkus:quarkus-maven-plugin:0.11.0:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=getting-started \
-DclassName="org.acme.quickstart.GreetingResource" \
-Dpath="/hello"
Running the above command will create a directory file similar to the following: Here, a sample Dockerfile is also automatically created under the src / main / docker directory.
$ tree getting-started/
getting-started/
├── pom.xml
└── src
├── main
│ ├── docker
│ │ └── Dockerfile
│ ├── java
│ │ └── org
│ │ └── acme
│ │ └── quickstart
│ │ └── GreetingResource.java
│ └── resources
│ └── META-INF
│ ├── microprofile-config.properties
│ └── resources
│ └── index.html
└── test
└── java
└── org
└── acme
└── quickstart
├── GreetingResourceTest.java
└── NativeGreetingResourceIT.java
Quarkus BOM and quarkus-maven-plugin are pre-configured in the automatically generated pom.xml as shown below.
pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
When you create a Maven project with the above command, the following sample code will be generated.
src/main/java/org/acme/quickstart/GreetingResource.java
package org.acme.quickstart;
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";
}
}
Next, try starting the application using "development mode". In "development mode", hot deployment by background compilation is possible, and when you update the Java file and update the browser, the Java file is automatically compiled and you can check the modified application.
$ mvn compile quarkus:dev
You can check the operation of the sample JAX-RS application by executing the following command.
$ curl http://localhost:8080/hello
hello
Next, let's customize the automatically generated sample application. Here, create a new service class and add a service class call to the automatically generated GreetingResource.java.
Add the following service class newly.
src/main/java/org/acme/quickstart/GreetingService.java
package org.acme.quickstart;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GreetingService {
public String greeting(String name) {
return "hello " + name;
}
}
Then modify the auto-generated GreetingResource.java.
src/main/java/org/acme/quickstart/GreetingResource.java
package org.acme.quickstart;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.inject.Inject;
import javax.ws.rs.PathParam;
@Path("/hello")
public class GreetingResource {
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(@PathParam("name") String name) {
return service.greeting(name);
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
Check the operation with the following command.
$ curl http://localhost:8080/hello/greeting/quarkus
hello quarkus
Next, I use GraalVM to create a Linux Native binary, but the auto-generated pom.xml comes with executions pre-configured in the profile. With the following settings, you can create a Linux Native binary by executing the Maven command.
pom.xml
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.version}</version>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<configuration>
<enableHttpUrlHandler>true</enableHttpUrlHandler>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Create a Linux Native binary with the following Maven command.
$ mvn package -Pnative -Dnative-image.docker-build=true
Here, the -Pnative
option is an option to generate a binary that can be executed by Native, and the -Dnative-image.docker-build = true
option is an option to generate a Native binary according to the OS on Docker. This is an option required to make it explicit.
By the way, when I ran it in my environment, it took "about 9 minutes" to complete the Maven command. If it takes so long without docker build running, it will not be possible to build frequently, so I would like to expect future functional improvements.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 08:48 min
[INFO] Finished at: 2019-03-18T12:16:35+09:00
[INFO] ------------------------------------------------------------------------
When you create a Maven project, a sample Dockerfile is automatically generated, so create a Docker image based on this file.
FROM registry.fedoraproject.org/fedora-minimal
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Create a Docker image using the following command.
$ docker build -f src/main/docker/Dockerfile -t quarkus-quickstart/quickstart .
Let's check the size of the created container image. Since the base image is "fedra-minimal", it is 125MB, but you can see from the difference that it is "about 20MB" if you just run the Quarkus sample JAX-RS application. Considering that it took hundreds of MB just to install the JDK, this container image size looks pretty small.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
quarkus-quickstart/quickstart latest d93d89bde0bb About a minute ago 125MB
registry.fedoraproject.org/fedora-minimal latest f0c38118c459 3 weeks ago 105MB
Next, try starting the Docker container.
$ docker run -i --rm -p 8080:8080 quarkus-quickstart/quickstart
2019-03-18 03:21:00,052 INFO [io.quarkus](main) Quarkus 0.11.0 started in 0.012s. Listening on: http://0.0.0.0:8080
2019-03-18 03:21:00,054 INFO [io.quarkus](main) Installed features: [cdi, resteasy]
In my environment, I was able to start it in a dramatically short time of "0.012 seconds", which is unthinkable with a conventional Java application, as in the above example. You can also check the operation with the following command.
curl http://localhost:8080/hello
hello
You can also see that the memory usage is as follows, and the sample JAX-RS application uses only 1.2MB.
$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
b4d39bbe3159 eloquent_bohr 0.00% 1.281MiB / 1.952GiB 0.06% 1.04kB / 0B 0B / 0B 5
Up to this point, you have created a Linux Native binary from the Java source code using the Maven command, and started the Linux binary as a container. Next, I would like to deploy an application using Quarkus on Kuberntetes (minikube).
Use the following command to create Deployment / ReplicaSet / Pod resources from the Docker image created earlier.
$ kubectl run quarkus-quickstart --image=quarkus-quickstart/quickstart:latest --port=8080 --image-pull-policy=IfNotPresent
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/quarkus-quickstart created
Next, create a Service resource with the kubectl expose command so that you can check the operation.
$ kubectl expose deployment quarkus-quickstart --type=NodePort
service/quarkus-quickstart exposed
The Kubernetes resources created by the above two commands are as follows.
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/quarkus-quickstart-7986c7cd95-44k9n 1/1 Running 1 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5m
service/quarkus-quickstart NodePort 10.103.25.16 <none> 8080:32179/TCP 27s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/quarkus-quickstart 1/1 1 1 1m
NAME DESIRED CURRENT READY AGE
replicaset.apps/quarkus-quickstart-7986c7cd95 1 1 1 1m
You can check the operation of the Quarkus application deployed on Kubernetes (minikube) with the following command.
$ curl $(minikube service quarkus-quickstart --url)/hello/greeting/quarkus
hello quarkus
In this article, I wrote about "Background of the appearance of Quarkus" and "Deploying applications using Quarkus to Kubernetes". As mentioned above, Quarkus not only makes startup dramatically faster, but also the essential elements for container applications such as small image size and memory usage are in Java, which has a large number of developers including enterprises. I think it was a very important release in the sense that it became possible.
However, since it has just been released, we also found that there are various restrictions on CDI and that it takes a long time to build.
Quarkus seems to be a product released by Red Hat, and is developed as OSS (open source software). It has just been released, and I think we will continue to add and improve functions in the future, so I would like to continue watching.
Recommended Posts