《OpenShift 4.x HOL教程汇总》
已在 OpenShift 4.13 环境中运行
有关 RedHa t的 Quarkus 的优势就不详细介绍了,总归就是通过将 Java 应用编译成可执行文件,可以让应用启动超快,占内存超少。非常适合企业 Java 应用的微服务化和大规模部署,另外在 Serverless 等场景也非常适合。
本文基于 quarkus.io 的 quarkus-quickstarts 示例,说明如何实现一个最简单的 Quarkus 应用,并将其以可执行文件的形态部署到 OpenShift 上运行。
安装环境
- 安装带有 OpenJDK17 的 GraavlVM 和可执行程序插件。如果下载地址有变化,可以到 GraavlVM 项目中(https://github.com/graalvm/graalvm-ce-builds/releases)下载。
$ sudo yum install -y java-17
$ GRAALVM_VERSION=22.3.2
$ JAVA_VERSION=java17
$ curl -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-$GRAALVM_VERSION/graalvm-ce-$JAVA_VERSION-linux-amd64-$GRAALVM_VERSION.tar.gz | tar -xzf -
$ JAVA_HOME=$PWD/graalvm-ce-$JAVA_VERSION-$GRAALVM_VERSION
$ PATH=./:$JAVA_HOME/bin/:$PATH
$ java -version
openjdk version "17.0.7" 2023-04-18
OpenJDK Runtime Environment GraalVM CE 22.3.2 (build 17.0.7+7-jvmci-22.3-b18)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.2 (build 17.0.7+7-jvmci-22.3-b18, mixed mode, sharing)
$ gu install native-image
Downloading: Component catalog from www.graalvm.org
Processing Component: Native Image
Downloading: Component native-image: Native Image from github.com
Installing new component: Native Image (org.graalvm.native-image, version 22.2.0)
$ gu list
ComponentId Version Component name Stability Origin
---------------------------------------------------------------------------------------------------------------------------------
graalvm 22.3.2 GraalVM Core Supported
native-image 22.3.2 Native Image Early adopter github.com
- 下载Maven,然后可以查看 Quarkus 的Maven plugin 信息。
$ MAVEN_VERSION=3.9.3
$ curl -L https://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar -xzf -
$ MAVEN_HOME=$PWD/apache-maven-$MAVEN_VERSION
$ PATH=$MAVEN_HOME/bin/:$PATH
- 最后还可以下载 Quarkus 的 cli 客户端。
$ QUARKUS_VERSION=3.2.2
$ curl -L https://github.com/quarkusio/quarkus/releases/download/$QUARKUS_VERSION.Final/quarkus-cli-$QUARKUS_VERSION.Final.tar.gz | tar -xzf -
$ PATH=$PWD/quarkus-cli-$QUARKUS_VERSION.Final/bin/:$PATH
生成应用框架
- 根据模板生成应用框架目录。
$ mvn io.quarkus:quarkus-maven-plugin:$QUARKUS_VERSION.Final:create \
-DprojectGroupId=com.example \
-DprojectArtifactId=hello
也可以用 quarkus 命令生成应用资源。
$ quarkus create com.example:hello
调式应用
- 以开发模式运行应用。成功启动后显示以下三行,其中“Profile dev activated. Live Coding activated”说明是运行在开发模式(代码更改后Quarkus会自动编译和加载应用),而“[cdi, resteasy-reactive, smallrye-context-propagation, vertx]”是该应用加载的Quarkus应用插件。
$ cd hello
$ mvn quarkus:dev
。。。
Listening for transport dt_socket at address: 5005
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-08-02 10:30:10,874 INFO [io.quarkus] (Quarkus Main Thread) hello 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.2.2.Final) started in 9.761s. Listening on: http://localhost:8080
2023-08-02 10:30:10,913 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2023-08-02 10:30:10,921 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy-reactive, smallrye-context-propagation, vertx]
--
Tests paused
Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
也可执行以下命令:
$ quarkus dev
- 用浏览器打开 http://localhost:8080
- 然后点击上图 ”VISIT THE DEV UI“,进入下图页面。
- 在第二个终端窗口访问应用,可以得到“hello”的返回结果。
$ curl -w "\n" http://localhost:8080/hello
Hello from RESTEasy Reactive
- 输入 ”q“ 即可停止第一个终端中运行的应用 Quarkus 应用,然后执行以下功能测试(其中测试代码在 src/test/java/com/example目录中),确认通过测试场景。
$ mvn test
。。。
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
。。。
- 在第一个终端中再次访问 hello 应用。
- 修改 src/main/java/com/example/GreetingResource.java 文件文件,将返回结果设为“hello world”。
[...]
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello World";
}
}
- 在第一个终端窗口确认有以下新的输出,说明quarkus发现代码变化,并自动重新编译并运行了新版应用。
。。。
2023-08-02 15:21:05,147 INFO [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-1) Restarting quarkus due to changes in GreetingResource.class.
2023-08-02 15:21:05,184 INFO [io.quarkus] (Quarkus Main Thread) hello stopped in 0.029s
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-08-02 15:21:06,176 INFO [io.quarkus] (Quarkus Main Thread) hello 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.2.2.Final) started in 0.979s. Listening on: http://localhost:8080
2023-08-02 15:21:06,179 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2023-08-02 15:21:06,181 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy-reactive, smallrye-context-propagation, vertx]
2023-08-02 15:21:06,182 INFO [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-1) Live reload total time: 2.068s
- 在第二个终端再次访问应用,确认返回结果已经变化。
$ curl -w "\n" http://localhost:8080/hello
Hello World
- 撤销前面对 GreetingResource.java 代码的修改。如果不撤销,则无法通过自动 Test。
打包 Java 应用
- 执行以下任意一个命令,可将 Java 应用打包。
$ mvn package
$ quarkus build
- 然后运行应用并验证应用可访问,最后退出应用运行
$ java -jar target/quarkus-app/quarkus-run.jar
- 执行以下任意一个命令,可以将 Java 应用打包成 uber-jar 类型的文件。
$ mvn package -Dquarkus.package.type=uber-jar
$ quarkus build -Dquarkus.package.type=uber-jar
- 然后运行应用并验证应用可访问,最后退出应用运行。
$ java -jar target/hello-1.0.0-SNAPSHOT-runner.jar
编译成可执行程序
- 确保RHEL上有gcc编译所需环境。
$ sudo yum -y install gcc glibc-devel zlib-devel libstdc++-static
- Java 应用编译成可执行应用,然后运行并访问 hello 应用,最后退出应用运行。
$ mvnw package -Pnative
。。。
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Running Quarkus native-image plugin on GraalVM 22.3.2 Java 17 CE (Java Version 17.0.7+7-jvmci-22.3-b18)
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] /home/dawnsky/redhat/graalvm-ce-java17-22.3.2/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dlogging.initial-configurator.min-level=500 -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=3 -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Duser.language=zh -J-Duser.country=CN -J-Dfile.encoding=UTF-8 --features=io.quarkus.runner.Feature,io.quarkus.runtime.graal.DisableLoggingFeature -J--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED -J--add-opens=java.base/java.text=ALL-UNNAMED -J--add-opens=java.base/java.io=ALL-UNNAMED -J--add-opens=java.base/java.lang.invoke=ALL-UNNAMED -J--add-opens=java.base/java.util=ALL-UNNAMED -H:+CollectImageBuildStatistics -H:ImageBuildStatisticsFile=hello-1.0.0-SNAPSHOT-runner-timing-stats.json -H:BuildOutputJSONFile=hello-1.0.0-SNAPSHOT-runner-build-output-stats.json -H:+AllowFoldMethods -J-Djava.awt.headless=true --no-fallback --link-at-build-time -H:+ReportExceptionStackTraces -H:-AddAllCharsets --enable-url-protocols=http -H:-UseServiceLoaderFeature -H:+StackTrace -J--add-exports=org.graalvm.sdk/org.graalvm.nativeimage.impl=ALL-UNNAMED --exclude-config io\.netty\.netty-codec /META-INF/native-image/io\.netty/netty-codec/generated/handlers/reflect-config\.json --exclude-config io\.netty\.netty-handler /META-INF/native-image/io\.netty/netty-handler/generated/handlers/reflect-config\.json hello-1.0.0-SNAPSHOT-runner -jar hello-1.0.0-SNAPSHOT-runner.jar
========================================================================================================================
GraalVM Native Image: Generating 'hello-1.0.0-SNAPSHOT-runner' (executable)...
========================================================================================================================
[1/7] Initializing... (13.1s @ 0.16GB)
Version info: 'GraalVM 22.3.2 Java 17 CE'
Java version info: '17.0.7+7-jvmci-22.3-b18'
C compiler: gcc (redhat, x86_64, 4.8.5)
Garbage collector: Serial GC
2 user-specific feature(s)
3. io.quarkus.runner.Feature: Auto-generated class by Quarkus from the existing extensions
4. io.quarkus.runtime.graal.DisableLoggingFeature: Disables INFO logging during the analysis phase
[2/7] Performing analysis... [******] (30.1s @ 2.71GB)
10,502 (88.47%) of 11,871 classes reachable
15,020 (57.54%) of 26,102 fields reachable
51,931 (55.34%) of 93,834 methods reachable
537 classes, 111 fields, and 2,644 methods registered for reflection
63 classes, 68 fields, and 55 methods registered for JNI access
4 native libraries: dl, pthread, rt, z
[3/7] Building universe... (4.6s @ 0.91GB)
[4/7] Parsing methods... [**] (2.6s @ 3.87GB)
[5/7] Inlining methods... [***] (1.4s @ 1.15GB)
[6/7] Compiling methods... [****] (12.3s @ 4.78GB)
[7/7] Creating image... (7.2s @ 1.74GB)
19.54MB (48.19%) for code area: 33,184 compilation units
20.69MB (51.03%) for image heap: 267,295 objects and 8 resources
325.80KB ( 0.78%) for other data
40.55MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 packages in code area: Top 10 object types in image heap:
1.62MB sun.security.ssl 4.33MB byte[] for code metadata
975.62KB java.util 2.48MB java.lang.Class
733.90KB java.lang.invoke 2.47MB java.lang.String
717.66KB com.sun.crypto.provider 2.21MB byte[] for general heap data
482.28KB java.lang 1.94MB byte[] for java.lang.String
450.52KB sun.security.x509 902.52KB com.oracle.svm.core.hub.DynamicHubCompanion
405.33KB io.netty.buffer 651.75KB java.util.HashMap$Node
384.45KB java.io 564.34KB byte[] for reflection metadata
381.27KB java.util.concurrent 484.90KB java.lang.String[]
345.26KB io.netty.handler.codec.http2 390.80KB byte[] for embedded resources
12.91MB for 391 more packages 4.15MB for 2558 more object types
------------------------------------------------------------------------------------------------------------------------
4.9s (6.1% of total time) in 29 GCs | Peak RSS: 6.38GB | CPU load: 8.23
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
/home/dawnsky/redhat/quarkus-app/hello/target/hello-1.0.0-SNAPSHOT-native-image-source-jar/hello-1.0.0-SNAPSHOT-runner (executable)
/home/dawnsky/redhat/quarkus-app/hello/target/hello-1.0.0-SNAPSHOT-native-image-source-jar/hello-1.0.0-SNAPSHOT-runner-build-output-stats.json (json)
/home/dawnsky/redhat/quarkus-app/hello/target/hello-1.0.0-SNAPSHOT-native-image-source-jar/hello-1.0.0-SNAPSHOT-runner-timing-stats.json (raw)
/home/dawnsky/redhat/quarkus-app/hello/target/hello-1.0.0-SNAPSHOT-native-image-source-jar/hello-1.0.0-SNAPSHOT-runner.build_artifacts.txt (txt)
========================================================================================================================
Finished generating 'hello-1.0.0-SNAPSHOT-runner' in 1m 18s.
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] objcopy --strip-debug hello-1.0.0-SNAPSHOT-runner
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 84410ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:37 min
[INFO] Finished at: 2023-08-02T15:33:18+08:00
[INFO] ------------------------------------------------------------------------
也可执行以下命令打包成可执行应用:
$ quarkus build --native
注意:如果在生成可执行程序过程中报: “OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000737300000, 839909376, 0) failed; error=‘Not enough space’ (errno=12)”,这是由于可以内存较少的原因。可运行以下命令用swapfile解决。
$ dd if=/dev/zero of=swapfile bs=1G count=8
$ mkswap swapfile
$ swapon swapfile
- 运行编译的可运行程序,然后再次访问 hello 应用,最后退出应用运行。
$ target/hello-1.0.0-SNAPSHOT-runner
参考
https://quarkus.io/version/2.16/guides/
https://quarkus.io/guides/building-native-image
https://access.redhat.com/documentation/en-us/red_hat_build_of_quarkus/rhbq-documentation-2-13/guide/aade4772-b875-485f-a3c9-bf595ff43fe3