[Docker, WLS] Run a WebLogic JMS Sample on Kubernetes

原文はこちら。
https://blogs.oracle.com/weblogicserver/run-a-weblogic-jms-sample-on-kubernetes

Overview

このエントリは、Kubernetesクラスタ内でWebLogic Server JMSアプリケーションのサンプルを構成し、実行するためのステップバイステップガイドです。まず、管理サーバとWebLogicクラスタを持つWebLogicドメインを作成する方法について説明した上で、WebLogic JMSリソースとデータソースを追加し、アプリケーションをデプロイして、最後にアプリケーションを実行します。
このアプリケーションは、WebLogic Serverのサンプルアプリケーションに含まれている 'Classic API - Using Distributed Destination' (分散送り先の使用)という名前のサンプルアプリケーションに基づいています。このアプリケーションは、従業員が到着時に自身の名前を送信し、スーパーバイザが従業員の到着時間を監視するというシナリオを実装したものです。
従業員は、チェックインメッセージの送信先(分散キューまたは分散トピック)を選択します。これらの宛先は、2つのアクティブな管理対象サーバが存在するクラスタ上で構成されています。これらの2つの宛先に対応する2つのmessage driven bean(MDB)がデプロイされ、チェックインメッセージを処理してデータベースに格納します。スーパーバイザーは、データベースに照会することですべてのチェックインメッセージをスキャンできます。

WebLogicの構成変更を自動化する方法には、主として、WLSTとREST APIがあります。KubernetesのWebLogicドメインでスクリプトやWLST、REST APIを実行するには、次の2つの方法があります。
  • KubernetesクラスタPod内でスクリプトを実行するこちらの方法を使う場合は、 'localhost'、NodePortサービス名、またはStatefulsetのヘッドレスサービス名と、Pod IP、Cluster IP、および内部ポートを使用します。このブログの手順では、 'localhost' を使用します。
  • Kubernetesクラスタ外でスクリプトを実行するこちらの方法を使う場合は、hostname/IPとNodePortを使用します。
このブログでは、REST APIを使用して管理サーバPod内のスクリプトを実行し、すべてのリソースをデプロイします。すべてのリソースはクラスタ全体を対象としています。クラスタが拡大または縮小する場合にうまく動作するため、Kubernetes上のWebLogic Serverの推奨アプローチです。

Creating the WebLogic Base Domain

GitHubのサンプルWebLogicドメインを使用してbaseドメインを作成します。
WebLogic Sample on Kubernetes with Shared Domain Home
https://github.com/oracle/docker-images/tree/master/OracleWebLogic/samples/wls-k8s-domain
このWebLogicサンプルアプリケーションには、​​Kubernetes上のWebLogicドメインでWebLogic Serverインスタンスとクラスタを構築して実行するためのDockerfile、スクリプト、yamlファイルがあります。サンプルドメインには、AdminServerという名前の管理サーバーと、managed-server-0からmanaged-server-3までの4つの管理対象サーバーを含むWebLogicクラスタが含まれています。今回4個の管理対象サーバを設定しますが、managed-server-0とmanaged-server-1の最初の2個だけ構成を開始します。
JMSサービスが他と異なる機能の一つとして、ステートフルであり、永続メッセージ、永続サブスクリプションなどといった、永続ストアにデータの大部分を保存する必要がある点があります。永続ストアは、データベースストアまたはファイルストアを使うことができます。このサンプルでは、​​外部ボリュームを使用してこのデータをファイルストアに格納する方法をご紹介します。
このWebLogicドメインでは、次の3つの永続ボリュームを構成します。
  • ドメインホームフォルダこのボリュームは、ドメイン内のすべてのWebLogic Serverインスタンス、つまり、管理サーバとWebLogicクラスタ内のすべての管理対象サーバーインスタンスが共有します。
  • ファイルストアこのボリュームは、WebLogicクラスタ内の管理対象サーバ・インスタンスが共有します。
  • MySQLデータベースこのボリュームの使用については、このブログの後半で説明します。
デフォルトでは、ドメインホームフォルダには、構成ファイル、ログファイル、診断ファイル、アプリケーションバイナリ、およびドメイン内の各WebLogic Serverインスタンスのデフォルトファイルストアファイルが含まれていることにご注意ください。カスタムファイルストアファイルもデフォルトでドメインホームフォルダに配置されていますが、このサンプルの設定をカスタマイズして、これらのファイルを個別の専用永続ボリュームに配置します。2つの永続ボリューム(ドメインホームとカスタムファイルストア)は、複数のWebLogic Serverインスタンスが共有します。それゆえ、Kubernetesクラスタが複数のマシンで実行されている場合、これらのボリュームは共用ストレージ内になければなりません。
README.mdファイルの手順を実行して、baseドメインを作成して実行し、すべてのWebLogic Serverインスタンス(管理サーバと2つの管理対象サーバ)が実行されるまで待ちます。管理サーバの実行、初期ドメインのプロビジョニングの完了後、管理対象サーバを順に開始するため、時間がかかることがあります。
$ kubectl get pod
NAME                           READY    STATUS    RESTARTS    AGE
admin-server-1238998015-kmbt9  1/1      Running   0           5m
managed-server-0               1/1      Running   0           3m
managed-server-1               1/1      Running   0           3m
ブログで使用するコマンドでは、$adminPodと$mysqlPodを実際のポッド名に置き換える必要があることに注意してください。

