Docker容器中ASP.NET Core 8 Web API DNS解析失败求助
问题背景
我开发了一个ASP.NET Core 8.0 Web API,通过以下代码获取连接客户端的hostname:
String? ip = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); if (String.IsNullOrEmpty(ip)) { throw new ArgumentNullException("No Ip found."); } String hostname = Dns.GetHostEntry(ip).HostName; if (String.IsNullOrEmpty(hostname)) { return ip; } return hostname;
该代码在Visual Studio中运行正常,但部署到Docker容器后抛出异常:
System.Net.Sockets.SocketException (00000005, 0xFFFDFFFF): Name or service not known
at System.Net.Dns.GetHostEntryOrAddressesCore(IPAddress address, Boolean justAddresses, AddressFamily addressFamily, Nullable`1 startingTimestamp)
at System.Net.Dns.GetHostEntry(String hostNameOrAddress, AddressFamily family)
at[上述自定义代码]
需要说明的是,我使用的是公司内部DNS,要解析的是内网IP对应的hostname。我尝试过在docker run命令中指定--dns=[dns_ip],并修改daemon.json配置,Dockerfile为Visual Studio生成的默认文件,但问题依旧。
已尝试的操作
- Docker run命令:
docker run -t -d -p 50000:8080 -p 50001:8081 -e ASPNETCORE_ENVIRONMENT=Development --dns=[dns_ip] --name testcontainer [my_image]:latest - daemon.json内容:
{ "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "dns-opts": [ "ndots:15" ], "experimental": false } - Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app WORKDIR /app EXPOSE 8080 EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Debug WORKDIR /src COPY ["MyProj/MyProj.csproj", "MyProj/"] COPY ["MyLib/MyLib.csproj", "MyLib/"] RUN dotnet restore "./MyProj/MyProj.csproj" COPY . . WORKDIR "/src/MyProj" RUN dotnet build "./MyProj.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Debug RUN dotnet publish "./MyProj.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "MyProj.dll"] - 尝试通过Docker Desktop exec在容器内解析hostname,但容器shell不支持相关命令。
解决方案
1. 验证容器内DNS解析能力
你使用的mcr.microsoft.com/dotnet/aspnet:8.0镜像基于Debian,默认未安装DNS测试工具,先进入容器安装工具:
# 进入容器 docker exec -it testcontainer bash # 切换到root用户(app用户无安装权限) su root # 更新源并安装dnsutils apt update && apt install -y dnsutils
安装完成后,直接测试内网IP的反向解析:
# 用公司DNS服务器解析目标IP nslookup [你的内网IP] [公司DNS IP]
如果命令能返回正确hostname,说明DNS配置没问题,问题出在代码;如果仍报错,说明容器DNS配置未生效。
2. 修正Docker的DNS配置
当前daemon.json未配置默认DNS服务器,添加公司DNS地址:
{ "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "dns": ["[公司DNS IP]"], "dns-opts": [ "ndots:15" ], "experimental": false }
修改后重启Docker服务:
- Linux:
sudo systemctl restart docker - Docker Desktop:在设置中点击"Restart"按钮
重启后重新创建容器,无需再指定--dns参数,容器会自动使用配置的DNS。
3. 优化代码的异常处理
内网环境中部分IP可能无法反向解析,代码需捕获SocketException,避免服务崩溃,同时返回IP作为备用:
String? ip = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); if (String.IsNullOrEmpty(ip)) { throw new ArgumentNullException("No Ip found."); } try { var hostEntry = Dns.GetHostEntry(ip); return !string.IsNullOrEmpty(hostEntry.HostName) ? hostEntry.HostName : ip; } catch (SocketException) { // 解析失败时直接返回IP return ip; }
4. 检查容器网络模式(测试环境可选)
如果默认桥接网络存在解析问题,可尝试使用host网络模式运行容器(注意:host模式下容器直接使用主机网络,无需端口映射):
docker run -t -d --network host -e ASPNETCORE_ENVIRONMENT=Development --name testcontainer [my_image]:latest
该模式下容器与主机共享网络栈,DNS配置和主机一致,能快速验证是否为网络模式导致的问题,但生产环境不建议使用,会暴露主机端口。
5. 确认Docker run命令的--dns参数格式
若不想修改daemon.json,直接用--dns参数时需确保格式正确:不要加括号,直接写IP,例如:
docker run -t -d -p 50000:8080 -p 50001:8081 -e ASPNETCORE_ENVIRONMENT=Development --dns=192.168.1.10 --name testcontainer [my_image]:latest
内容的提问来源于stack exchange,提问作者Juli Krajewski

