CLOVER🍀

That was when it all began.

WildFlyのドメインモードで、サーバーグループとサーバーを追加する

これは、なにをしたくて書いたもの?

WildFlyのドメインモードで、自分でサーバーグループとサーバーを追加しようとして、適当にやっていたらちょっと
ハマったのでちゃんと確認しておこうかなと思いまして。

WildFlyのドメインモード

WildFlyには、2つの動作モードがありスタンドアロンモードとドメインモードがあります。

ふだんはスタンドアロンモードしか使っていないんですけどね。

ドメインモードについては、こちら。

Domain Setup

ドメインモードには、以下の構成要素があります。

これらが、各ホスト上で動作します。

この用語の説明は、JBoss EAPのドキュメントを見た方がわかりやすい気がしますね。

第8章 ドメイン管理 7.4 | Red Hat Customer Portal

管理対象ドメイン

今回は、ドメインモードで動作するWildFlyに自分でサーバーグループやサーバーを追加してみたいと思います。

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-80-generic", arch: "amd64", family: "unix"

WildFlyは、24.0.0.Finalを使います。

$ curl -OL https://download.jboss.org/wildfly/24.0.0.Final/wildfly-24.0.0.Final.zip
$ unzip wildfly-24.0.0.Final.zip
$ cd wildfly-24.0.0.Final

デフォルトの構成ファイルでドメインモードを起動する

ドメインモードで起動する際にはbin/domain.shでWildFlyを起動するのですが、この時に--host-configオプションで
ホストの構成ファイルを指定する必要があります。

Managed Domain Configuration Files

デフォルト(未指定)の場合は、host.xmlが選択されます。

$ bin/domain.sh

管理CLIでログインすると

$ bin/jboss-cli.sh -c
[domain@localhost:9990 /] 

2つのサーバーグループと3つのサーバーがあります。

[domain@localhost:9990 /] ls -l /server-group
main-server-group
other-server-group


[domain@localhost:9990 /] ls -l /host=master/server-config
server-one
server-three
server-two

いったん、全部削除してみましょう。最初にサーバーを止めて(server-threeはデフォルトでは起動しないようです)、
削除。

[domain@localhost:9990 /] /host=master/server=server-one:stop()
[domain@localhost:9990 /] /host=master/server-config=server-one:remove()

[domain@localhost:9990 /] /host=master/server=server-two:stop()
[domain@localhost:9990 /] /host=master/server-config=server-two:remove()

[domain@localhost:9990 /] /host=master/server-config=server-three:remove()

サーバーを削除すると、サーバーグループも削除できるようになります。

[domain@localhost:9990 /] /server-group=main-server-group:remove()
[domain@localhost:9990 /] /server-group=other-server-group:remove()

次に、自分でサーバーグループを追加してみます。

[domain@localhost:9990 /] /server-group=server-group1:add(profile=default,socket-binding-group=standard-sockets)

[domain@localhost:9990 /] /server-group=server-group2:add(profile=default,socket-binding-group=standard-sockets)

追加したサーバーグループに、サーバーを作成して割り当てます。ポートのオフセットは、2つ目以降は100ずつ
ずらしていきます。

[domain@localhost:9990 /] /host=master/server-config=server1-1:add(group=server-group1)
[domain@localhost:9990 /] /host=master/server-config=server1-2:add(group=server-group1,socket-binding-port-offset=100)

[domain@localhost:9990 /] /host=master/server-config=server2-1:add(group=server-group2,socket-binding-port-offset=200)

サーバーを起動。

[domain@localhost:9990 /] /host=master/server=server1-1:start()
[domain@localhost:9990 /] /host=master/server=server1-2:start()
[domain@localhost:9990 /] /host=master/server=server2-1:start()

アプリケーションをデプロイしてみます。両方のサーバーグループにデプロイしようと思うので--all-server-groupsを
使ってもいいのですが、今回は最初にひとつのサーバーグループにデプロイして、次に別のサーバーグループにも
デプロイメントを割り当てる、という方法でやってみます。

[domain@localhost:9990 /] deploy /path/to/target/ROOT.war --server-groups=server-group1
[domain@localhost:9990 /] deployment enable ROOT.war --server-groups=server-group2

