java.net.ConnectException: Время ожидания операции (Время ожидания соединения) при подключении докера mysql с локальной машины

#java #mysql #scala #docker #apache-spark

Вопрос:

Я пытаюсь подключиться к контейнеру mysql, который работает на локальной обработке, используя код scala. По какой-то причине я получаю либо время ожидания операции(dockerIp), либо ошибку отказа в подключении(localhost/127.0.0.1).

 docker run --name=mysql-docker -p3306:3306 -e MYSQL_ROOT_PASSWORD='root' -d mysql:latest
docker exec -it mysql-docker bash
mysql -u root -p
update mysql.user set host = ‘127.0.0.1’ where user=’root’;
 

Я могу подключиться к докеру с терминала, используя mysql -h 127.0.0.1 -P 3306 -u root -p

Ниже приведен мой код scala.

   val url = "jdbc:mysql://172.17.0.2:3006/mysql"
  val driver = "com.mysql.jdbc.Driver"
  val username = "root"
  val password = "root"
  Class.forName("com.mysql.jdbc.Driver")
  val connection = DriverManager.getConnection(url, username, password)
  val statement = connection.createStatement
  val rs = statement.executeQuery("SELECT host, user FROM user")
  connection.close
 

К сожалению, этот код вызывает

 
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
        at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:828)
        at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:448)
        at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241)
        at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198)
        at java.sql.DriverManager.getConnection(DriverManager.java:664)
        at java.sql.DriverManager.getConnection(DriverManager.java:247)
        at largedataprocessor.LargeDataProcessor$.delayedEndpoint$largedataprocessor$LargeDataProcessor$1(LargeDataProcessor.scala:35)
        at largedataprocessor.LargeDataProcessor$delayedInit$body.apply(LargeDataProcessor.scala:9)
        at scala.Function0.apply$mcV$sp(Function0.scala:39)
        at scala.Function0.apply$mcV$sp$(Function0.scala:39)
        at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
        at scala.App$anonfun$main$1.apply(App.scala:76)
        at scala.App$anonfun$main$1.apply(App.scala:76)
        at scala.collection.immutable.List.foreach(List.scala:431)
        at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
        at scala.App$class.main(App.scala:76)
        at largedataprocessor.LargeDataProcessor$.main(LargeDataProcessor.scala:9)
        at largedataprocessor.LargeDataProcessor.main(LargeDataProcessor.scala)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: 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)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
        at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)
        at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:89)
        at com.mysql.cj.NativeSession.connect(NativeSession.java:119)
        at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:948)
        at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:818)
        ... 17 more
Caused by: java.net.ConnectException: Operation timed out (Connection timed out)
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:607)
        at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:156)
        at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:63)
        ... 20 more
 

Вместо этого, если я использую «jdbc:mysql://127.0.0.1:3006/mysql», я получаю сообщение об ошибке отказа в подключении.

Пожалуйста, укажите на мою ошибку.

Ответ №1:

С точки зрения сети, какой-то докеризованный процесс выполняется на другом хосте, чем не докеризованные. Таким образом, подключение к localhost контейнеру или 127.0.0.1 внутри него приведет к обратному подключению к тому же контейнеру, где ничто не прослушивается на порту 3306 — вы правильно поняли connection refused .

Если вы попытаетесь подключиться к IP-адресу вашего хоста через порт 3306, вы можете либо

  • получите отказ в подключении, если ваш mysql прослушивает только localhost:3306
  • получите тайм-аут, если брандмауэр вашего хоста блокирует доступ

Обязательно настройте оба элемента, прежде чем ожидать успеха.

Другим вариантом было бы запустить ваш контейнер в сети хоста. Тогда нет необходимости раскрывать порт (он все равно открыт), и подключение к локальному хосту должно дать вам ожидаемый эффект.

Возможно, вам захочется поближе познакомиться с сетями Docker.

Правка: До сих пор я пытался объяснить, почему вы воспринимаете результаты, о которых вы упомянули. Все работает так, как задумано. Итак, теперь давайте выясним, что вам нужно сделать, чтобы получить подключение:

  • имейте в виду, что 127.0.0.1 не будет работать
  • настройте mysql внутри контейнера для прослушивания 0.0.0.0:3306
  • запустите контейнер с-p 3306:3306
  • откройте брандмауэр вашего хоста, чтобы разрешить трафик на :3306
  • запустите клиентское приложение и попробуйте подключиться по адресу :3306

Комментарии:

1. Приложение работает в моем локальном, а не в контейнере. И IP-адрес контейнеров mysql 172.17.0.2, использование которого выдает ошибку тайм-аута. Когда вы говорите брандмауэр хостов, означает ли это брандмауэр mac ?

2. На самом деле, под докеризованным приложением я имел в виду ваш mysql. Теперь отредактировано, чтобы сделать его более нейтральным. Применимо ли это сейчас?

3. Ладно, понял эту часть. Как насчет 2-го пункта, брандмауэра хоста, предотвращающего доступ? Как мне это обойти ? Также вы упомянули о запуске контейнера в сети хоста (я предполагаю, что mysql), но разве я уже этого не делаю, я имею в виду, предоставляя порт?

4. Сегодня многие операционные системы поставляются с брандмауэром, активированным по умолчанию. Чтобы не показывать злоумышленникам, что есть машина, которая может быть атакована, они предотвращают сообщения «отказано в подключении», если не указано иное. Вы подключаетесь к IP/порту, который виден снаружи вашего компьютера, поэтому брандмауэр может перехватить пакеты и решить не отвечать. В зависимости от того, какую систему вы используете, вам просто придется перенастроить ее, чтобы разрешить трафик.

5. Если это уже работает, возможны TCP-соединения из-за пределов контейнера с вашей базой данных. В этом случае просто выясните, почему ваше приложение scala не выполняет то же TCP-соединение, что и клиент mysql.