LoginSignup
2
1

More than 1 year has passed since last update.

OpenShift用のシンプルなQuarkusネイティブアプリケーションの作成

Last updated at Posted at 2021-09-04

はじめに

この記事では、OpenShiftへのデプロイを目的として、Quarkusによるシンプルなネイティブアプリケーションを作成します。デプロイ先のOpenShift環境は下記の記事で紹介しています。

■ 参考

1. 環境準備

アプリケーションはWindows 10のVisual Studio Code(VScode)で作成します。
VScodeにはJavaとGradleのプラグインを、Windows 10には下記を導入しています。
OpenShiftにデプロイするネイティブアプリケーションのLinux用バイナリはDockerで作成します。

  • Docker Desktop 4.0.0
  • Maven 3.8.2
  • Gradle 7.1.1
  • Java 11

1.1. ソースコード作成

gradle用のプロジェクトをmavenで作成し、拡張「quarkus-resteasy-qute」を追加します。
自動生成されたbuild.gradleのversion行のみ修正しました。

PowerShell
mvn io.quarkus:quarkus-maven-plugin:2.2.1.Final:create `
  -DcodestartsEnabled -DprojectGroupId=dummy `
  -DprojectArtifactId=quarkus-native -DbuildTool=GRADLE
cd quarkus-native
gradle listExtensions
### 標準出力↓

RESTEasy Qute                                      quarkus-resteasy-qute


gradle addExtension --extensions="quarkus-resteasy-qute"

下表のソースコードを「src/main」以下のディレクトリに追加します。

ディレクトリ ファイル 用途
java/dummy IndexResource.java 要求「/index」にindex.htmlを応答。
java/dummy HealthzResource.java 要求「/healthz」にhezlthz.htmlを応答。
resources/templates index.html ユーザーエージェントとホスト名を表示。
resources/templates healthz.html OKを表示。
IndexResource.java
package dummy;

import java.net.InetAddress;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.jboss.resteasy.annotations.jaxrs.HeaderParam;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;

@Path("/index")
public class IndexResource {

    @Inject
    Template index; 

    @GET
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get(@HeaderParam("User-Agent") String userAgent) {
        String hostName = "";
        try {
            InetAddress ia = InetAddress.getLocalHost();
            hostName = ia.getHostName();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return index.data("userAgent", userAgent, "hostName", hostName);  
    }
}
HealthzResource.java
package dummy;

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

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;

@Path("/healthz")
public class HealthzResource {

    @Inject
    Template healthz; 

    @GET
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get() {
        return healthz.instance();  
    }
}
index.html
<html><head><title>Quarkus Native</title></head><body>
    <table border="1" style="font-size: 20pt" cellpadding="10">
        <tr><th>Version</th><th>20210904</th></tr>
        <tr><th>User Agent</th><th>{userAgent}</th></tr>
        <tr><th>Pod</th><th>{hostName}</th></tr>
    </table>
</body></html>
healthz.html
OK
build.gradle
plugins {
    id 'java'
    id 'io.quarkus'
}

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    implementation 'io.quarkus:quarkus-resteasy-qute'
    implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
    implementation 'io.quarkus:quarkus-arc'
    implementation 'io.quarkus:quarkus-resteasy'
    testImplementation 'io.quarkus:quarkus-junit5'
    testImplementation 'io.rest-assured:rest-assured'
}

group 'dummy'
version '1.0'

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

compileJava {
    options.encoding = 'UTF-8'
    options.compilerArgs << '-parameters'
}

compileTestJava {
    options.encoding = 'UTF-8'
}

■ 参考資料

2. Quarkusアプリケーションのビルドと実行

2.1. Quarkusアプリケーションのビルド

『gradle build』によりコンパイルされ「build/quarkus-app/quarkus-run.jar」、「build/quarkus-app/lib/~」が作成されます。これらのファイルはQuarkusアプリケーションをJava仮想マシンで実行する場合に使用します。

PowerShell
gradle build
### 標準出力↓
> Task :quarkusBuild
building quarkus jar

BUILD SUCCESSFUL in 7s
8 actionable tasks: 3 executed, 5 up-to-date

『gradle build』にネイティブイメージをコンテナで作成するオプションを追加することで、Docker Desktop上にコンテナが起動され、Linux用のネイティブコード「build/quarkus-native-1.0-runner」が作成されます。

