无法从在 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 命名实例的主要内容,如果未能解决你的问题,请参考以下文章