コンテナ上で稼働する SpringBoot on WebSphere Liberty を Instanaで監視する 

# SpringBoot on WebSphere Libety の Instana監視

RHEL8のコンテナ環境(podman)で稼働するSpringBoot on Libertyを、Instanaで監視していきたいと思います。
SpringBootで、パフォーマンス情報を公開する設定などが必要となるので、いくつかステップが必要となりますが、順にやっていけば問題なく監視可能です。

手順は、以下の通りです。
1. SpringBoot でメトリック公開の設定をし、SpringBoot アプリケーションをビルド
1. ビルドされたSpringBootアプリケーションを、WebSphere Liberty上で稼働するよう コンテナ化

# 1. SpringBoot でメトリック公開の設定をし、SpringBoot アプリケーションをビルド

### 1-1. SpringBootアプリケーション・テンプレートのダウンロード
SpringBoot Initialzrを利用して、ベースとなる Springbootアプリをダウンロードします。
今回は、[こちらのdockerの記事](https://www.docker.com/ja-jp/blog/9-tips-for-containerizing-your-spring-boot-code/) を参考に、作成し、`spring-boot-docker.zip`をダウンロードし、任意のディレクトリに展開します。
```
[root@itz-3100008gyq-qtj5 spring-boot-docker]# ls
HELP.md  mvnw  mvnw.cmd  pom.xml  src
```

### 1-2. SpringBoot アプリケーションの修正
先ほどの記事を参考に、REST API に応答するよう src/main/java 配下にある SpringBootDockerApplication.java を編集します
```java:SpringBootDockerApplication.java
package com.example.springbootdocker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class SpringBootDockerApplication {

	@RequestMapping("/")
    public String home() {
        return "Hello World";
    }

	public static void main(String[] args) {
		SpringApplication.run(SpringBootDockerApplication.class, args);
	}

}
```
### 1-3. SpringBoot JMX および エンドポイントの有効化
src/main/resources 配下にある application.properties を編集します。
```properties:application.properties
spring.jmx.enabled=true
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
management.endpoint.health.enabled=true
management.endpoint.metrics.enabled=true
management.endpoint.env.enabled=true
```

### 1-4. pom.xml を編集し、spring-boot-starter-actuator をdependencyに追加
```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	...
	<name>spring-boot-docker</name>
    ...
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
        <!-- 以下を追加 -->
		<dependency>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
        <!-- ここまで -->
	</dependencies>
	<build>
    ...
</project>
```

### 1-5. mvnw package で SpringBootアプリケーションをビルド
`mvnw package`で SpringBoot アプリケーションをビルドします

```
[root@itz-3100008gyq-qtj5 spring-boot-docker]# ls
HELP.md  mvnw  mvnw.cmd  pom.xml  src  target
[root@itz-3100008gyq-qtj5 spring-boot-docker]# ./mvnw package
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.example:spring-boot-docker >-------------------
[INFO] Building spring-boot-docker 0.0.1-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------

... 中略

[INFO]
[INFO] --- jar:3.2.2:jar (default-jar) @ spring-boot-docker ---
[INFO]
[INFO] --- spring-boot:2.7.18:repackage (repackage) @ spring-boot-docker ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.411 s
[INFO] Finished at: 2024-02-19T20:34:37-06:00
[INFO] ------------------------------------------------------------------------
```
うまくいかない場合は export JAVA_HOMEの環境変数で、正しい JDKを 指定できているか確認ください。`# yum install java-1.8.0-openjdk`で入るのは JREのみです。`# yum install java-1.8.0-openjdk-devel`でJDKを導入し、そのパスを指定しているか確認ください。

### 1-6. ビルドされた SpringBootアプリケーションの確認
target ディレクトリ配下に アプリケーションがビルドされます
```
[root@itz-3100008gyq-qtj5 target]# ls -ltr
合計 19508
drwxr-xr-x. 3 root root     4096  2月 19 17:34 generated-sources
drwxr-xr-x. 3 root root     4096  2月 19 17:34 maven-status
drwxr-xr-x. 3 root root     4096  2月 19 17:36 classes
drwxr-xr-x. 3 root root     4096  2月 19 17:36 generated-test-sources
drwxr-xr-x. 3 root root     4096  2月 19 17:36 test-classes
drwxr-xr-x. 2 root root     4096  2月 19 17:36 surefire-reports
drwxr-xr-x. 2 root root     4096  2月 19 17:36 maven-archiver
-rw-r--r--. 1 root root 19946219  2月 19 19:22 spring-boot-docker-0.0.1-SNAPSHOT.jar
```

# 2. ビルドされたSpringBootアプリケーションを、WebSphere Liberty上で稼働するよう コンテナ化

### 2-1. WebSphere Liberty 構成ファイル server.xml の定義
springBootフィーチャーと、Liberty自身のJMXを有効化するための monitorフィーチャーを有効化します。
また、springBootApplicationエレメントで、SpringBootApplicationのjar名を指定します。

```xml:server.xml
<?xml version="1.0" encoding="UTF-8"?>
<server description="Default server">

    <featureManager>
  	<feature>springBoot-2.0</feature>
  	<feature>servlet-4.0</feature>
	<feature>monitor-1.0</feature>
    </featureManager>

    <httpEndpoint id="defaultHttpEndpoint"
                  host="*" httpPort="9080" httpsPort="9443" />

    <springBootApplication location="spring-boot-docker-0.0.1-SNAPSHOT.jar"/>
    <applicationManager autoExpand="true"/>

</server>
```
### 2-2. WebSphere Liberty 環境変数ファイル server.env の定義
```properties:server.env
JAVA_HOME=/opt/ibm/java/jre
```
### 2-3. コンテナをビルドするため dockerfile を用意します
WebSphere Libety の公式イメージに、編集後のserver.xmlおよびserver.envを配置します。
また、１の手順でビルドしたSpringBootアプリケーションを appsディレクトリに配置します。

```dockerfile:dockerfile
FROM docker.io/library/websphere-liberty:full-java8-ibmjava
COPY server.xml /opt/ibm/wlp/usr/servers/defaultServer/
COPY server.env /opt/ibm/wlp/usr/servers/defaultServer/
COPY spring-boot-docker/target/spring-boot-docker-0.0.1-SNAPSHOT.jar /opt/ibm/wlp/usr/servers/defaultServer/apps
```

2-4. podman でビルドします。
```
[root@itz-3100008gyq-qtj5 work]# podman build -f dockerfile -t springbootonliberty:1.5 .
STEP 1/4: FROM docker.io/library/websphere-liberty:full-java8-ibmjava
STEP 2/4: COPY server.xml /opt/ibm/wlp/usr/servers/defaultServer/
--> Using cache 8025acfa3aba9179e03d2c28b3167ce43ad0d3b44436b49c5d42accb77351177
--> 8025acfa3aba
STEP 3/4: COPY server.env /opt/ibm/wlp/usr/servers/defaultServer/
--> Using cache 269f45bfd6b2699f83dbc4b78b38738bfc9ed89e5bb43ea0cc42fab062b446b7
--> 269f45bfd6b2
STEP 4/4: COPY spring-boot-docker/target/spring-boot-docker-0.0.1-SNAPSHOT.jar /opt/ibm/wlp/usr/servers/defaultServer/apps
--> Using cache b0a084241ba0d66a241564e9b75ffbe5879b3bed51e828b9f1e67e2860df83f6
COMMIT springbootonliberty:1.5
--> b0a084241ba0
Successfully tagged localhost/springbootonliberty:1.5
Successfully tagged localhost/springbootonliberty:1.4
b0a084241ba0d66a241564e9b75ffbe5879b3bed51e828b9f1e67e2860df83f6
```
### 2-5. SpringBoot コンテナを起動します
```
[root@itz-3100008gyq-qtj5 work]# podman run -d -p9080:9080 springbootonliberty:1.5
bdcdd9df9db19eb329c51b64fce1a35ec02dcc9f5a262b2ca0d8b23a3e239182
[root@itz-3100008gyq-qtj5 work]# podman ps
CONTAINER ID  IMAGE                              COMMAND               CREATED        STATUS        PORTS                   NAMES
bdcdd9df9db1  localhost/springbootonliberty:1.5  /opt/ibm/wlp/bin/...  9 seconds ago  Up 9 seconds  0.0.0.0:9080->9080/tcp  gallant_golick
```
### 2-6. コンテナのログを確認します。
```
[root@itz-3100008gyq-qtj5 work]# podman logs bdcdd9df9db1

Launching defaultServer (WebSphere Application Server 24.0.0.1/wlp-1.0.85.cl240120240115-2042) on IBM J9 VM, version 8.0.8.20 - pxa6480sr8fp20-20240112_01(SR8 FP20) (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKE0100I: This product is licensed for development, and limited production use. The full license terms can be viewed here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/24.0.0.1/lafiles/en.html
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ibm/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications.
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::               (v2.7.18)
2024-02-20 09:03:06.643  INFO 1 --- [ecutor-thread-4] c.e.s.SpringBootDockerApplication        : Starting SpringBootDockerApplication using Java 1.8.0_401 on bdcdd9df9db1 with PID 1 (/opt/ibm/wlp/output/defaultServer/workarea/spring/spring.thin.apps/spring-boot-docker-0.0.1-SNAPSHOT.spring started by default in /opt/ibm/wlp/output/defaultServer)
2024-02-20 09:03:06.659  INFO 1 --- [ecutor-thread-4] c.e.s.SpringBootDockerApplication        : No active profile set, falling back to 1 default profile: "default"
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://bdcdd9df9db1:9080/
2024-02-20 09:03:08.946  INFO 1 --- [ecutor-thread-3] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2214 ms
2024-02-20 09:03:10.565  INFO 1 --- [ecutor-thread-4] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
2024-02-20 09:03:10.655  INFO 1 --- [ecutor-thread-4] c.e.s.SpringBootDockerApplication        : Started SpringBootDockerApplication in 4.731 seconds (JVM running for 10.005)
[AUDIT   ] CWWKZ0001I: Application spring-boot-docker-0.0.1-SNAPSHOT started in 5.697 seconds.
[AUDIT   ] CWWKF1037I: The server added the [monitor-1.0, springBoot-2.0] features to the existing feature set.
[AUDIT   ] CWWKF0012I: The server installed the following features: [monitor-1.0, servlet-4.0, springBoot-2.0].
[AUDIT   ] CWWKF0013I: The server removed the following features: [appClientSupport-1.0, appSecurity-2.0, appSecurity-3.0, batch-1.0, beanValidation-2.0, cdi-2.0, concurrent-1.0, distributedMap-1.0, ejb-3.2, ejbHome-3.2, ejbLite-3.2, ejbPersistentTimer-3.2, ejbRemote-3.2, el-3.0, j2eeManagement-1.1, jacc-1.5, jaspic-1.1, javaMail-1.6, javaee-8.0, jaxb-2.2, jaxrs-2.1, jaxrsClient-2.1, jaxws-2.2, jca-1.7, jcaInboundSecurity-1.0, jdbc-4.2, jms-2.0, jndi-1.0, jpa-2.2, jpaContainer-2.2, jsf-2.3, json-1.0, jsonb-1.0, jsonp-1.1, jsp-2.3, jwt-1.0, managedBeans-1.0, mdb-3.2, microProfile-3.0, mpConfig-1.3, mpFaultTolerance-2.0, mpHealth-2.0, mpJwt-1.1, mpMetrics-2.0, mpOpenAPI-1.1, mpOpenTracing-1.3, mpRestClient-1.3, opentracing-1.3, ssl-1.0, wasJmsClient-2.0, wasJmsSecurity-1.0, wasJmsServer-1.0, webProfile-8.0, websocket-1.1].
[AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 10.080 seconds.
```
#3. Instanaで稼働を確認します。

手で数回打鍵しただけで、見えている情報量も少ないですが、各コンポーネントで情報が拾えていくことを確認します。

まず SpringBootアプリケーションのトレーシングです。要求が確認できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323873/bc0674b2-935f-dade-93e3-1ac693c843d5.png)

その SpringBootアプリケーションの基盤として、Libertyのプロセスが見えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323873/164738a0-2e0f-6ecb-16d1-e6a33d42262b.png)

リンクを開くと、LibertyのJavaのメトリック情報が見えています。（何ヶ所かデータ欠けているのは再起動の跡です）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323873/3a171fb4-18ec-16da-6b61-72fb0e0e54d4.png)

SpringBoot のメトリックが確認できます。1-3、1-4の手順で有効化したところですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323873/58270d31-c87b-e6c6-3f0a-0ee07b496511.png)

WebSphere Libertyのメトリックが確認できます。こちらは 2-1 の手順で有効化したところです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323873/cb109b56-208f-ba08-7a92-068f017385c3.png)

# まとめ
SpringBoot および コンテナと、それぞれビルドが必要で ステップが多く見えますが、一つ一つ実施していけば問題ないですね。監視対象でメトリックさえ出力される設定になっていれば、Instana Agent 自体にはなにも設定をいれずに、情報が収集できています。