Deploying the JMS Resources with a File Store

ドメインが稼動中であれば、JMSリソースをデプロイできます。

まず、1つのファイルストア、1つのJMSサーバ、および1つのJMSモジュールの定義を含むJSONデータファイルを準備します。ファイルはPythonスクリプトが処理し、WebLogic ServerのREST APIを使用してリソースを1つずつ作成します。
file jms1.json:
{"resources": { 
  "filestore1": {
    "url": "fileStores",
    "data": {
      "name": "filestore1",
      "directory": "/u01/filestores/filestore1",
      "targets": [{
                 "identity":["clusters", "myCluster"]
                }]
    }
  },
  
  "jms1": {
    "url": "JMSServers",
    "data": {
      "messagesThresholdHigh": -1,
      "targets": [{
                   "identity":["clusters", "myCluster"]
                  }],
      "persistentStore": [
         "fileStores",
         "filestore1"
        ],
      "name": "jmsserver1"
    }
  },
  
  "module": {
    "url": "JMSSystemResources",
    "data": {
      "name": "module1",
      "targets":[{
                  "identity": [ "clusters", "myCluster" ]
                }]
    }
  },
  
  "sub1": {
    "url": "JMSSystemResources/module1/subDeployments",
    "data": {
      "name": "sub1",
      "targets":[{
                  "identity": [ "JMSServers", "jmsserver1" ]
                }]
    }
  }
}}
続いて、JMSモジュールファイルを準備します。これには接続ファクトリ、分散キュー、分散トピックが含まれます。
file module1-jms.xml:
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-jms xmlns="http://xmlns.oracle.com/weblogic/weblogic-jms" xmlns:sec="http://xmlns.oracle.com/weblogic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wls="http://xmlns.oracle.com/weblogic/security/wls" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-jms http://xmlns.oracle.com/weblogic/weblogic-jms/1.1/weblogic-jms.xsd">
  <connection-factory name="cf1">
    <default-targeting-enabled>true</default-targeting-enabled>
    <jndi-name>cf1</jndi-name>
    <transaction-params>
      <xa-connection-factory-enabled>true</xa-connection-factory-enabled>
    </transaction-params>
    <load-balancing-params>
      <load-balancing-enabled>true</load-balancing-enabled>
      <server-affinity-enabled>false</server-affinity-enabled>
    </load-balancing-params>
  </connection-factory>
  <uniform-distributed-queue name="dq1">
    <sub-deployment-name>sub1</sub-deployment-name>
    <jndi-name>dq1</jndi-name>
  </uniform-distributed-queue>
  <uniform-distributed-topic name="dt1">
    <sub-deployment-name>sub1</sub-deployment-name>
    <jndi-name>dt1</jndi-name>
    <forwarding-policy>Partitioned</forwarding-policy>
  </uniform-distributed-topic>
</weblogic-jms>
3つめに、これらの2ファイルをコピーして管理サーバのPodに配置し、Pythonスクリプトを実行して管理サーバPod内でJMSリソースを作成します。
$ kubectl exec $adminPod -- mkdir /u01/wlsdomain/config/jms/
$ kubectl cp ./module1-jms.xml $adminPod:/u01/wlsdomain/config/jms/
$ kubectl cp ./jms1.json $adminPod:/u01/oracle/
$ kubectl exec $adminPod -- python /u01/oracle/run.py createRes /u01/oracle/jms1.json
ブラウザでhttp://<hostIP>:30007/consoleにアクセスしてWebLogic Server管理コンソールを開き、全てのJMSリソースが問題なく動作していることを確認します。

Deploying the Data Source

Setting Up and Running MySQL Server in Kubernetes

このサンプルはCheck-inメッセージをデータベースに格納します。それではMySQL Serverを構成しKubernetes上で動作するようにしましょう。

最初に、以下のものを準備します。
  • mysql.yml:暗号化されたユーザー名とパスワード資格証明を格納するシークレットが定義されている
  • 永続ボリュームクレーム(Permanent Volume Claim : PVC):外部ディレクトリにデータベース・データを格納するためのボリューム
  • MySQL Serverインストーラとサービス
