无法从在 Docker (Linux) 中运行的 ASP.NET Core 连接到 SQL Server 命名实例

Posted

技术标签:

【中文标题】无法从在 Docker (Linux) 中运行的 ASP.NET Core 连接到 SQL Server 命名实例【英文标题】:Can't connect to SQL Server named instance from ASP.NET Core running in Docker (Linux) 【发布时间】:2019-10-21 17:47:33 【问题描述】:

我有一个应用程序应该使用命名实例连接到在远程服务器上运行的 SQL Server。

使用 IISExpress,我可以连接到 SQL Server,但是从 Docker(Linux 容器)它失败了 - 访问上下文时它只是挂起 - 没有抛出异常或错误消息。例如

var context = serviceScope.ServiceProvider.GetService<AppContext>();
context.Users.ToList();

在调试器中它永远不会到达异常处理程序。

相反,我看到很多这样的输出:

The thread 125 has exited with code 0 (0x0).
The thread 164 has exited with code 0 (0x0).
The thread 0xa4 has exited with code 0 (0x0).

使用 node.js,我甚至可以毫无问题地从 docker 连接到 SQL Server。

当我使用例如[ipaddress or host.docker.internal],1433 - 不幸的是,在远程 SQL Server 上,我无法配置固定端口。

使用 IISExpress 工作(因此在 Windows 上运行) 使用固定端口而不是命名实例连接到在开发计算机上运行的 SQL Server 时有效(但我无法更改我们的生产服务器) 在使用 node.js 时有效!来自 docker 也带有命名实例(两者:带有主机名或 IP 地址 - 所以我可以解析远程名称,防火墙不是问题) 尝试使用 Microsoft 容器作为基础的 ASP.NET Core 2.2 和 3.0preview5,例如FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS 基础

连接字符串:

"Data Source=remoteIP\\WEBDB;Initial Catalog=TestDB;User ID=testuser;Password=******;"

还尝试使用“Integrated Security=False;”在连接字符串中

服务器身份验证设置为混合

我可以重现这也是没有实体框架:

var conString = "Data Source=remoteIP\\WEBDB;Initial Catalog=TestDB;Integrated Security=False;User ID=testuser;Password=********";

using (SqlConnection conn = new SqlConnection(conString))
using (SqlCommand cmd = new SqlCommand("SELECT * FROM Users", conn))

   conn.Open();
   var rows = cmd.ExecuteNonQuery();
   Console.WriteLine($"rows: rows");

它会挂在conn.Open();线上。

知道我能做什么吗?

更新:

输入的连接字符串不正确。 完整示例更新代码

编辑

这行得通:

var conString = "Data Source=10.0.75.1,1433;Initial Catalog=TestDB;Integrated Security=False;User ID=testuser;Password=********";

这不起作用:

var conString = "Data Source=10.0.75.1\\Developer;Initial Catalog=TestDB;Integrated Security=False;User ID=testuser;Password=********";

我可以 ping 远程 IP 地址以及远程服务器名称。

不幸的是,由于缺少依赖项,在 ubuntu 映像上安装 mssql-cli 失败。

【问题讨论】:

只使用 一个 反斜杠,如果需要转义则使用两个。 尝试将remoteIP\\WEBDB改为ServerName\InstanceName,如果ServerName解析失败,尝试使用FQDN 【参考方案1】:

我知道你解决了这个问题。 我只是为其他人添加更多。 类型

ipconfig

我们可以看到网络的IP

Ethernet adapter vEthernet (DockerNAT):

   Connection-specific DNS Suffix  . :
   IPv4 Address. . . . . . . . . . . : 10.0.75.1
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . :

如果我们在 IIS 上运行应用程序,我们可以使用上述 IP。 但是,如果我们在 docker 上运行,应用程序将无法连接到数据库。

Server=172.17.0.2;Database=VoiconCrochet;User Id=sa;Password=P@ssw0rd123;

【讨论】:

【参考方案2】:

Issue #222 in SqlClient repository 解释了问题。