PowerShell
gradle build -D quarkus.package.type=native -D quarkus.native.container-build=true
### 標準出力↓
building quarkus jar

21.2-java11: Pulling from quarkus/ubi-quarkus-native-image
Digest: sha256:2b32e2494199c6096e68c66ffd7dc8b4924735e1e237c8d821deb5d2209b1da9
Status: Image is up to date for quay.io/quarkus/ubi-quarkus-native-image:21.2-java11
quay.io/quarkus/ubi-quarkus-native-image:21.2-java11
[quarkus-native-1.0-runner:25]    classlist:   3,238.74 ms,  0.96 GB
[quarkus-native-1.0-runner:25]        (cap):     555.31 ms,  0.96 GB
[quarkus-native-1.0-runner:25]        setup:   2,063.57 ms,  0.96 GB
The bundle named: messages, has not been found. If the bundle is part of a module, verify the bundle name is a fully qualified class name. Otherwise verify the bundle path is accessible in the classpath.
13:10:11,346 INFO  [org.jbo.threads] JBoss Threads version 3.4.2.Final
[quarkus-native-1.0-runner:25]     (clinit):     489.94 ms,  4.25 GB
[quarkus-native-1.0-runner:25]   (typeflow):   9,909.48 ms,  4.25 GB
[quarkus-native-1.0-runner:25]    (objects):  12,342.45 ms,  4.25 GB
[quarkus-native-1.0-runner:25]   (features):     877.11 ms,  4.25 GB
[quarkus-native-1.0-runner:25]     analysis:  24,646.53 ms,  4.25 GB
[quarkus-native-1.0-runner:25]     universe:   1,195.41 ms,  4.25 GB
[quarkus-native-1.0-runner:25]      (parse):   2,535.66 ms,  4.25 GB
[quarkus-native-1.0-runner:25]     (inline):   4,183.78 ms,  4.63 GB
[quarkus-native-1.0-runner:25]    (compile):  18,716.19 ms,  4.36 GB
[quarkus-native-1.0-runner:25]      compile:  27,282.70 ms,  4.36 GB
[quarkus-native-1.0-runner:25]        image:   3,782.32 ms,  4.36 GB
[quarkus-native-1.0-runner:25]        write:   1,512.34 ms,  4.40 GB
[quarkus-native-1.0-runner:25]      [total]:  64,244.58 ms,  4.40 GB
# Printing build artifacts to: /project/quarkus-native-1.0-runner.build_artifacts.txt

BUILD SUCCESSFUL in 1m 22s
6 actionable tasks: 1 executed, 5 up-to-date

2.2. Quarkusアプリケーションの実行

『gradle quarkusDev』でQuarkusアプリケーションを起動することができます。
JBoss上で動作しているようです。Windowsネイティブではありません。

PowerShell
gradle quarkusDev
### 標準出力↓
> Task :quarkusDev
Listening for transport dt_socket at address: 5005
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/.gradle/caches/modules-2/files-2.1/org.jboss.slf4j/slf4j-jboss-logmanager/1.1.0.Final/5f1c0e3f5082c21f6b4964b97fe5b1d5f8c42f53/slf4j-jboss-logmanager-1.1.0.Final.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/.m2/repository/org/jboss/slf4j/slf4j-jboss-logmanager/1.1.0.Final/slf4j-jboss-logmanager-1.1.0.Final.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Slf4jLoggerFactory]
Press [h] for more options>NG [8s]
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2021-09-04 17:11:57,608 INFO  [io.quarkus] (Quarkus Main Thread) quarkus-native 1.0 on JVM (powered by Quarkus 2.2.1.Final) started in 2.003s. Listening on: http://localhost:8080
2021-09-04 17:11:57,621 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2021-09-04 17:11:57,622 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, qute, resteasy, resteasy-qute, smallrye-context-propagation]

http://localhost:8080/indexを開くと以下のような画面が表示されます。
OpenShiftにデプロイしていないので、Pod名ではなくホスト名が表示されています。
image.png

2.3. GitHubの利用

ソースコードをGitHubに公開しました。gitコマンドとJava 11とDocker(あるいはPodman)が導入されていれば、下記の手順でネイティブのQuarkusアプリケーションをビルド・実行することができます。Linux用のバイナリであるため、CentOSの場合は「./build/quarkus-native-1.0-runner」を直接実行可能です。Gradleも自動的にダウンロードされます。
https://github.com/y-akio/source.git

