创建一个简单的用于OpenShift的应用程序

首先

在这篇文章中,我们将使用Spring Boot和Open Liberty创建一个简单的应用程序,目的是将其部署到OpenShift。有关部署到OpenShift环境的详细信息,请参考下面的文章。

准备好了Visual Studio Code。

在Windows 10的Visual Studio Code (VScode)中创建应用程序。
在使用之前,需要先安装Java、Gradle和以下的用于VSCode的插件。

    • Java Extension Pack

 

    Spring Boot Extension Pack

1.1 创建一个Spring Boot项目

image.png

1.2. 编写源代码

将下表中的源代码添加到「src/main」目录及其子目录中。

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

import java.net.InetAddress;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.ui.Model;

@Controller
public class SpringLibertyController {
    @RequestMapping("/")
    public String index(Model model, @RequestHeader("User-Agent") String userAgent) {
        model.addAttribute("userAgent", userAgent);

        try {
            InetAddress ia = InetAddress.getLocalHost();
            model.addAttribute("hostName", ia.getHostName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "index";
    }

    @RequestMapping("/healthz")
    public String healthz() {
        return "healthz";
    }
}
<html><head><title>Spring Boot + Liberty</title></head><body>
    <table border="1" style="font-size: 20pt" cellpadding="10">
        <tr><th>Version</th><th>20210716_01</th></tr>
        <tr><th>User Agent</th><th><p th:text="${userAgent}"></p></th></tr>
        <tr><th>Pod</th><th><p th:text="${hostName}"></p></th></tr>
    </table>
</body></html>
OK

使用Gradle插件来添加Open Liberty 1.3版本。

为了使用Open Liberty开发支援插件,需要编辑build.gradle文件。

plugins {
    id 'org.springframework.boot' version '2.5.2'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'io.openliberty.tools.gradle.Liberty' version '3.2'
    id 'java'
    id 'war'
}

group = 'dummy'
version = ''
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    libertyRuntime group: 'io.openliberty', name: 'openliberty-runtime', version: '21.0.0.7'
}

test {
    useJUnitPlatform()
}

liberty {
    server {
        name = 'defaultServer'
        deploy {
            apps = [file('build/libs/spring-liberty-plain.war')]
        }
    }
}

clean.dependsOn 'libertyStop'

2. 构建和运行Spring Boot应用程序

2.1. 构建Spring Boot应用程序

使用Gradle构建将编译生成”build/libs/spring-liberty-plain.war”文件。

gradle build
### 標準出力↓
Starting a Gradle Daemon, 2 busy and 3 incompatible and 1 stopped Daemons could not be reused, use --status for details

BUILD SUCCESSFUL in 8s
7 actionable tasks: 7 up-to-date

在Open Liberty上运行应用程序。

使用『gradle libertyRun』命令将执行以下操作。

    • build.gradleで指定されたバージョンのOpen Libertyが存在しないときはダウンロードする。

 

    • Open Libertyのディレクトリ「build/wlp」を作成する。

 

    • src/main/liberty/server.xmlを「build/wlp/user/servers/defaultServer」にコピーする。

 

    • build/libs/spring-liberty-plain.warを「build/wlp/usr/servers/defaultServer/apps」にコピーする。

 