デプロイしたアプリケーション自体は、最後に簡単に載せます。ここでは、/helloにHTTP GETでアクセスすると
Hello World!!と返ってくるものが動作するものとしてください。

確認。

$ curl localhost:8080/hello
Hello World!!

$ curl localhost:8180/hello
Hello World!!

$ curl localhost:8280/hello
Hello World!!

OKですね。

host-master.xmlを使う

次に、ちょっと試しにとhost-master.xmlを使ってみます。
※ここまでの操作の内容は、いったん削除してまっさらなWildFlyでやり直しています

host-master.xmlの説明を見ると、実環境のマスターとなるドメインコントローラーを想定した設定ファイルのようです。

Managed Domain Configuration Files

とりあえず、起動してみます。

$ bin/domain.sh --host-config=host-master.xml

管理CLIで接続。

$ bin/jboss-cli.sh -c
[domain@localhost:9990 /] 

サーバーグループはありますが、サーバーの定義はありません。

[domain@localhost:9990 /] ls -l /server-group
main-server-group
other-server-group


[domain@localhost:9990 /] ls -l /host=master/server-config

先ほどのhost.xmlを使った時と、同じことをしてみましょう。

今のサーバーグループを削除。

[domain@localhost:9990 /] /server-group=main-server-group:remove()
[domain@localhost:9990 /] /server-group=other-server-group:remove()

サーバーとサーバーグループを追加。

[domain@localhost:9990 /] /server-group=server-group1:add(profile=default,socket-binding-group=standard-sockets)
[domain@localhost:9990 /] /server-group=server-group2:add(profile=default,socket-binding-group=standard-sockets)

[domain@localhost:9990 /] /host=master/server-config=server1-1:add(group=server-group1)
[domain@localhost:9990 /] /host=master/server-config=server1-2:add(group=server-group1,socket-binding-port-offset=100)
[domain@localhost:9990 /] /host=master/server-config=server2-1:add(group=server-group2,socket-binding-port-offset=200)

これで、サーバーを起動しようとすると

[domain@localhost:9990 /] /host=master/server=server1-1:start()

サーバーの起動に失敗します。ログファイル(domain/servers/server1-1/log/server.log)を見ると、こんな感じに。