我已经验证这两个选项都适合我:

将基础 Docker 映像文件从 mcr.microsoft.com/dotnet/core/aspnet:3.1.0-buster-slim 更改为 mcr.microsoft.com/dotnet/core/aspnet:3.1.0-bionic

在我的 docker 文件中添加一些步骤:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.0-buster-slim AS final
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
. . .

【讨论】:

【参考方案3】:

尝试将“Connect Timeout=60”添加到您的连接字符串中。

【讨论】:

【参考方案4】:

我正在使用 Docker 容器化应用程序。我添加了如下的连接字符串,

services.AddDbContext<OrderContext>(options =>
            
                options.UseSqlServer(Configuration["ConnectionString"]);
            );

我的连接字符串如下:

Server=sqlserver ; Database=CustomerDb; User Id=sa;Password=8jkGh47hnDw89Haq8LN2

sqlserver是运行在docker上的sql镜像,

sqlserver:
    image: microsoft/mssql-server-linux:latest
    container_name: sqlserver
    ports:
      - "7100"
    environment:
      - ACCEPT_EULA=Y 
      - MSSQL_PID=Developer
      - SA_PASSWORD=8jkGh47hnDw89Haq8LN2

【讨论】:

你在生产中也使用 sql server 容器吗? 目前尚未投入生产。但我可以在本地 docker 中运行它。【参考方案5】:

Data Source 是错误的。命名实例仅使用一个反斜杠。正确的来源是:

remoteIP\WEBDB

反斜杠 needs to be escaped 仅当字符串存储在需要这种转义的介质中时,例如在 C# 字符串或 JSON 字符串中。对于 C#、JSON、javascript 和 C++ 相关语言,转义字符是反斜杠本身,例如:

var connectionString="Data Source=remoteIP\\WEBDB;Initial Catalog=TestDB;User ID=testuser;Password=******;"


    "ConnectionStrings": 
        "BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
    ,

文字 C# 字符串、XML 或 INI 文件不需要转义。以下 C# 行不需要转义。

var connectionString=@"Data Source=remoteIP\WEBDB;Initial Catalog=TestDB;User ID=testuser;Password=******;"

编辑

修复名称只是可能出错的一件事。当 DNS 尝试将无法识别的字符串解析为有效 IP 时,错误的地址很容易将应用程序交给应用程序。

另一个问题是docker容器默认没有网络连接。您必须指定它们可以连接的内容以及内部 IP 和端口如何映射到外部 IP 和端口。

您可以使用 SQL Server CLI 工具 mssql-cli 来测试与服务器的连接,而无需运行您自己的应用程序:

mssql-cli -S InternallyMappedIP\WEBDB -d TestDB -U testuser

【讨论】:

感谢您的快速回复。不幸的是,这不是代码中的问题。我更新了这个例子。正如我所说:如果我在 Windows 上的 IISExpress 中运行它,它会毫无问题地连接,并且不会更改代码 @Norman78 什么也没说。在您配置容器之前,容器没有外部网络连接。 是否您已将容器配置为连接到远程 IP 和端口?使用mssql-cli 从命令行测试连接性,无需每次都启动自己的应用程序 好吧,多做一些实验:我现在使用的不是 buster-slim 图像,而是 3.0.0-preview5-disco,因为它包含更多工具。 ping 服务器工作,如果我使用 10.0.75.1,1433 它工作,如果我使用 10.0.75.1\\Developer 它不

以上是关于无法从在 Docker (Linux) 中运行的 ASP.NET Core 连接到 SQL Server 命名实例的主要内容,如果未能解决你的问题,请参考以下文章

如何从在 AWS ecs 上使用 docker 部署的应用程序获取日志

是否可以从在 Wine 中运行的 Windows 应用程序调用本机 Linux API?

无法在 Docker 容器中运行命令

无法通过使用newman docker run文档中提供的步骤与docker运行newman集合

从在 QThread 中运行的 C 代码显示 QMessageBox

从在 ElasticBeanstalk 中运行的 Flask 应用程序使用 AWS