    Open Liberty をフォアグラウンドで実行する。
gradle libertyRun
### 標準出力↓
> Task :deploy
Application spring-liberty-plain.war was installed as a file as specified. To install as a loose application, specify the plugin or task generating the archive.

> Task :installFeature


> Task :libertyRun
OpenJDK 64-Bit Server VM バージョン 11.0.11+9-LTS (ja_JP) で、defaultServer (Open Liberty 21.0.0.7/wlp-1.0.54.cl210720210629-1900) を起動しています
[監査      ] CWWKE0001I: サーバー defaultServer が起動されました。
[監査      ] CWWKZ0058I: アプリケーションの dropins をモニター中です。
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.ibm.ws.util.ThreadContextAccessor (file:/C:/workspace/source/spring-liberty/build/wlp/lib/com.ibm.ws.container.service_1.0.54.jar) to field java.lang.Thread.contextClassLoader
WARNING: Please consider reporting this to the maintainers of com.ibm.ws.util.ThreadContextAccessor
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[監査      ] CWWKT0016I: Web アプリケーションが使用可能です (default_host): http://xxx.xxx.xxx.xxx:9080/
  .   ____          _            __ _ _  
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \ 
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)
2021-08-07 10:03:09.803  INFO 11352 --- [cutor-thread-22] dummy.springliberty.ServletInitializer   : Starting ServletInitializer using Java 11.0.11 on mark2 with PID 11352 (C:\workspace\source\spring-liberty\build\wlp\usr\servers\defaultServer\apps\expanded\spring-liberty-plain.war\WEB-INF\classes 
started by root in C:\workspace\source\spring-liberty\build\wlp\usr\servers\defaultServer)
2021-08-07 10:03:09.803  INFO 11352 --- [cutor-thread-22] dummy.springliberty.ServletInitializer   : No active profile set, falling back to default profiles: default
2021-08-07 10:03:10.649  INFO 11352 --- [cutor-thread-22] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 796 m 
2021-08-07 10:03:11.092  INFO 11352 --- [cutor-thread-22] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2021-08-07 10:03:11.244  INFO 11352 --- [cutor-thread-22] dummy.springliberty.ServletInitializer   : Started ServletInitializer in 1.996 seconds (JVM running for 10.896)
[監査      ] CWWKZ0001I: アプリケーション spring-liberty-plain が 4.134 秒で開始しました。
[監査      ] CWWKF0012I: サーバーは次のフィーチャーをインストールしました。[el-3.0, jsp-2.3, servlet-3.1]。
[監査      ] CWWKF0011I: defaultServer サーバーは、Smarter Planet に対応する準備ができました。defaultServer サーバーは 10.786 秒で始動しました。
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
    <!-- Enable features -->
    <featureManager>
        <feature>jsp-2.3</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" />

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>

    <webApplication contextRoot="/" location="spring-liberty-plain.war" />
</server>

此外,当执行”gradle libertyDev”时,Open Liberty将在后台运行,并在Java源代码更新时自动重新启动Open Liberty。

image.png
■ 起動方法
java -jar build/libs/spring-liberty.war

■ URL
http://localhost:8080/

2.3. 使用 GitHub

我已经在GitHub上发布了源代码。只要您安装了git命令和Java 11,并按照以下步骤,您就可以在Open Liberty上运行此Spring Boot应用程序。Gradle也将会自动下载。
https://github.com/y-akio/source.git

git clone https://github.com/y-akio/source.git
cd source/spring-liberty
chmod +x gradlew
./gradlew build
### 標準出力↓
Downloading https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
..........10%...........20%...........30%..........40%...........50%...........60%..........70%...........80%...........
90%...........100%
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :compileJava
> Task :processResources
> Task :classes
> Task :bootWarMainClassName
> Task :bootWar
> Task :war
> Task :assemble
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :check
> Task :build

BUILD SUCCESSFUL in 1m 18s
7 actionable tasks: 7 executed

./gradlew libertyRun
### 標準出力↓
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :bootWarMainClassName UP-TO-DATE
> Task :bootWar UP-TO-DATE
> Task :installLiberty
> Task :libertyCreate
> Task :war UP-TO-DATE

> Task :deploy
Application spring-liberty.war was installed as a file as specified. To install as a loose application, specify the plugin or task generating the archive.

> Task :installFeature


> Task :libertyRun
OpenJDK Server VM バージョン 11.0.11+9-LTS (ja_JP) で、defaultServer (Open Liberty 21.0.0.7/wlp-1.0.54.cl210720210629-1900) を起動しています
[監査      ] CWWKE0001I: サーバー defaultServer が起動されました。
[監査      ] CWWKZ0058I: アプリケーションの dropins をモニター中です。
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.ibm.ws.util.ThreadContextAccessor (file:/tmp/source/spring-liberty/build/wlp/lib/com.ibm.ws.container.service_1.0.54.jar) to field java.lang.Thread.contextClassLoader
WARNING: Please consider reporting this to the maintainers of com.ibm.ws.util.ThreadContextAccessor
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[監査      ] CWWKT0016I: Web アプリケーションが使用可能です (default_host): http://haproxy:9080/
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)
2021-08-07 10:23:03.049  INFO 14369 --- [ecutor-thread-4] dummy.springliberty.ServletInitializer   : Starting ServletInitializer using Java 11.0.11 on haproxy with PID 14369 (/tmp/
source/spring-liberty/build/wlp/usr/servers/defaultServer/apps/expanded/spring-liberty-plain.war/WEB-INF/classes started by root in /tmp/source/spring-liberty/build/wlp/usr/servers
/defaultServer)
2021-08-07 10:23:03.067  INFO 14369 --- [ecutor-thread-4] dummy.springliberty.ServletInitializer   : No active profile set, falling back to default profiles: default
2021-08-07 10:23:08.991  INFO 14369 --- [ecutor-thread-4] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 5318 ms
2021-08-07 10:23:11.566  INFO 14369 --- [ecutor-thread-4] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2021-08-07 10:23:12.485  INFO 14369 --- [ecutor-thread-4] dummy.springliberty.ServletInitializer   : Started ServletInitializer in 12.681 seconds (JVM running for 35.805)
[監査      ] CWWKZ0001I: アプリケーション spring-liberty-plain が 24.971 秒で開始しました。
[監査      ] CWWKF0012I: サーバーは次のフィーチャーをインストールしました。[el-3.0, jsp-2.3, servlet-3.1]。
[監査      ] CWWKF0011I: defaultServer サーバーは、Smarter Planet に対応する準備ができました。defaultServer サーバーは 35.766 秒で始動しました。