base domainで、mysql.ymlで定義されたPVCが利用できるように、一つの永続ボリュームを予約して利用可能にしておきます。
file mysql.yml:
apiVersion: v1
kind: Secret
metadata:
  name: dbsecret
type: Opaque
data:
  username: bXlzcWw=
  password: bXlzcWw=
  rootpwd: MTIzNHF3ZXI=
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: mysql-server 
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1beta1 
kind: Deployment 
metadata:
  name: mysql-server
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql-server 
    spec:
      containers:
      - name: mysql-server
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
        env:
        - name:  MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: dbsecret
              key: rootpwd
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: dbsecret
              key: username
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: dbsecret
              key: password
        - name: MYSQL_DATABASE
          value: "wlsdb"
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: db-volume
      volumes:
      - name: db-volume
        persistentVolumeClaim:
          claimName: mysql-pv-claim
---
apiVersion: v1 
kind: Service
metadata:
  name: mysql-server
  labels:
    app: mysql-server 
spec:
  ports:
  - name: client
    port: 3306
    protocol: TCP
    targetPort: 3306
  clusterIP: None
  selector:
    app: mysql-server
続いて、MySQL ServerをKubernetesクラスタにデプロイします。
$ kubectl create -f mysql.yml

Creating the Sample Application Table

まず、サンプルのアプリケーション表のためのDDLファイルを準備します。
file sampleTable.ddl:
create table jms_signin (
          name varchar(255) not null,
          time varchar(255) not null,
          webServer varchar(255) not null,
          mdbServer varchar(255) not null);
続いて、MySQL Serverで表を作成します。
$ kubectl exec -it $mysqlPod -- mysql -h localhost -u mysql -pmysql wlsdb < sampleTable.ddl

Creating a Data Source for the WebLogic Server Domain

サンプルアプリケーションがMySQL Serverと通信できるよう、データソースを構成する必要があります。最初にFirst, prepare the ds1-jdbc.xml モジュールファイルを準備します。
file ds1-jdbc.xml:
<?xml version='1.0' encoding='UTF-8'?>
<jdbc-data-source xmlns="http://xmlns.oracle.com/weblogic/jdbc-data-source" xmlns:sec="http://xmlns.oracle.com/weblogic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wls="http://xmlns.oracle.com/weblogic/security/wls" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/jdbc-data-source http://xmlns.oracle.com/weblogic/jdbc-data-source/1.0/jdbc-data-source.xsd">
  <name>ds1</name>
  <datasource-type>GENERIC</datasource-type>
  <jdbc-driver-params>
    <url>jdbc:mysql://mysql-server:3306/wlsdb</url>
    <driver-name>com.mysql.jdbc.Driver</driver-name>
    <properties>
      <property>
        <name>user</name>
        <value>mysql</value>
      </property>
    </properties>
    <password-encrypted>mysql</password-encrypted>
    <use-xa-data-source-interface>true</use-xa-data-source-interface>
  </jdbc-driver-params>
  <jdbc-connection-pool-params>
    <capacity-increment>10</capacity-increment>
    <test-table-name>ACTIVE</test-table-name>
  </jdbc-connection-pool-params>
  <jdbc-data-source-params>
    <jndi-name>jndi/ds1</jndi-name>
    <algorithm-type>Load-Balancing</algorithm-type>
    <global-transactions-protocol>EmulateTwoPhaseCommit</global-transactions-protocol>
  </jdbc-data-source-params>
  <jdbc-xa-params>
    <xa-transaction-timeout>50</xa-transaction-timeout>
  </jdbc-xa-params>
</jdbc-data-source>
続いて、データソース・モジュールをWebLogic Serverドメインにデプロイします。
$ kubectl cp ./ds1-jdbc.xml  $adminPod:/u01/wlsdomain/config/jdbc/
$ kubectl exec $adminPod -- curl -v \
--user weblogic:weblogic1 \
-H X-Requested-By:MyClient \
-H Accept:application/json \
-H Content-Type:application/json \
-d '{
"name": "ds1",
"descriptorFileName": "jdbc/ds1-jdbc.xml",
"targets":[{
"identity":["clusters", "myCluster"]
}]
}' -X POST http://localhost:8001/management/weblogic/latest/edit/JDBCSystemResources

Deploying the Servlet and MDB Applications

まず、2個のアプリケーション・アーカイブ(signin.war と signinmdb.jar)をダウンロードします。

以下のコマンドを入力してこれらの2個のアプリケーションをREST APIを使ってWebLogic Server管理サーバが動作しているPodにデプロイします。
# copy the two app files to admin pod
$ kubectl cp signin.war $adminPod:/u01/wlsdomain/signin.war
$ kubectl cp signinmdb.jar $adminPod:/u01/wlsdomain/signinmdb.jar

