testcontainers / testcontainers-dotnet

A library to support tests with throwaway instances of Docker containers for all compatible .NET Standard versions.
https://dotnet.testcontainers.org
MIT License
3.67k stars 254 forks source link

[Bug]: Can't modify the timeout of DockerClient which is by default 100 seconds #1086

Closed Evyatar108 closed 5 months ago

Evyatar108 commented 6 months ago

Testcontainers version

3.5.0

Using the latest Testcontainers version?

Yes

Host OS

Windows

Host arch

x64

.NET version

6

Docker version

24.0.7

Docker info

Client:
 Version:    24.0.7
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.12.0-desktop.2
    Path:     C:\Program Files\Docker\cli-plugins\docker-buildx.exe
  compose: Docker Compose (Docker Inc.)
    Version:  v2.23.3-desktop.2
    Path:     C:\Program Files\Docker\cli-plugins\docker-compose.exe
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-dev.exe
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.21
    Path:     C:\Program Files\Docker\cli-plugins\docker-extension.exe
  feedback: Provide feedback, right in your terminal! (Docker Inc.)
    Version:  0.1
    Path:     C:\Program Files\Docker\cli-plugins\docker-feedback.exe
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v0.1.0-beta.10
    Path:     C:\Program Files\Docker\cli-plugins\docker-init.exe
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
    Version:  0.6.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-sbom.exe
  scan: Docker Scan (Docker Inc.)
    Version:  v0.26.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-scan.exe
  scout: Docker Scout (Docker Inc.)
    Version:  v1.2.0
    Path:     C:\Program Files\Docker\cli-plugins\docker-scout.exe

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 33
 Server Version: 24.0.7
 Storage Driver: windowsfilter
  Windows:
 Logging Driver: json-file
 Plugins:
  Volume: local
  Network: ics internal l2bridge l2tunnel nat null overlay private transparent
  Log: awslogs etwlogs fluentd gcplogs gelf json-file local logentries splunk syslog
 Swarm: inactive
 Default Isolation: hyperv
 Kernel Version: 10.0 22621 (22621.1.amd64fre.ni_release.220506-1250)
 Operating System: Microsoft Windows Version 22H2 (OS Build 22621.2861)
 OSType: windows
 Architecture: x86_64
 CPUs: 16
 Total Memory: 63.73GiB
 Name: DESKTOP-212EVNK
 ID: 6629d261-2dff-4695-926b-a400d3552bab
 Docker Root Dir: C:\ProgramData\Docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine

What happened?

I sometime reach the timeout of 100 seconds when trying to start a new container, I checked the code and couldn't find a straightforward way to modify the timeout

Relevant log output

Class Initialization method FunctionalTests.HealthControllerTests.InitContainer threw exception. System.OperationCanceledException: System.OperationCanceledException: The operation was canceled..

at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Docker.DotNet.DockerClient.PrivateMakeRequestAsync(TimeSpan timeout, HttpCompletionOption completionOption, HttpMethod method, String path, IQueryString queryString, IDictionary`2 headers, IRequestContent data, CancellationToken cancellationToken)
at Docker.DotNet.DockerClient.MakeRequestAsync(IEnumerable`1 errorHandlers, HttpMethod method, String path, IQueryString queryString, IRequestContent body, IDictionary`2 headers, TimeSpan timeout, CancellationToken token)
at Docker.DotNet.ContainerOperations.StartContainerAsync(String id, ContainerStartParameters parameters, CancellationToken cancellationToken)
at DotNet.Testcontainers.Clients.TestcontainersClient.StartAsync(String id, CancellationToken ct)
at DotNet.Testcontainers.Containers.DockerContainer.UnsafeStartAsync(CancellationToken ct)
at DotNet.Testcontainers.Containers.DockerContainer.StartAsync(CancellationToken ct)
at FunctionalTests.TestsInitializer.Initialize() in C:\a\_work\1\s\sources\test\MyProject\FunctionalTests\TestsInitializer.cs:line 53
at FunctionalTests.TestsInitializer.GetInstance() in C:\a\_work\1\s\sources\test\MyProject\FunctionalTests\TestsInitializer.cs:line 29
at FunctionalTests.TestBase.InitContainer(TestContext context) in C:\a\_work\1\s\sources\test\MyProject\FunctionalTests\TestBase.cs:line 24

Additional information

I use this code to build the container:

    new ContainerBuilder()...Build()

for now to bypass this issue I modify the timeout with a bit of reflection:

    private static void RemoveDockerClientTimeout(IContainer container)
    {
        Assembly testcontainersAssembly = Assembly.Load("Testcontainers");

        object testContainersclient = typeof(DockerContainer)
            .GetField("_client", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(container);

        object containerOperations = testcontainersAssembly
            .GetType("DotNet.Testcontainers.Clients.TestcontainersClient")
            .GetProperty("Container", BindingFlags.Public | BindingFlags.Instance)
            .GetValue(testContainersclient);

        DockerClient dockerClient = (DockerClient)testcontainersAssembly
            .GetType("DotNet.Testcontainers.Clients.DockerApiClient")
            .GetProperty("Docker", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(containerOperations);

        dockerClient.DefaultTimeout = Timeout.InfiniteTimeSpan;
    }

and then I run

    await container.StartAsync().ConfigureAwait(false);
HofmeisterAn commented 6 months ago

This sounds very unusual. The HTTP request should get its response fairly quickly. I would expect something else is causing an issue. A few seconds is already a lot. I haven't seen something like this before. Although, it looks like you are depending on Windows containers (on purpose?), which I haven't used for a while now. Have you tried the Linux engine? Do you run into similar issues?

To override the default Docker client configuration, you can pass a custom Docker endpoint configuration to the builder (you can use the custom Docker endpoint as a global configuration too without assigning it to every builder configuration). Here is a quick example:

_ = new ContainerBuilder()
    .WithDockerEndpoint(new MyCustomDockerEndpoint())
    .Build();

private sealed class MyCustomDockerEndpoint : IDockerEndpointAuthenticationConfiguration
{
    public Uri Endpoint => TestcontainersSettings.OS.DockerEndpointAuthConfig.Endpoint;

    public Credentials Credentials => TestcontainersSettings.OS.DockerEndpointAuthConfig.Credentials;

    public DockerClientConfiguration GetDockerClientConfiguration(Guid sessionId = default)
    {
        return new DockerClientConfiguration(Endpoint, Credentials, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5), ReadOnlyDictionary<string, string>.Empty);
    }
}
HofmeisterAn commented 5 months ago

I will close this issue due to inactivity. If you still have any issues or further questions, please do not hesitate to reopen it again.