3. 部署到 OpenShift

使用Dockerfile在Open Liberty上创建一个运行Spring Boot应用程序的容器镜像,并从容器镜像创建一个名为“spring-liberty”的部署。

3.1. 构建容器镜像

在 OpenShift 中构建容器镜像。结果将创建镜像流。

ls -l
### 標準出力
-rw-r--r--. 1 root root      139  8月  7 10:22 Dockerfile
-rw-r--r--. 1 root root      669  8月  7 10:22 server.xml
-rw-r--r--. 1 root root 13138834  8月  7 10:06 spring-liberty-plain.war
-rw-r--r--. 1 root root     1097  8月  7 10:22 spring-liberty.yaml

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

Pulling image open-liberty:21.0.0.7-full-java11-openj9 ...
・・・
STEP 1: FROM open-liberty:21.0.0.7-full-java11-openj9
STEP 2: COPY server.xml /config/
--> bb126b57c0d
STEP 3: COPY spring-liberty-plain.war /config/apps/
--> 5b9a3b886cd
STEP 4: USER 1001
--> fde4d2230c0
STEP 5: EXPOSE 9080
・・・
Successfully pushed image-registry.openshift-image-registry.svc:5000/spring-liberty/spring-liberty@sha256:1ab62ce3019906
cf896185b701053189d01528603f55c7004f103b469354a672
Push successful

oc get is
### 標準出力↓
NAME             IMAGE REPOSITORY                                                                 TAGS     UPDATED
spring-liberty   image-registry.openshift-image-registry.svc:5000/spring-liberty/spring-liberty   latest   7 seconds ago

3.2. 部署容器

使用 “spring-liberty” 部署容器。

oc apply -f spring-liberty.yaml
oc get pod,svc,ing
### 標準出力↓
NAME                                  READY   STATUS      RESTARTS   AGE
pod/spring-liberty-1-build            0/1     Completed   0          2m28s
pod/spring-liberty-84c44ffc5b-24w8n   0/1     Running     0          25s
pod/spring-liberty-84c44ffc5b-js6cg   0/1     Running     0          25s

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/spring-liberty   ClusterIP   172.30.162.86   <none>        80/TCP    25s

NAME                                       CLASS    HOSTS                               ADDRESS                             PORTS   AGE
ingress.networking.k8s.io/spring-liberty   <none>   spring-liberty.apps.ocp.cloud.vpc   router-default.apps.ocp.cloud.vpc   80      25s
FROM open-liberty:21.0.0.7-full-java11-openj9

COPY server.xml /config/
COPY spring-liberty-plain.war /config/apps/

EXPOSE 9080
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
    <!-- Enable features -->
    <featureManager>
        <feature>jsp-2.3</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" accessLoggingRef="accessLogging" />
    <httpAccessLogging id="accessLogging" filePath="/logs/http_access.log"/>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>

    <webApplication contextRoot="/" location="spring-liberty-plain.war" />
</server>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-liberty
  labels:
    app: spring-liberty
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-liberty
  template:
    metadata:
      labels:
        app: spring-liberty
    spec:
      containers:
        - name: spring-liberty
          image: image-registry.openshift-image-registry.svc:5000/spring-liberty/spring-liberty
          ports:
            - containerPort: 9080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 9080
---
apiVersion: v1
kind: Service
metadata:
  name: spring-liberty
spec:
  selector:
    app: spring-liberty
  type: ClusterIP
  ports:
   - protocol: TCP
     port: 80
     targetPort: 9080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: spring-liberty
spec:
  rules:
    - host: spring-liberty.apps.ocp.cloud.vpc
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: spring-liberty
                port:
                  number: 80
image.png
广告
将在 10 秒后关闭
bannerAds