无法使用网桥网络模式从docker容器连接到远程SQL服务器



我有一个由四台Ubuntu 20.04机器组成的Docker Swarm。我想以复制的方式运行许多不同的应用程序。其中一个应用程序是API,它从运行在命名实例上的远程SQL Server进行读取。

如果我指定主机网络模式,我可以连接到SQL Server,但这并不理想,因为我将无法映射将来要运行的其他服务的端口。这也感觉像是一个黑客。

这是我的docker撰写文件,名为scapi-stack.yaml

version: '3.7'
services:
sc-api:
command: [ "--privileged" ]
image: #private repo image
deploy:
replicas: 4
restart_policy:
condition: on-failure
ports:
- "51955:51955" #SQL Server instance port
- "8443:443"
- "8080:80"
environment:
- ASPNETCORE_URLS=http://+:80
- ASPNETCORE_URLS=https://+:443

这是我运行服务的命令:

docker stack deploy --compose-file scapi-stack.yaml scapi

如果我对一个容器执行docker attach并导航到8080端口,我会看到以下错误:

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred
while establishing a connection to SQL Server. The server was not found or was not accessible. 
Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)

我已尝试指定--privileged命令,但没有成功。我还尝试过将主要图像更改为仿生、焦点和大片苗条。我也试过下载.Net Core 3.1,但没有什么不同。我还运行了这个答案中的这两个命令:

sysctl net.ipv4.conf.all.forwarding=1
sudo iptables -P FORWARD ACCEPT

我能让它工作的唯一方法是使用主机网络,但这违背了目的。

图像的dockerfile是这样的:

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
EXPOSE 51955
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["SCAPI/SCAPI.csproj", "SCAPI/"]
COPY ["src/Infrastructure/Infrastructure.csproj", "src/Infrastructure/"]
COPY ["src/Application/Application.csproj", "src/Application/"]
COPY ["src/Domain/Domain.csproj", "src/Domain/"]
RUN dotnet restore "SCAPI/SCAPI.csproj"
COPY . .
WORKDIR "/src/SCAPI"
RUN dotnet build "SCAPI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "SCAPI.csproj" -c Release -o /app/publish
FROM base AS final
#Enable connections with TLS 1.0
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "SCAPI.dll"]

我错过了什么?如何在不使用主机网络的情况下指定端口以启用与SQL Server的通信?

更新

我尝试连接的SQL服务器位于群之外的Windows计算机上。如果我删除端口映射并在我的合成文件中指定"主机"网络,我可以连接到它:

version: '3.7'
services:
sc-api:
command: [ "--privileged" ]
image: #private repo image
deploy:
replicas: 4
restart_policy:
condition: on-failure
environment:
- ASPNETCORE_URLS=http://+:80
- ASPNETCORE_URLS=https://+:44
networks:
- host
networks:
host:
name: host
external: true

但正如Docker官方文档中所描述的那样,这也有缺点

如果对容器使用主机网络模式,则该容器的网络堆栈不会与Docker主机隔离(容器共享主机的网络命名空间(,并且容器不会分配自己的IP地址。例如,如果运行绑定到端口80的容器,并且使用主机网络,则容器的应用程序在主机IP地址的端口80上可用。

留给后人

因此,在花了近60个小时在互联网上搜索线索并尝试了一百万种不同的事情后,这一问题终于得到了解决。我甚至切换到了在同一台机器上运行的Kubernetes集群,但无济于事——我也遇到了同样的问题。

我的网络专家同事终于让我在其中一个linux盒子上安装了Wireshark,他发现流量正在从容器/吊舱中流出,通过linux盒子接口到达SQL服务器,但没有回来。

一段时间后,他发现来自swarm/kubernetes的IP地址没有伪装,核心网络交换机不知道如何将流量返回到容器/pod。

这些linux盒子是虚拟机。

快速sudo iptables --append POSTROUTING --table nat --out-interface ens160 --jump MASQUERADE其中"ens160"是网络接口,瞧!一切都很好。

此命令将所有容器/pod的IP地址转换为盒子的IP地址,反之亦然。

最新更新