【问题标题】:Docker communication between two containers with Java使用 Java 在两个容器之间进行 Docker 通信
【发布时间】:2017-03-28 19:47:16
【问题描述】:

有两个java文件,Server.java和Client.java。 两者都在不同的容器中。

码头工人文件: 我用于服务器的 dockerfile(在名为“Server”的文件夹中)是:

FROM java:8
COPY Server.java /
RUN javac Server.java
EXPOSE 25000
ENTRYPOINT ["java"]
CMD ["Server"]

客户端的dockerfile(在名为'Client'的文件夹中)是:

FROM java:8
COPY Client.java /
RUN javac Client.java
EXPOSE 25000
ENTRYPOINT ["java"]
CMD ["Client"]

构建容器: 使用sudo docker build -t serverimage .构建容器

运行容器: 我使用命令sudo docker run <IMAGE_NAME> 运行图像。我首先运行服务器图像。

我得到的错误(当我运行 clientimage 时)是:

java.net.ConnectException: Connection refused: connect

Server.java 文件:

import java.io.*;  
import java.net.*;  
public class MyServer {  
   public static void main(String[] args){  
       try{  
           ServerSocket ss=new ServerSocket(25000);  
           Socket s=ss.accept();//establishes connection   
           DataInputStream dis=new DataInputStream(s.getInputStream());  
           String  str=(String)dis.readUTF();  
           System.out.println("message= "+str);  
           ss.close();  
       }catch(Exception e){System.out.println(e);}  
   }  
}  

Client.java 文件:

import java.io.*;  
import java.net.*;  
public class MyClient {  
   public static void main(String[] args) {  
      try{      
         Socket s=new Socket("localhost",25000);  
         DataOutputStream dout=new DataOutputStream(s.getOutputStream());  
         dout.writeUTF("Hello Server");  
         dout.flush();  
         dout.close();  
         s.close();  
      }catch(Exception e){System.out.println(e);}  
   }  
}  

我可能做错了什么? 谢谢!

【问题讨论】:

  • 你做错的是从客户端连接到客户端(这就是“localhost”的意思——容器本身)。您可能想了解一下Docker networking。

标签: docker


【解决方案1】:

适用于现代 docker 版本 (1.13+)

要了解这种方法的错误之处,docker networking guide 包含所有复杂的细节,但它很大程度上归结为这样一个事实,即您不能简单地在一个容器中引用 localhost 并期望它路由到另一个容器在您的主机上运行的容器。

默认情况下,每个容器 runs on a bridge 网络,并且每个容器实际上都显示为该桥接网络上的单独主机,位于同一子网中。容器可以通过在桥接网络上分配的 IP 地址引用其他容器,但 localhost 只是指容器本身,而不是运行容器的底层主机。

要实现类似于您所追求的可预测路由,您可以define your own bridge network 并在该用户定义的网络上运行客户端和服务器容器。这确实需要在您的Client.java 中更改一点代码。而不是localhost,您必须使用选定的别名来寻址服务器,例如server。编辑客户端代码并重建 clientimage 后,请尝试以下操作:

  • 创建网络 - sudo docker network create client_server_network
  • 运行服务器 - sudo docker run --network-alias server --network client_server_network -it serverimage
  • 运行客户端 - sudo docker run --network client_server_network -it clientimage
  • 您应该会在服务器终端中看到message= Hello Server 打印

请注意,我为服务器的docker run 提供了一个额外的--network-alias server,以添加一个网络别名,客户端可以预测地访问服务器容器。您有多种实现该别名的方法,包括使用--name 选项,但请查看docker embedded dns docs 了解更多详细信息。

对于较旧的 docker 版本 (1.12-)

Docker 提供了一个container linking functionality,通过提供给docker run 的--link 选项公开。您将需要一些与上述相同的更新,特别是使用server 代替localhost,并使用--name server 运行服务器容器。 docker run 看起来像:

  • 运行服务器 - sudo docker run --name server -it serverimage
  • 运行客户端 - sudo docker run --link server -it clientimage
  • 您应该会在服务器终端中看到message= Hello Server 打印

【讨论】:

  • 成功了!谢谢
【解决方案2】:

有3个问题:

  1. 类应命名为 Server 和 Client,否则 Server.java 和 Client.Java 文件应分别命名为 MyServer.java 和 MyClient.java。
  2. 创建 Docker 容器时,会创建 2 个接口:localhost 和另一个用于与其他容器通信的接口。您应该将“localhost”更改为服务器容器 IP 或主机 IP。
  3. java 图像已弃用。

此外,客户端 Dockerfile 中不需要 EXPOSE 指令。

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 2021-01-06
    • 2018-11-10
    相关资源
    最近更新 更多