CentOSでの実行例
git clone https://github.com/y-akio/source.git
cd source/quarkus-native
chmod +x gradlew
./gradlew build -D quarkus.package.type=native -D quarkus.native.container-build=true
### 標準出力↓
> Task :quarkusGenerateCode
preparing quarkus application

> Task :quarkusGenerateCodeTests
preparing quarkus application

> Task :quarkusBuild
building quarkus jar

Trying to pull quay.io/quarkus/ubi-quarkus-native-image:21.2-java11...
Getting image source signatures
Copying blob sha256:6f9adeed15adce73e9f73519fb1f314eb58ed175594daabaa944f26b787daa67
Copying blob sha256:c2c17d84f25a8380da8196e4173249e5324e4f653231b00d2e95a6efaac5687a
Copying blob sha256:46cdcde062b27f6c24775848f60eeb6a7216a98d4d6d7617927f5024fc8edfc3
Copying config sha256:2dffe88ed345adf89d68f8a1312bf1a405a4da1b857ba7dc052f1d82640f6bd0
Writing manifest to image destination
Storing signatures
2dffe88ed345adf89d68f8a1312bf1a405a4da1b857ba7dc052f1d82640f6bd0
[quarkus-native-1.0-runner:25]    classlist:   3,844.03 ms,  0.96 GB
[quarkus-native-1.0-runner:25]        (cap):     580.38 ms,  0.96 GB
[quarkus-native-1.0-runner:25]        setup:   2,631.16 ms,  0.96 GB
The bundle named: messages, has not been found. If the bundle is part of a module, verify the bundle name is a fully qualified class name. Otherwise verify the bundle path is acces
sible in the classpath.
09:00:43,724 INFO  [org.jbo.threads] JBoss Threads version 3.4.2.Final
[quarkus-native-1.0-runner:25]     (clinit):     571.91 ms,  2.95 GB
[quarkus-native-1.0-runner:25]   (typeflow):  18,347.68 ms,  2.95 GB
[quarkus-native-1.0-runner:25]    (objects):  18,567.88 ms,  2.95 GB
[quarkus-native-1.0-runner:25]   (features):     860.43 ms,  2.95 GB
[quarkus-native-1.0-runner:25]     analysis:  39,571.10 ms,  2.95 GB
[quarkus-native-1.0-runner:25]     universe:   1,631.93 ms,  2.96 GB
[quarkus-native-1.0-runner:25]      (parse):   5,390.79 ms,  2.96 GB
[quarkus-native-1.0-runner:25]     (inline):   6,300.51 ms,  3.17 GB
[quarkus-native-1.0-runner:25]    (compile):  30,355.53 ms,  3.38 GB
[quarkus-native-1.0-runner:25]      compile:  44,119.20 ms,  3.38 GB
[quarkus-native-1.0-runner:25]        image:   4,570.07 ms,  3.36 GB
[quarkus-native-1.0-runner:25]        write:     616.21 ms,  3.36 GB
[quarkus-native-1.0-runner:25]      [total]:  97,073.20 ms,  3.36 GB
# Printing build artifacts to: /project/quarkus-native-1.0-runner.build_artifacts.txt

BUILD SUCCESSFUL in 1m 45s
6 actionable tasks: 6 executed

./build/quarkus-native-1.0-runner
### 標準出力↓
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2021-09-04 04:44:08,871 INFO  [io.quarkus] (main) quarkus-native 1.0 native (powered by Quarkus 2.2.1.Final) started in 0.014s. Listening on: http://0.0.0.0:8080
2021-09-04 04:44:08,871 INFO  [io.quarkus] (main) Profile prod activated.
2021-09-04 04:44:08,871 INFO  [io.quarkus] (main) Installed features: [cdi, qute, resteasy, resteasy-qute, smallrye-context-propagation]

3. OpenShiftへのデプロイ

3.1. コンテナイメージのビルド

OpenShiftでコンテナイメージをビルドします。結果としてイメージストリームが作成されます。