2021-07-23 22:25:06,379 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([("socket-binding-group" => "standard-sockets")]) - failure description: {
    "WFLYCTL0412: Required services that are not installed:" => ["org.wildfly.network.interface.public"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => ["org.wildfly.management.socket-binding-manager is missing [org.wildfly.network.interface.public]"]
}
2021-07-23 22:25:06,380 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([
    ("subsystem" => "remoting"),
    ("http-connector" => "http-remoting-connector")
]) - failure description: {
    "WFLYCTL0412: Required services that are not installed:" => ["jboss.http-upgrade-registry.default"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => ["jboss.remoting.remoting-http-upgrade-service.http-remoting-connector is missing [jboss.http-upgrade-registry.default]"]
}
2021-07-23 22:25:06,382 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([("subsystem" => "jca")]) - failure description: {
    "WFLYCTL0412: Required services that are not installed:" => ["org.wildfly.transactions.global-default-local-provider"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => ["org.wildfly.jca.transaction-integration is missing [org.wildfly.transactions.global-default-local-provider]"]
}
2021-07-23 22:25:06,384 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([
    ("subsystem" => "ejb3"),
    ("service" => "timer-service"),
    ("file-data-store" => "default-file-store")
]) - failure description: {
    "WFLYCTL0412: Required services that are not installed:" => ["org.wildfly.transactions.global-default-local-provider"],
    "WFLYCTL0180: Services with missing/unavailable dependencies" => ["org.wildfly.ejb3.timer-service.timer-persistence-service.default-file-store is missing [org.wildfly.transactions.global-default-local-provider]"]
}
2021-07-23 22:25:06,502 INFO  [org.jboss.as.controller] (Controller Boot Thread) WFLYCTL0183: Service status report
WFLYCTL0184:    New missing/unsatisfied dependencies:
      service jboss.http-upgrade-registry.default (missing) dependents: [service jboss.remoting.remoting-http-upgrade-service.http-remoting-connector] 
      service org.wildfly.network.interface.public (missing) dependents: [service org.wildfly.management.socket-binding-manager] 
      service org.wildfly.transactions.global-default-local-provider (missing) dependents: [service org.wildfly.jca.transaction-integration, service org.wildfly.ejb3.timer-service.timer-persistence-service.default-file-store] 
WFLYCTL0448: 24 additional services are down due to their dependencies being missing or failed

依存関係が足りないようです。

ここで、host.xmlとhost-master.xmlを比較してみます。

$ diff domain/configuration/host.xml domain/configuration/host-master.xml
68,70d67
<         <interface name="public">
<             <inet-address value="${jboss.bind.address:127.0.0.1}"/>
<         </interface>
82,92d78
<     <servers>
<         <server name="server-one" group="main-server-group"/>
<         <server name="server-two" group="main-server-group" auto-start="true">
<             <jvm name="default"/>
<             <socket-bindings port-offset="150"/>
<         </server>
<         <server name="server-three" group="other-server-group" auto-start="false">
<             <jvm name="default"/>
<             <socket-bindings port-offset="250"/>
<         </server>
<     </servers>

サーバーの定義がないのはいいとして、interfaceの定義からpublicとされているもの(のinet-addressの定義)がありません。

確かにないようなので

[domain@localhost:9990 /] ls -l /interface=public
ATTRIBUTE          VALUE     TYPE    
any                undefined OBJECT  
any-address        undefined BOOLEAN 
inet-address       undefined STRING  
link-local-address undefined BOOLEAN 
loopback           undefined BOOLEAN 
loopback-address   undefined STRING  
multicast          undefined BOOLEAN 
name               public    STRING  
nic                undefined STRING  
nic-match          undefined STRING  
not                undefined OBJECT  
point-to-point     undefined BOOLEAN 
public-address     undefined BOOLEAN 
site-local-address undefined BOOLEAN 
subnet-match       undefined STRING  
up                 undefined BOOLEAN 
virtual            undefined BOOLEAN 

ものは試しとinet-addressを追加してみます。

[domain@localhost:9990 /] /interface=public:write-attribute(name=inet-address,value="${jboss.bind.address:127.0.0.1}")

ホストを再起動。

[domain@localhost:9990 /] reload --host=master

すると、今度はサーバーが起動するようになります。今の設定だと、auto-startがtrueになっているので、全サーバーが
起動してきますが…。

デプロイと

[domain@localhost:9990 /] deploy /path/to/target/ROOT.war --server-groups=server-group1
[domain@localhost:9990 /] deployment enable ROOT.war --server-groups=server-group2

動作確認。

$ curl localhost:8080/hello
Hello World!!

$ curl localhost:8180/hello
Hello World!!

$ curl localhost:8280/hello
Hello World!!

OKですね。

さて、設定を変えたら動いたわけですが、やったことが設定ファイルの意図と反している気がします。

こちらの説明を見ていると、ドメインコントローラーはホストコントローラーでもあるようなので、サーバーグループと
サーバーを追加したら動くと思っていたのですが。

管理対象ドメイン

host-master.xmlの説明を見ても、ドメインコントローラーであることと、サーバーが起動するように構成されていない
という感じで書かれているだけな気がします。

Managed Domain Configuration Files

管理対象ドメイン設定ファイル

ここで、host-slave.xmlとの差分を見てみましょう。

$ diff domain/configuration/host-master.xml domain/configuration/host-slave.xml 
3c3
< <host xmlns="urn:jboss:domain:17.0" name="master">
---
> <host xmlns="urn:jboss:domain:17.0">
11a12,14
>                 <server-identities>
>                     <secret value="c2xhdmVfdXMzcl9wYXNzd29yZA=="/>
>                 </server-identities>
62c65,69
<         <local/>
---
>         <remote security-realm="ManagementRealm">
>             <discovery-options>
>                 <static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote+http}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9990}"/>
>             </discovery-options>
>         </remote>
67a75,77
>         <interface name="public">
>             <inet-address value="${jboss.bind.address:127.0.0.1}"/>
>         </interface>
78a89,94
>     <servers>
>         <server name="server-one" group="main-server-group"/>
>         <server name="server-two" group="other-server-group">
>             <socket-bindings port-offset="150"/>
>         </server>
>     </servers>

こちらにはサーバーの定義があり、publicにもinet-addressの定義があります。

ということは、リクエストをハンドリングするのは、host-slave.xmlで定義されているホストコントローラー管理下の
サーバーで行うことを想定している気がしますね。

そしてサーバーを追加するのも、host-slave.xmlで管理されているホストコントローラー側であるべきなのでしょう。

こちらの説明を読んでいて、ドメイン内のホストコントローラーのひとつがドメインコントローラーとなるという
イメージだったのですが。

管理対象ドメイン

こうなると、ドメインコントローラーはドメイン内でも独立して扱った方が良さそうな感じでしょうか。

参考までに、host.xmlとhost-slave.xmlの差分を見てみましょう。

$ diff domain/configuration/host.xml domain/configuration/host-slave.xml 
3c3
< <host xmlns="urn:jboss:domain:17.0" name="master">
---
> <host xmlns="urn:jboss:domain:17.0">
11a12,14
>                 <server-identities>
>                     <secret value="c2xhdmVfdXMzcl9wYXNzd29yZA=="/>
>                 </server-identities>
62c65,69
<         <local/>
---
>         <remote security-realm="ManagementRealm">
>             <discovery-options>
>                 <static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote+http}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9990}"/>
>             </discovery-options>
>         </remote>
84,85c91
<         <server name="server-two" group="main-server-group" auto-start="true">
<             <jvm name="default"/>
---
>         <server name="server-two" group="other-server-group">
87,90d92
<         </server>
<         <server name="server-three" group="other-server-group" auto-start="false">
<             <jvm name="default"/>
<             <socket-bindings port-offset="250"/>

