使用 .NET 8 时无法从 Docker 容器连接到 SQL Server

Cannot connect to SQL Server from a Docker container when using .NET 8

提问人:Emiliyan Ivanov Angelov 提问时间:11/16/2023 最后编辑:Emiliyan Ivanov Angelov 更新时间:11/17/2023 访问量:129

问:

我有一个仅连接到本地 SQL Server 的 .Net 8 控制台应用程序。 当我在 docker 中运行(使用 Visual Studio 2022)应用程序时,出现以下错误:

System.Exception
  HResult=0x80131500
  Message=Cannot connect to SQL Server Browser. Ensure SQL Server Browser has been started.
  Source=Microsoft.Data.SqlClient
  StackTrace:
   at Microsoft.Data.SqlClient.SNI.SSRP.GetPortByInstanceName(String browserHostName, String instanceName, Int64 timerExpire, Boolean allIPsInParallel, SqlConnectionIPAddressPreference ipPreference)
   at Microsoft.Data.SqlClient.SNI.SNIProxy.CreateTcpHandle(DataSource details, Int64 timerExpire, Boolean parallel, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename)
   at Microsoft.Data.SqlClient.SNI.SNIProxy.CreateConnectionHandle(String fullServerName, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Byte[]& instanceName, Byte[][]& spnBuffer, String serverSPN, Boolean flushCache, Boolean async, Boolean parallel, Boolean isIntegratedSecurity, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename)
   at Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged.CreatePhysicalSNIHandle(String serverName, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Byte[]& instanceName, Byte[][]& spnBuffer, Boolean flushCache, Boolean async, Boolean parallel, SqlConnectionIPAddressPreference iPAddressPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, String serverSPN, Boolean isIntegratedSecurity, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename)
   at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnectionString connectionOptions, Boolean withFailover)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)
   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open()
   at ConsoleApp_Test.Program.Main(String[] args) in C:\Users\eangelov\source\repos\ConsoleApp_Test\Program.cs:line 10

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
SocketException: Name or service not known

法典:

string connString = "Data Source=ServerName\\INST1;Initial Catalog=MyDB;User Id=MyUser;Password=MyUserPass;Integrated Security=False;Encrypt=False";
using SqlConnection dbConn = new( connString );
dbConn.Open();
Console.WriteLine( "Hi" );

Docker 文件:

FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ConsoleApp_Test.csproj", "."]
RUN dotnet restore "./././ConsoleApp_Test.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./ConsoleApp_Test.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./ConsoleApp_Test.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ConsoleApp_Test.dll"]

NuGet 包:

  1. Microsoft.Data.SqlClient 5.1.2
  2. Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.19.5

我尝试将应用程序更改为使用 .Net 6 和 .Net 7,它工作成功,连接到 SQL Server 实例。还尝试通过 IP(“IP\INST1”) 连接,结果是一样的,当使用 .Net 8 时它会中断,而当使用 .Net 6/7 时它会起作用。

软件:

  1. Visual Studio Community 2022(64 位)版本 17.8.0
  2. SQL Server 2019
  3. Docker 桌面 4.25.1

Docker 文件 .Net 7:

FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ConsoleApp_Test.csproj", "."]
RUN dotnet restore "./././ConsoleApp_Test.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./ConsoleApp_Test.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./ConsoleApp_Test.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ConsoleApp_Test.dll"]
sql-server docker net-8.0

评论

2赞 David Browne - Microsoft 11/16/2023
“无法连接到 SQL Server 浏览器。确保 SQL Server 浏览器已启动。你这样做了吗?或者将 SQL Server 配置为侦听固定端口,并连接到该端口。
0赞 Emiliyan Ivanov Angelov 11/16/2023
我不认为问题出在SQL Server上。如果将应用程序的目标从 .Net 8 更改为 .Net 7 或 6,并将 dockerfile 更改为使用 .Net 7/6 的图像,则代码有效,它仅在我以 .Net 8 为目标时中断
0赞 Troy Berg 11/17/2023
我遇到了类似的问题,尽管我的报告了握手错误。在 wireshark 中观看,在 Windows 中运行我的测试应用程序,它在“Client Hello”条目上报告 TLSv1.2。在 docker/wsl 中运行,它报告 TLSv1。 将项目和 dockerfile 更改为使用 .net 6,它适用于所有环境。到目前为止,将 openssl.cnf 设置为 docker 映像尚未发生任何更改(并且在 .net 6 中需要它才能运行)。最里面的错误是“error:0A0000B5:SSL routines::no ciphers available” 我已经通过交互式会话进行了检查,并且环境中有可用的 TLSv1.2 密码
1赞 AlwaysLearning 11/17/2023
您是否尝试过使用任何变体来查看问题是否是由特定发行版引起的@EmiliyanIvanovAngelov?例如:、 或 .mcr.microsoft.com/dotnet/runtime:8.0-bookworm-slimmcr.microsoft.com/dotnet/runtime:8.0-alpinemcr.microsoft.com/dotnet/runtime:8.0-jammy
1赞 Emiliyan Ivanov Angelov 11/17/2023
@AlwaysLearning 使用 8.0-jammy 可以按预期工作,其他的会中断

答: 暂无答案