classicノード
ls -l
### 標準出力
-rw-r--r--. 1 root root      273  9月  4 17:19 Dockerfile
-rw-r--r--. 1 root root 42787352  9月  4 17:31 quarkus-native-1.0-runner
-rw-r--r--. 1 root root     1097  9月  4 17:20 quarkus-native.yaml

oc new-project quarkus-native
oc new-build --name=quarkus-native --strategy=docker --binary
oc start-build quarkus-native --from-dir=. --follow
### 標準出力↓
Uploading directory "." as binary input for the build ...
.
Uploading finished
build.build.openshift.io/quarkus-native-1 started
Receiving source from STDIN as archive ...
Caching blobs under "/var/cache/blobs".

Pulling image registry.access.redhat.com/ubi8/ubi-minimal:8.4 ...
・・・
STEP 1: FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
STEP 2: RUN mkdir /work
--> bd1f6bd04b5
STEP 3: COPY quarkus-native-1.0-runner /work/
--> 1153e514fc7
STEP 4: RUN chmod +x /work/quarkus-native-1.0-runner
--> 5e90ecd40a9
STEP 5: EXPOSE 8080
--> 4373d6396f7
STEP 6: CMD ["/work/quarkus-native-1.0-runner","-Dquarkus.http.host=0.0.0.0"]
--> 98a1c910c10
STEP 7: ENV "OPENSHIFT_BUILD_NAME"="quarkus-native-1" "OPENSHIFT_BUILD_NAMESPACE"="quarkus-native"
--> 1770b08a74a
STEP 8: LABEL "io.openshift.build.name"="quarkus-native-1" "io.openshift.build.namespace"="quarkus-native"
STEP 9: COMMIT temp.builder.openshift.io/quarkus-native/quarkus-native-1:775e898a
・・・
Successfully pushed image-registry.openshift-image-registry.svc:5000/quarkus-native/quarkus-native@sha256:fcb197e10922265a8e84fe9d184b80064cc4192327860d9a9e60114f1bc7eaf4
Push successful

oc get is
### 標準出力↓
NAME             IMAGE REPOSITORY                                                                 TAGS     UPDATED
quarkus-native   image-registry.openshift-image-registry.svc:5000/quarkus-native/quarkus-native   latest   22 seconds ago
Dockerfile
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4

RUN mkdir /work
COPY quarkus-native-1.0-runner /work/
RUN chmod +x /work/quarkus-native-1.0-runner

EXPOSE 8080

CMD ["/work/quarkus-native-1.0-runner", "-Dquarkus.http.host=0.0.0.0"]

3.2. コンテナのデプロイ

デプロイメント「quarkus-native」としてコンテナをデプロイします。

classicノード
oc apply -f quarkus-native.yaml
oc get pod,svc,ing
### 標準出力↓
NAME                                  READY   STATUS      RESTARTS   AGE
pod/quarkus-native-1-build           0/1     Completed   0          2m54s
pod/quarkus-native-65d6c4fbd-2zfxz   1/1     Running     0          95s
pod/quarkus-native-65d6c4fbd-b45ns   1/1     Running     0          95s
pod/quarkus-native-65d6c4fbd-z6zbw   1/1     Running     0          95s

NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/quarkus-native   ClusterIP   172.30.233.121   <none>        80/TCP    95s

NAME                                       CLASS    HOSTS                               ADDRESS                             PORTS   AGE
ingress.networking.k8s.io/quarkus-native   <none>   quarkus-native.apps.ocp.cloud.vpc   router-default.apps.ocp.cloud.vpc   80      95s
quarkus-native.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: quarkus-native
  labels:
    app: quarkus-native
spec:
  replicas: 3
  selector:
    matchLabels:
      app: quarkus-native
  template:
    metadata:
      labels:
        app: quarkus-native
    spec:
      containers:
        - name: quarkus-native
          image: image-registry.openshift-image-registry.svc:5000/quarkus-native/quarkus-native
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: quarkus-native
spec:
  selector:
    app: quarkus-native
  type: ClusterIP
  ports:
   - protocol: TCP
     port: 80
     targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: quarkus-native
spec:
  rules:
    - host: quarkus-native.apps.ocp.cloud.vpc
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: quarkus-native
                port:
                  number: 80

ブラウザでhttp://quarkus-native.apps.ocp.cloud.vpc/indexを開くと以下のような画面が表示されます。端末で実行した時と違いPod名が表示されています。
image.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1