#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.