我正在尝试在 k8s 中部署的 2 个 WebSphere Liberty 服务器之间设置远程 EJB 调用。 是的,我知道 EJB 不是人们在 k8s 中部署时想要使用的东西,但我现在必须处理它。
我遇到的问题是如何在 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中,我通过LoadBalancer服务为远程pod暴露了端口2809,并尝试从客户端pod访问远程服务器,我在corbaname定义中设置了远程的服务IP地址。 这当然是行不通的。我可以通过telnet访问远程ip:port,所以这不是网络问题。
我已经尝试了远程服务器上的所有设置组合。在 host="0.0.0.0"上导出结果出现与上述相同的异常(连接被拒绝)。
我不确定导出内部 IP 地址是否有效,但即使可以,在 pod 部署到 k8s 之前我也不知道内部 IP。或者有什么办法可以知道吗?没有环境。变量与它,我已经检查过。
暴露服务 IP 地址(主机 =“${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 定义来解决:
远程 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已成功调用。
关于kubernetes - Kubernetes 中的远程 EJB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64700043/