无法从 Docker 容器连接到外部 SQL Server

5
我开发了一个SpringBoot(Java)应用程序,它调用外部端口为1433的SQL Server。 SQL Server实例位于本地(不是本地SQL Server实例)。 但是,无论是使用IntelliJ还是SQL客户端,它都可以从我的桌面连接到该SQL Server实例。
我正在使用Microsoft SQL Server JDBC连接器与实例通信。
如果我从IntelliJ运行应用程序,一切正常,应用程序可以调用SQL Server,执行命令并返回结果集。
然而,现在我正在尝试将api应用程序Docker化。容器执行常规的SpringBoot初始化,但当它尝试调用SQL Server时,我会收到以下错误:
com.microsoft.sqlserver.jdbc.SQLServerException: The TCP/IP connection to the host myexternalsqlserver.domain, port 1433 has failed. Error: "myexternalsqlserver.domain. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall.".
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:234)
    at com.microsoft.sqlserver.jdbc.SQLServerException.ConvertConnectExceptionToSQLServerException(SQLServerException.java:285)
    at com.microsoft.sqlserver.jdbc.SocketFinder.findSocket(IOBuffer.java:2434)
    at com.microsoft.sqlserver.jdbc.TDSChannel.open(IOBuffer.java:659)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2546)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:2216)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:2067)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1204)
    at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:825)
    at java.sql/java.sql.DriverManager.getConnection(Unknown Source)
    at java.sql/java.sql.DriverManager.getConnection(Unknown Source)
    at com.symetra.SdsApi.SqlConnector.getResultSet(SqlConnector.java:26)

这是我的Docker文件。
FROM openjdk:11.0.4-jre-slim-buster
VOLUME /tmp

COPY target/myapi-1.0-SNAPSHOT.jar app.jar
EXPOSE 8080
EXPOSE 1433
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker -jar /app.jar" ]

以下是我用来构建和运行容器的Docker命令:
docker build -t myapi . && docker run -p 8080:8080 -p 1433:1433 --name myapi myapi "java","-jar","myapi-1.0-SNAPSHOT.jar"

我认为不必映射1433端口,这只是一个实验。我应该能够通过主机上的1433端口与容器外通信。由于在容器外运行时没有问题,因此主机上的1433端口没有被阻止。最后,这是我使用的连接字符串:
//Create Connection Url.
String connectionUrl="jdbc:sqlserver://myexternalsqlserver.domain:1433;database=mydb;user=MyUser;password=MyPassword";

我不确定在这里做错了什么。我想知道是否需要设置 Docker 网络。

感谢您的帮助!


谁解析了 myexternalsqlserver.domain 这个名称?它是本地主机还是你网络中的其他 IP?另外,你使用的是 Linux、Mac 还是 Windows? - theBittor
2个回答

0

应该可以工作。

NB 我假设你没有使用 myexternalsqlserver.domain

测试容器的一种方法是进入 shell(或创建变体)并尝试解析 SQL Server 的主机名:

docker run --interactive --tty openjdk:11.0.4-jre-slim-buster /bin/bash

# then from within the container's shell
apt update && apt install -y dnsutils
nslookup ${SQL_SERVER}

如果成功了,那就是你的代码没问题。
如果不行,那就是网络的问题。
注意:你的容器不需要发布1443端口(--publish=1433:1433),因为它只是在消耗SQL Server上的该端口,而不是暴露该端口本身。

我现在遇到了这个问题,当我尝试使用“apt”命令时出现以下错误:W: Failed to fetch http://deb.debian.org/debian/dists/buster/InRelease Could not resolve 'deb.debian.org' - KSS
我可以在浏览器中访问这些URL。 - KSS
清楚地说... 当您尝试运行 docker run --interactive --tty openjdk:11.0.4-jre-slim-buster /bin/bash -c "apt update && apt install -y dnsutils && nslookup google.com" 时会发生什么?那应该可以工作。如果不行,那么您有一个不同的问题。 - DazWilkin
它正在尝试访问deb.debian.org,但无法到达那里。因此,它甚至无法安装dnsutils。我认为我可能需要在etc/docker/daemon.json中添加我的dns网关的IP地址。我记得几个月前在拉取一些Python东西时不得不这样做。 - KSS
@KSS 你可以在 docker run 命令中使用 --dns 8.8.8.8 选项添加你的 DNS 网关。 - tziemek

0

同样的问题困扰了我好几天,最终通过以下步骤解决了它。

在我的情况下,SQL服务器托管在Azure托管实例上并公开了一个私有端点。Docker能够将Azure托管实例的DNS名称解析为私有IP地址(如预期)。但是,此解析的IP被docker网络/桥接视为本地运行的应用程序,因为在检查docker的桥接时(docker network inspect bridge),发现桥接的子网是一系列IP地址,其中SQL服务器的解析IP也属于其中之一。因此,docker认为SQL服务器托管在同一本地网络中而不是外部(这里是企业网络)。在我的情况下,我正在使用的Windows VM已经在企业的私有网络上。

解决方案:

在docker桌面版 -> 设置 -> Docker Engine json文件中,添加一个新的键值对"bip": "<解析sql服务器IP之外的本地IP地址范围>"。重新启动docker桌面版,问题应该得到解决。


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