docker / for-linux

Docker Engine for Linux
https://docs.docker.com/engine/installation/
757 stars 86 forks source link

Docker .NET HTTPClient cannot assign requested address when host times out #1076

Open BainsDev opened 4 years ago

BainsDev commented 4 years ago

Expected behavior

When connecting to a host on a port behind a firewall using HTTPClient in a Docker Linux container via .NET (eg. http://google.com:8089), the request should time out and raise the following exception:

An unhandled exception of type 'System.Net.Http.HttpRequestException' occurred in System.Private.CoreLib.dll
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

Actual behavior

An unhandled exception of type 'System.Net.Http.HttpRequestException' occurred in System.Private.CoreLib.dll: 'Cannot assign requested address'
Stack trace:
 >   at System.Net.Http.ConnectHelper.<ConnectAsync>d__1.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Threading.Tasks.ValueTask`1.get_Result()
 >   at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()

Since Docker sits between the Linux kernel and the connect() call, the assumption is that the execution flow is something like this:

1) you attempt to make a request with C#'s HTTPClient 2) it calls the UNIX socket function connect() 3) the Linux kernel handles the connection 4) if the request takes too long to execute, it's cancelled by the kernel 5) Docker sees the kernel failed the connect() call

Therefore, Docker returns an error that it couldn't assign an address because it thinks the kernel refused an address:port assignment.

Setting the HTTPClient timeout to lower than the kernel limit to something like TimeSpan.FromSeconds(15) correctly raises a TaskCanceledException and not "cannot assign requested address".

Note: This issue does not exist when using Windows Containers. In addition, it does not occur when using barebones C to execute the same network request in a Linux container. It seems to be an issue with Docker and .NET.

Steps to reproduce the behavior

.Net Core Console application:

class Program
{
    static async Task Main(string[] args)
    {
        var client = new HttpClient();
        var result = await client.GetAsync("http://google.com:8089");
    }
}

Auto-Generated Dockerfile in Visual Studio:

FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["ConsoleApp1/ConsoleApp1.csproj", "ConsoleApp1/"]
RUN dotnet restore "ConsoleApp1/ConsoleApp1.csproj"
COPY . .
WORKDIR "/src/ConsoleApp1"
RUN dotnet build "ConsoleApp1.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ConsoleApp1.csproj" -c Release -o /app/publish

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

Output of docker version:

Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:43:18 2020
 OS/Arch:           windows/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:27 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Output of docker info:

Client:
 Debug Mode: false

Server:
 Containers: 2
  Running: 1
  Paused: 0
  Stopped: 1
 Images: 36
 Server Version: 19.03.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.19.76-linuxkit
 Operating System: Docker Desktop
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 1.945GiB
 Name: docker-desktop
 ID: 4VOY:AZUQ:HI5H:JJIK:XUL7:6B6B:DXFE:4WDO:ZVTE:CHIP:JZQV:GZQD
 Docker Root Dir: /var/lib/docker
 Debug Mode: true
  File Descriptors: 46
  Goroutines: 55
  System Time: 2020-07-29T16:27:50.516631058Z
  EventsListeners: 3
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine
Darkatek7 commented 3 years ago

Did you ever figure this out?

kbialkowski commented 2 years ago

@BainsDev @Darkatek7 got the same problem. Did you found anything ?

Gradi commented 1 month ago

Same problem for me in year 2024 :)