两个Docker容器之间通信出现问题

5
我是一名新手,正在学习Docker,并尝试将我的运行中的Spring Boot应用连接到在同一物理机上运行的端口为6603的mymysql Docker容器中的MySQL服务器。事实上,如果我将我的Spring Boot应用连接到mymysql Docker容器以便与数据库通信,我不会遇到任何错误,一切都正常。 但是,当我将我的Spring Boot应用程序移动到boot-example容器中并尝试通过Hibernate与mymysql容器通信时,我会遇到以下错误:
2018-02-05 09:58:38.912 ERROR 1 --- [           main] o.a.tomcat.jdbc.pool.ConnectionPool      : Unable to create initial connections of pool.

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]

我的Spring Boot应用程序属性文件如下:

server.port=8083
spring.jpa.hibernate.ddl-auto=create-drop
spring.datasource.url=jdbc:mysql://localhost:6603/mydockerdb
spring.datasource.username=root
spring.datasource.password=mypassword

我的Spring Boot应用程序在正确构建Docker镜像后,在端口8082上运行时出现问题:

docker run -it -p 8082:8083 boot-example 
3个回答

11

在容器内部无法使用localhost,因为它指的是容器本身。因此,您将始终收到连接被拒绝的错误。

您可以执行以下操作 -

  1. 在您的Spring Boot应用程序的application.properties文件中添加您的主机IP地址。(不建议,因为它会破坏Docker的可移植性逻辑)

  2. 如果您想使用localhost,请在启动容器时使用--net=host(不建议在生产环境中使用,因为没有逻辑网络层存在)

  3. 使用--links与DNS名称进行容器通信。(已弃用/遗留)

  4. 创建一个Compose文件,并通过服务名称从Spring Boot应用程序调用您的数据库,因为它们将位于同一网络中并高度集成。 (推荐)

附注 - 每当您需要将多个容器组合在一起时,始终使用docker-compose版本3+。 使用docker run|build来了解基础知识并进行干试运行和测试。


我建议使用链接进行容器通信。内部的Spring Boot application.yml可以准备使用特定的主机名来连接MySQL数据库,例如“jdbc:mysql://mydatabase:6603/mydockerdb”。 如果我们想在开发过程中拥有本地数据库,可以有一个特殊的“application-dev.yml”文件,其中包含指向数据库的localhost URL。通过启用“dev” Spring配置文件,可以激活此配置。 - Georg Wittberger
我使用了--net=host,它可以工作,但是...即使我将Java容器映射为-p 8082:8083,我的Spring Boot服务仍然在端口8083上可用,而不是Docker端口的8082...为什么?谢谢! - Alessandro Argentieri
由于您的容器在主机网络上启动,它使用主机TCP端口空间来公开容器内运行的服务。当您开始使用 --net=host 时,Docker网络不会以相同的方式工作。将其视为在主机机器上运行的另一个进程,没有任何隔离的网络。 - vivekyad4v

6
正如 @vivekyad4v 建议的那样 - 实现您的愿望最简单的方法是使用 docker-compose,它具有更好的容器通信集成。
Docker-compose 是用于管理单个或多个 docker 容器的工具。它使用一个称为 docker-compose.yml 的单个配置文件。
要获取有关 docker-compose 的更多信息,请查看 文档compose 文件参考
在我的经验中,遵循 SRP(单一职责原则)是一个好的实践,因此 - 为您的数据库创建一个容器,为您的应用程序创建另一个容器。它们都使用您在配置中指定的网络进行通信。
以下是 docker-compose.yml 的示例可能会对您有所帮助:
version: '2'
 networks: 
 # your network name
  somename:
    driver: bridge

services:
   # PHP server
  php:
   image: dalten/php5.6-apache
   ports:
    - 80:80
   volumes:
    - .application_path:/some/application/path
   # your container network name defined at the beggining 
   networks: 
    - somename

   # Mysql server for backend
  mysql:
   image: dalten/mysql:dev
   ports:
    - 3306:3306
   # The /var/lib/mysql volume MUST be specified to achieve data persistence over container restart
   volumes:
    - ./mysql_data:/var/lib/mysql
   environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_DATABASE: backend
   # your container network name defined at the beggining 
   networks: 
      - somename

注意:容器内部的通信可以通过从容器内部调用“服务名称”来实现。
在本例中,从PHP连接到MySQL容器的连接参数为:
hostname: mysql
port: 3306
database: backend
user: root
password: root

2
根据上述建议,如果您不想使用compose/swarm模式,可以使用Docker-compose。以下是具体步骤:
  1. 使用docker network create myNet创建自己的网络。
  2. 在创建的网络上部署容器--network myNet
  3. spring.datasource.url更改为jdbc:mysql://mymysql:6603/mydockerdb
通过使用Docker守护进程的DNS解析功能,容器可以相互发现并进行通信。[默认桥接网络不支持DNS。需要使用用户定义的桥接网络。]
了解更多信息,请访问:https://docs.docker.com/engine/userguide/networking/

谢谢您的回答,使用网络,您可以加入两个识别相同网络的容器。但是,如果我只想在两个独立的服务器上部署我的mysql容器怎么办?我希望连接这两个容器,只需使用它们的地址和端口,就像所有传统的连接一样。 - Alessandro Argentieri
你的意思是在不同的服务器上部署MySQL容器,并从另一个运行在另一台服务器上的容器连接它吗?请澄清一下。 :) - ThunderStorm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接