Kubernetes 中的远程 EJB

Remote EJB in Kubernetes

我正在尝试在部署在 k8s 中的 2 个 WebSphere Liberty 服务器之间设置远程 EJB 调用。 是的,我知道在 k8s 中部署时,EJB 不是人们想要使用的东西,但我现在必须处理它。

我遇到的问题是如何在 k8s 中公开远程 ORB IP:port。据我了解,只有在客户端和远程“侦听”同一 IP 时,才有可能让它工作。我不是网络专家,我对 k8s 很陌生,所以也许我在这里遗漏了一些东西,这就是我需要帮助的原因。

我让它工作的唯一方法是当我明确地将远程服务器上的主机设置为它自己的 IP 地址,然后从同一 IP 上的客户端访问它。此测试是在具有 macvlan0 网络的 Docker 主机上完成的(每个容器都有自己的 IP 地址)。

这是远程 server.xml 配置的 ORB 设置:

<iiopEndpoint id="defaultIiopEndpoint" host="172.30.106.227" iiopPort="2809" />

<orb id="defaultOrb" iiopEndpointRef="defaultIiopEndpoint">
    <serverPolicy.csiv2>
        <layers>
            <!-- don't care about security at this point -->
            <authenticationLayer establishTrustInClient="Never"/>
            <transportLayer sslEnabled="false"/>
        </layers>
    </serverPolicy.csiv2>
</orb>

和客户端server.xml配置:

    <orb id="defaultOrb">
    <clientPolicy.csiv2>
        <layers>
            <!-- really, I don't care about security -->
            <authenticationLayer establishTrustInClient="Never"/>
            <transportLayer sslEnabled="false"/>
        </layers>
    </clientPolicy.csiv2>
</orb>

来自客户端,这是我尝试访问的 JNDI 名称:

corbaname::172.30.106.227:2809#ejb/global/some-app/ejb/BeanName!org\.example\.com\.BeanRemote

这行得通。

由于不想在暴露ORB端口时设置固定IP,所以我必须找到一种基于主机IP动态暴露它的方法。 在 0.0.0.0 上公开不起作用。本地主机也是如此。在这两种情况下,客户端都拒绝连接此类错误:

Error connecting to host=0.0.0.0, port=2809: Connection refused (Connection refused)

在 k8s 中,我通过远程 pods 的 LoadBalancer 服务公开了端口 2809,并尝试从客户端 pod 访问远程服务器,我在 corbaname 定义中设置了远程的服务 IP 地址。 这当然行不通。我可以通过 telnet 访问远程 ip:port,所以这不是网络问题。

我已经在远程服务器上尝试了所有设置组合。在 host="0.0.0.0" 上导出结果与上述相同(连接被拒绝)。

我不确定导出内部 IP 地址是否可行,但即使可行,我也不知道在 pod 部署到 k8s 之前的内部 IP。或者有办法知道吗?没有环境。变量,我检查过。

暴露服务 IP 地址(host="${REMOTE_APP_SERVICE_HOST}")失败并出现此错误:

The server socket could not be opened on 2,809. The exception message is Cannot assign requested address (Bind failed).

同样,我知道用 Rest 替换 EJB 是可行的方法,但现在不是一个选项(不要问为什么)。

请帮忙!


编辑:

我已经取得了一些进展。实际上,我相信我已经成功地调用了远程 EJB。 我所做的是在 pod 定义中添加 hostAliases,这为我的主机添加了别名,如下所示:

hostAliases:
- ip: 0.0.0.0
  hostnames:
  - my.host.name

然后我将这个主机名添加到远程 server.xml:

<iiopEndpoint id="defaultIiopEndpoint" host="my.host.name" iiopPort="2809" />

我还向我的客户端 pod 添加了主机别名:

hostAliases:
- ip: {remote.server.service.ip.here}
  hostnames:
  - my.host.name

最后,我将 JNDI 名称更改为:

corbaname::my.host.name:2809#ejb/global/some-app/ejb/BeanName!org\.example\.com\.BeanRemote

通过此设置,成功调用了远程服务器!

但是,现在我有另一个问题,我在 Docker 主机上测试时没有遇到。查找完成,但我得到的不是我期望的。

查找代码与您所期望的差不多:

Object obj = new InitialContext().lookup(jndi);
BeanRemote remote = (BeanRemote) PortableRemoteObject.narrow(obj, BeanRemote.class);

不幸的是,这个狭窄的调用失败了 ClassCastException:

Caused by: java.lang.ClassCastException: org.example.com.BeanRemote
    at com.ibm.ws.transport.iiop.internal.WSPortableRemoteObjectImpl.narrow(WSPortableRemoteObjectImpl.java:50)
    at [internal classes]
    at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:62)

我收到的对象是 org.omg.stub.java.rmi._Remote_Stub。有什么想法吗?

解决了!

因此,第一个问题是解决主机映射问题,正如上面编辑中提到的那样,通过添加主机别名 id pod 定义来解决:

远程吊舱:

hostAliases:
- ip: 0.0.0.0
  hostnames:
  - my.host.name

客户端:

hostAliases:
- ip: {remote.server.service.ip.here}
  hostnames:
  - my.host.name

然后远程服务器必须在 iiop 主机定义中使用该主机名:

<iiopEndpoint id="defaultIiopEndpoint" host="my.host.name" iiopPort="2809" />

此外,客户端必须通过 JNDI 查找引用该主机名:

corbaname::my.host.name:2809#ejb/global/some-app/ejb/BeanName!org\.example\.com\.BeanRemote

此设置解决远程 EJB 调用。

ClassCastException 的另一个问题真的很不寻常。我设法在 Docker 主机上重现了错误,然后一次更改一件事,直到问题得到解决。事实证明,问题出在 ldapRegistry-3.0 特征 (!?) 上。将此功能添加到客户的功能列表解决了我的问题:

<feature>ldapRegistry-3.0</feature>

添加此功能后,成功调用远程EJB。