【问题标题】:Trouble communicating between two docker containers两个 docker 容器之间的通信问题
【发布时间】:2018-07-15 03:55:54
【问题描述】:

我是 docker 新手,我正在尝试将运行在 boot-example docker 容器中的 spring boot 应用程序连接到运行在 mymysql 中的 mysql 服务器6603 端口上的 docker 容器,两者都在同一台物理机器上运行。 事实是:如果我将我的 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 application.properties是:

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 应用程序在端口 8082 上的 docker 容器中运行之前,它可以正常工作,(在正确构建 docker 映像之后):

docker run -it -p 8082:8083 boot-example 

【问题讨论】:

    标签: java mysql spring docker spring-boot


    【解决方案1】:

    您不能在容器内使用localhost,它是容器本身。因此,您将始终收到连接被拒绝错误。

    你可以做以下事情 -

    1. 在您的 Spring Boot 应用程序的 application.properties 文件中添加您的主机 IP。 (不推荐,因为它破坏了 docker 可移植性逻辑)

    2. 如果您想使用localhost,请在启动容器时使用--net=host(不推荐用于生产,因为不存在逻辑网络层)

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

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

    PS - 每当您需要将多个容器集成在一起时,请始终使用docker-compose version 3+。使用docker run|build 了解基本原理并进行试运行。

    【讨论】:

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

    正如@vivekyad4v 建议的那样 - 实现您的愿望的最简单方法是使用具有更好容器通信集成的docker-compose

    Docker-compose 是一个用于管理单个或多个 docker 容器的工具。它使用一个名为docker-compose.yml的配置文件。

    有关 docker-compose 的更多信息,请查看 documentationcompose file reference

    根据我的经验,遵循 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
    

    注意:网络内容器之间的通信可以通过在容器内调用service name来实现。

    从 PHP 到 MySQL 容器的连接参数,在这个例子中是:

    hostname: mysql
    port: 3306
    database: backend
    user: root
    password: root
    

    【讨论】:

      【解决方案3】:

      根据上述建议,Docker-compose 是一种方法,但如果您不想使用 compose/swarm 模式。

      1. 只需使用docker network create myNet 创建您自己的网络
      2. 部署您的容器侦听创建的网络--network myNet
      3. 将 spring.datasource.url 更改为 jdbc:mysql://mymysql:6603/mydockerdb

      通过使用 docker demo 的 DNS 解析,容器可以发现彼此,从而进行通信。 [默认网桥不支持DNS。使用网桥的用户定义网络。]

      欲了解更多信息:https://docs.docker.com/engine/userguide/networking/

      【讨论】:

      • 感谢您的回答,使用网络您可以加入识别同一网络的两个容器。但是,如果我只想将我的 mysql 容器部署到两个单独的服务器呢?我想像所有传统连接一样连接两个容器,它们只有它们的地址和端口。
      • 您的意思是在另一台服务器上部署 MySQL 容器,然后将它与在另一台服务器上运行的另一个容器连接起来?请说清楚。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多