# deploy the two app via REST api
$ kubectl exec $adminPod -- curl -v \
--user weblogic:weblogic1 \
-H X-Requested-By:MyClient \
-H Content-Type:application/json \
-d "{
  name:       'webapp',
  sourcePath: '/u01/wlsdomain/signin.war',
  targets:    [ { identity: [ 'clusters', 'myCluster' ] } ]
}" \
-X POST http://localhost:8001/management/weblogic/latest/edit/appDeployments

$ kubectl exec $adminPod -- curl -v \
--user weblogic:weblogic1 \
-H X-Requested-By:MyClient \
-H Content-Type:application/json \
-d "{
  name:       'mdb',
  sourcePath: '/u01/wlsdomain/signinmdb.jar',
  targets:    [ { identity: [ 'clusters', 'myCluster' ] } ]
}" \
-X POST http://localhost:8001/management/weblogic/latest/edit/appDeployments
続いて、WebLogic Server管理コンソール(http://<hostIP>:30007/console)を開き、アプリケーションのデプロイに成功し、実行中であることを確認します。

Running the Sample

ブラウザで http://<hostIP>:30009/signIn/ にアクセスし、管理対象サーバ上にあるアプリケーションを起動します。数多くの異なるブラウザやマシンを使って複数のWebクライアントをシミュレートし、いくつかのユニークな従業員名を投稿します。その後、ブラウザで http://<hostIP>:30009/signIn/response.jsp にアクセスして結果を確認します。異なるレベルの2つの負荷分散がなされていることがわかるでしょう。
  • HTTPリクエストがクラスタ内の管理対象サーバ間で負荷分散されている。[Web Server Name]という列のエントリを見ると、従業員のチェックインごとに、このカラムで、対応するHTTPリクエストを処理しているサーブレットインスタンスを含むWebLogic Serverインスタンスの名前を確認できる。
  • 分散送り先に送信されたJMSメッセージは、クラスタ内のMDBインスタンス間で負荷分散されている。[MDB Server Name]という列のエントリを見ると、メッセージを処理しているMDBインスタンスを含むWebLogic Serverインスタンスを確認できる。

Restarting All Pods

Restart the MySQL、WebLogic Server管理サーバと管理対象サーバのPodをそれぞれ再起動します。ここでは外部ボリュームにあるデータが確かにPodのライフサイクルとは関係なく保存されていることを説明します。

まず、正常にMySQL Podを停止します。
$ kubectl exec -it $mysqlpod /etc/init.d/mysql stop
Podが停止したら、Kubernetesコントロール・パネルが自動的に再起動させるでしょう。

続いて、README.mdの"Restart Pods"の章に移り、全てのWebLogic ServerのPodを再起動します。
$ kubectl get pod
NAME                            READY   STATUS   RESTARTS   AGE
admin-server-1238998015-kmbt9   1/1     Running  1          7d
managed-server-0                1/1     Running  1          7d
managed-server-1                1/1     Running  1          7d
mysql-server-3736789149-n2s2l   1/1     Running  1          3h
各Podの再起動のカウントがインクリメントされ、0から1に変わったことがわかるでしょう。

全てのPodが再起動したら、WebLogic Server管理コンソールにアクセスしてサーバがRUNNING状態になっていることを確認します。サーバが再起動すると、全てのメッセージがリカバリされます。全てのデータは外部データボリュームに格納されており、そのためPodの再起動後リカバリできるため再起動前と同じ結果を確認できます。

Cleanup

以下のコマンドを入力して、MySQL Serverインスタンスが利用していたリソースのクリーンアップを実施します。
$ kubectl delete -f mysql.yml
続いて、README.mdの "Cleanup" の章に従い、base domainを削除し、このサンプルで利用したその他全てのリソースを削除します。

Summary and Futures

このエントリでは、KubernetesをWebLogic Server JMSクラスタをホストするための柔軟でスケーラブルな環境として使用する方法をご紹介しました。基本的なKubernetesの機能を利用して、WebLogicサーバーのライフサイクルを管理し、ファイルベースのメッセージ永続性を使用し、Java EEアプリケーション間のクラスター内JMS通信を実証しました。また、ポッドのライフサイクルを超えてデータを維持するため、Kubernetes Pod外の共有データボリュームにファイルを外出しすることで、FileベースのJMS永続化がうまく機能することも実証しました。
今後のエントリで、WebLogicの将来的に完全に動作保証されたWebLogicのKubernetes ‘operator based’のKubernetes環境を使用してWebLogic JMSクラスタをホストする方法を紹介することを検討しています。さらに、外部JMSクライアントを使用して、Kubernetesクラスタ内で動作するWebLogic JMSサービスと通信する方法、永続ストアとしてファイルの代わりにデータベースを使用する方法、WebLogic JMS自動サービス移行を使用してJMSインスタンスをシャットダウンされたPodから実行中のPodに自動的に移行する方法についても説明する予定です。

0 件のコメント:

コメントを投稿