host-slave.xmlにはドメインコントローラーを参照しにいく定義があり、またサーバーの定義が少々異なりますね。

また、ドメイン自体の設定ファイルはdomain.xmlで管理されており、これはdomain.shの引数で指定することもできます。

    -c <config>, -c=<config>            Name of the domain configuration file 
                                        to use (default is "domain.xml") (Same 
                                        as --domain-config)


    --domain-config=<config>            Name of the domain configuration file 
                                        to use (default is "domain.xml") (Same 
                                        as -c)

このファイルは、マスターとなるドメインコントローラーが参照するようです。

Domain Wide Configuration – domain.xml

domain/configuration/domain.xmlでのinterfaceの定義を見ると以下のようになっており、publicとmanagementが空です。

    <interfaces>
        <interface name="management"/>
        <interface name="private">
            <inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
        </interface>
        <interface name="public"/>
        <interface name="unsecure">
            <inet-address value="${jboss.bind.address.unsecure:127.0.0.1}"/>
        </interface>
    </interfaces>

一方でhost-master.xmlではinterfacesはこうなっており

    <interfaces>
        <interface name="management">
            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
        </interface>
    </interfaces>

host.xmlおよびhost-slave.xmlではこのようになっています。

    <interfaces>
        <interface name="management">
            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
        </interface>
        <interface name="public">
            <inet-address value="${jboss.bind.address:127.0.0.1}"/>
        </interface>
    </interfaces>

domain.xmlはドメインコントローラーでしか読み込まないということですが、この差分を上書きできる仕組みにでも
なっているんでしょうか?

なお、ホストコントローラーはひとつのホストにつきひとつを想定しているようで、それでもその構成を行ってみたい場合は
こちらを見るとよさそうです。

1 台のマシンで管理対象ドメインを設定

反対に、2つのホストでドメインを構成したい場合(host-master.xml、host-slave.xmlを使う場合)は、こちらを見ると
よさそうです。

2 台のマシンで管理対象ドメインを設定

まとめ

WildFlyのドメインモードで、サーバーグループとサーバーを自分で追加してみたいなと思い、そして気軽にhost-master.xmlを
扱ってみるといろいろハマり。

結果として、各種役割だったり2つのhost-xxxxx.xmlの役割の違いなどを調べることになり、意外と理解が進んだような
気がします。

まあ、単一のホストで実行する場合は、素直にhost.xmlを使うのが良さそうですね。

2つ以上のホストで構成する場合は、サーバーが動作するのはhost-slave.xmlになるんでしょうね。