From 2868289b6fb3b7f9ec6509c2a8983ad967bbcee7 Mon Sep 17 00:00:00 2001
From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
Date: Thu, 13 Nov 2025 20:03:30 +0100
Subject: [PATCH 1/4] feat: Support configuring Docker API version
---
docs/custom_configuration/index.md | 1 +
...erDesktopEndpointAuthenticationProvider.cs | 6 +++++
...ontainersEndpointAuthenticationProvider.cs | 6 +++++
src/Testcontainers/Clients/DockerApiClient.cs | 2 +-
.../Configurations/CustomConfiguration.cs | 5 ++++
.../EnvironmentConfiguration.cs | 13 ++++++++--
.../Configurations/ICustomConfiguration.cs | 8 +++++++
.../PropertiesFileConfiguration.cs | 7 ++++++
.../Configurations/TestcontainersSettings.cs | 10 ++++++++
.../Configurations/CustomConfigurationTest.cs | 24 +++++++++++++++++++
10 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/docs/custom_configuration/index.md b/docs/custom_configuration/index.md
index d7e5eb371..b745f2a53 100644
--- a/docs/custom_configuration/index.md
+++ b/docs/custom_configuration/index.md
@@ -4,6 +4,7 @@ Testcontainers supports various configurations to set up your test environment.
| Properties File | Environment Variable | Description | Default |
|---------------------------------|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|------------------------------|
+| `docker.api.version` | `DOCKER_API_VERSION` | The Docker API version to use. | `1.44` |
| `docker.config` | `DOCKER_CONFIG` | The directory path that contains the Docker configuration (`config.json`) file. | `~/.docker/` |
| `docker.host` | `DOCKER_HOST` | The Docker daemon socket to connect to. | - |
| `docker.context` | `DOCKER_CONTEXT` | The Docker context to connect to. | - |
diff --git a/src/Testcontainers/Builders/DockerDesktopEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/DockerDesktopEndpointAuthenticationProvider.cs
index 02d164d6f..9411c6b89 100644
--- a/src/Testcontainers/Builders/DockerDesktopEndpointAuthenticationProvider.cs
+++ b/src/Testcontainers/Builders/DockerDesktopEndpointAuthenticationProvider.cs
@@ -25,6 +25,12 @@ public override bool IsApplicable()
return !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && DockerEngine != null;
}
+ ///
+ public Version GetDockerApiVersion()
+ {
+ return null;
+ }
+
///
public string GetDockerConfig()
{
diff --git a/src/Testcontainers/Builders/TestcontainersEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/TestcontainersEndpointAuthenticationProvider.cs
index 04335eb00..4e4e9780e 100644
--- a/src/Testcontainers/Builders/TestcontainersEndpointAuthenticationProvider.cs
+++ b/src/Testcontainers/Builders/TestcontainersEndpointAuthenticationProvider.cs
@@ -57,6 +57,12 @@ public override IDockerEndpointAuthenticationConfiguration GetAuthConfig()
return new DockerEndpointAuthenticationConfiguration(_dockerEngine);
}
+ ///
+ public Version GetDockerApiVersion()
+ {
+ return _customConfiguration.GetDockerApiVersion();
+ }
+
///
public string GetDockerConfig()
{
diff --git a/src/Testcontainers/Clients/DockerApiClient.cs b/src/Testcontainers/Clients/DockerApiClient.cs
index 927bb397a..172db1a09 100644
--- a/src/Testcontainers/Clients/DockerApiClient.cs
+++ b/src/Testcontainers/Clients/DockerApiClient.cs
@@ -134,7 +134,7 @@ private static IDockerClient GetDockerClient(Guid sessionId, IDockerEndpointAuth
{
using (var dockerClientConfiguration = dockerEndpointAuthConfig.GetDockerClientConfiguration(sessionId))
{
- return dockerClientConfiguration.CreateClient();
+ return dockerClientConfiguration.CreateClient(TestcontainersSettings.DockerApiVersion);
}
}
}
diff --git a/src/Testcontainers/Configurations/CustomConfiguration.cs b/src/Testcontainers/Configurations/CustomConfiguration.cs
index 81c79c003..eed39241c 100644
--- a/src/Testcontainers/Configurations/CustomConfiguration.cs
+++ b/src/Testcontainers/Configurations/CustomConfiguration.cs
@@ -15,6 +15,11 @@ protected CustomConfiguration(IReadOnlyDictionary properties)
_properties = properties;
}
+ protected virtual Version GetDockerApiVersion(string propertyName)
+ {
+ return _properties.TryGetValue(propertyName, out var propertyValue) && !string.IsNullOrEmpty(propertyValue) && Version.TryParse(propertyValue, out var dockerApiVersion) ? dockerApiVersion : null;
+ }
+
protected virtual string GetDockerConfig(string propertyName)
{
return GetPropertyValue(propertyName);
diff --git a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
index 7a2f9b9c3..c33c62a43 100644
--- a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
+++ b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
@@ -10,6 +10,8 @@ namespace DotNet.Testcontainers.Configurations
///
internal class EnvironmentConfiguration : CustomConfiguration, ICustomConfiguration
{
+ private const string DockerApiVersion = "DOCKER_API_VERSION";
+
private const string DockerConfig = "DOCKER_CONFIG";
private const string DockerHost = "DOCKER_HOST";
@@ -54,11 +56,12 @@ static EnvironmentConfiguration()
public EnvironmentConfiguration()
: base(new[]
{
- DockerAuthConfig,
- DockerCertPath,
+ DockerApiVersion,
DockerConfig,
DockerHost,
DockerContext,
+ DockerAuthConfig,
+ DockerCertPath,
DockerTls,
DockerTlsVerify,
DockerHostOverride,
@@ -82,6 +85,12 @@ public EnvironmentConfiguration()
public static ICustomConfiguration Instance { get; }
= new EnvironmentConfiguration();
+ ///
+ public Version GetDockerApiVersion()
+ {
+ return GetDockerApiVersion(DockerApiVersion);
+ }
+
///
public string GetDockerConfig()
{
diff --git a/src/Testcontainers/Configurations/ICustomConfiguration.cs b/src/Testcontainers/Configurations/ICustomConfiguration.cs
index a9964cac4..57e63aa27 100644
--- a/src/Testcontainers/Configurations/ICustomConfiguration.cs
+++ b/src/Testcontainers/Configurations/ICustomConfiguration.cs
@@ -10,6 +10,14 @@ namespace DotNet.Testcontainers.Configurations
///
internal interface ICustomConfiguration
{
+ ///
+ /// Gets the Docker API version custom configuration.
+ ///
+ /// The Docker API version custom configuration.
+ /// https://dotnet.testcontainers.org/custom_configuration/.
+ [CanBeNull]
+ Version GetDockerApiVersion();
+
///
/// Gets the Docker config custom configuration.
///
diff --git a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
index 7ae19fe46..a4412010e 100644
--- a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
+++ b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
@@ -56,6 +56,13 @@ public PropertiesFileConfiguration(params string[] lines)
public static ICustomConfiguration Instance { get; }
= new PropertiesFileConfiguration();
+ ///
+ public Version GetDockerApiVersion()
+ {
+ const string propertyName = "docker.api.version";
+ return GetDockerApiVersion(propertyName);
+ }
+
///
public string GetDockerConfig()
{
diff --git a/src/Testcontainers/Configurations/TestcontainersSettings.cs b/src/Testcontainers/Configurations/TestcontainersSettings.cs
index cf72ac995..cf316298b 100644
--- a/src/Testcontainers/Configurations/TestcontainersSettings.cs
+++ b/src/Testcontainers/Configurations/TestcontainersSettings.cs
@@ -42,6 +42,16 @@ static TestcontainersSettings()
{
}
+ ///
+ /// Gets or sets the Docker API version.
+ ///
+ ///
+ /// https://github.com/moby/moby/releases/tag/docker-v29.0.0.
+ ///
+ [CanBeNull]
+ public static Version DockerApiVersion { get; set; }
+ = EnvironmentConfiguration.Instance.GetDockerApiVersion() ?? PropertiesFileConfiguration.Instance.GetDockerApiVersion() ?? new Version(1, 44);
+
///
/// Gets or sets the Docker host override value.
///
diff --git a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs
index 1d123dea5..652c10be1 100644
--- a/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs
+++ b/tests/Testcontainers.Tests/Unit/Configurations/CustomConfigurationTest.cs
@@ -15,6 +15,7 @@ public sealed class EnvironmentConfigurationTest : IDisposable
static EnvironmentConfigurationTest()
{
+ EnvironmentVariables.Add("DOCKER_API_VERSION");
EnvironmentVariables.Add("DOCKER_CONFIG");
EnvironmentVariables.Add("DOCKER_HOST");
EnvironmentVariables.Add("DOCKER_CONTEXT");
@@ -34,6 +35,18 @@ static EnvironmentConfigurationTest()
EnvironmentVariables.Add("TESTCONTAINERS_NAMED_PIPE_CONNECTION_TIMEOUT");
}
+ [Theory]
+ [InlineData("", "", null)]
+ [InlineData("DOCKER_API_VERSION", "", null)]
+ [InlineData("DOCKER_API_VERSION", "version", null)]
+ [InlineData("DOCKER_API_VERSION", "1.52", "1.52")]
+ public void GetDockerApiVersionCustomConfiguration(string propertyName, string propertyValue, string expected)
+ {
+ SetEnvironmentVariable(propertyName, propertyValue);
+ ICustomConfiguration customConfiguration = new EnvironmentConfiguration();
+ Assert.Equal(expected, customConfiguration.GetDockerApiVersion()?.ToString());
+ }
+
[Theory]
[InlineData("", "", null)]
[InlineData("DOCKER_CONFIG", "", null)]
@@ -259,6 +272,17 @@ private static void SetEnvironmentVariable(string propertyName, string propertyV
public sealed class PropertiesFileConfigurationTest
{
+ [Theory]
+ [InlineData("", null)]
+ [InlineData("docker.api.version=", null)]
+ [InlineData("docker.api.version=version", null)]
+ [InlineData("docker.api.version=1.52", "1.52")]
+ public void GetDockerApiVersionCustomConfiguration(string configuration, string expected)
+ {
+ ICustomConfiguration customConfiguration = new PropertiesFileConfiguration(new[] { configuration });
+ Assert.Equal(expected, customConfiguration.GetDockerApiVersion()?.ToString());
+ }
+
[Theory]
[InlineData("", null)]
[InlineData("docker.config=", null)]
From aa40a9310d5639cf9887bb23a54c28ba9fe18011 Mon Sep 17 00:00:00 2001
From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
Date: Fri, 14 Nov 2025 07:34:12 +0100
Subject: [PATCH 2/4] fix: Bump dind image version
---
.../Fixtures/Containers/Unix/DockerTlsFixture.cs | 2 +-
.../Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs | 2 +-
.../Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs
index 1ed591185..810872503 100644
--- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs
+++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/DockerTlsFixture.cs
@@ -9,7 +9,7 @@ public sealed class DockerTlsFixture : ProtectDockerDaemonSocket
{
public DockerTlsFixture()
: base(new ContainerBuilder()
- .WithCommand("--tlsverify=false"), "20.10.18")
+ .WithCommand("--tlsverify=false"), "29.0.0")
{
}
diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
index 37705ec29..3e87a9ab7 100644
--- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
+++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
@@ -5,7 +5,7 @@ namespace DotNet.Testcontainers.Tests.Fixtures
[UsedImplicitly]
public sealed class OpenSsl1_1_1Fixture : DockerMTls
{
- public OpenSsl1_1_1Fixture() : base("20.10.18")
+ public OpenSsl1_1_1Fixture() : base("29.0.0")
{
}
}
diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs
index 0a4768b96..9b50c72f3 100644
--- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs
+++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl3_1Fixture.cs
@@ -5,7 +5,7 @@ namespace DotNet.Testcontainers.Tests.Fixtures
[UsedImplicitly]
public sealed class OpenSsl3_1Fixture : DockerMTls
{
- public OpenSsl3_1Fixture() : base("24.0.5")
+ public OpenSsl3_1Fixture() : base("29.0.0")
{
}
}
From c2b334f7a71511a35fc7d02fb944c4a8529793f6 Mon Sep 17 00:00:00 2001
From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
Date: Fri, 14 Nov 2025 12:41:01 +0100
Subject: [PATCH 3/4] fix: User older API for outdated image
---
.../DockerEndpointAuthenticationProvider.cs | 2 +-
src/Testcontainers/Clients/DockerApiClient.cs | 2 +-
...ckerEndpointAuthenticationConfiguration.cs | 6 ++++++
...ckerEndpointAuthenticationConfiguration.cs | 6 ++++++
.../Containers/Unix/OpenSsl1_1_1Fixture.cs | 2 +-
.../Unix/ProtectDockerDaemonSocketTest.cs | 19 +++++++++++++++++--
6 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs
index 76d18058a..738050db8 100644
--- a/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs
+++ b/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs
@@ -41,7 +41,7 @@ public virtual bool IsAvailable()
{
using (var dockerClientConfiguration = authConfig.GetDockerClientConfiguration(ResourceReaper.DefaultSessionId))
{
- using (var dockerClient = dockerClientConfiguration.CreateClient())
+ using (var dockerClient = dockerClientConfiguration.CreateClient(authConfig.Version))
{
try
{
diff --git a/src/Testcontainers/Clients/DockerApiClient.cs b/src/Testcontainers/Clients/DockerApiClient.cs
index 172db1a09..d2cc9dedd 100644
--- a/src/Testcontainers/Clients/DockerApiClient.cs
+++ b/src/Testcontainers/Clients/DockerApiClient.cs
@@ -134,7 +134,7 @@ private static IDockerClient GetDockerClient(Guid sessionId, IDockerEndpointAuth
{
using (var dockerClientConfiguration = dockerEndpointAuthConfig.GetDockerClientConfiguration(sessionId))
{
- return dockerClientConfiguration.CreateClient(TestcontainersSettings.DockerApiVersion);
+ return dockerClientConfiguration.CreateClient(dockerEndpointAuthConfig.Version);
}
}
}
diff --git a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs
index 94a0103fa..57c22671a 100644
--- a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs
+++ b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs
@@ -10,6 +10,9 @@ namespace DotNet.Testcontainers.Configurations
[PublicAPI]
public readonly struct DockerEndpointAuthenticationConfiguration : IDockerEndpointAuthenticationConfiguration
{
+ // https://github.com/moby/moby/releases/tag/docker-v29.0.0.
+ private static readonly Version DockerEngineApi = EnvironmentConfiguration.Instance.GetDockerApiVersion() ?? PropertiesFileConfiguration.Instance.GetDockerApiVersion() ?? new Version(1, 44);
+
// Since the static `TestcontainersSettings` class holds the detected container
// runtime information from the auto-discovery mechanism, we can't add a static
// `NamedPipeConnectionTimeout` property to it because that would create a
@@ -30,6 +33,9 @@ public DockerEndpointAuthenticationConfiguration(Uri endpoint, Credentials crede
Credentials = credentials;
}
+ ///
+ public Version Version => DockerEngineApi;
+
///
public Uri Endpoint { get; }
diff --git a/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs b/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs
index b303ce4a6..cafcf2277 100644
--- a/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs
+++ b/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs
@@ -10,6 +10,12 @@ namespace DotNet.Testcontainers.Configurations
[PublicAPI]
public interface IDockerEndpointAuthenticationConfiguration
{
+ ///
+ /// Gets the Docker API version.
+ ///
+ [CanBeNull]
+ Version Version { get; }
+
///
/// Gets the Docker API endpoint.
///
diff --git a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
index 3e87a9ab7..37705ec29 100644
--- a/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
+++ b/tests/Testcontainers.Tests/Fixtures/Containers/Unix/OpenSsl1_1_1Fixture.cs
@@ -5,7 +5,7 @@ namespace DotNet.Testcontainers.Tests.Fixtures
[UsedImplicitly]
public sealed class OpenSsl1_1_1Fixture : DockerMTls
{
- public OpenSsl1_1_1Fixture() : base("29.0.0")
+ public OpenSsl1_1_1Fixture() : base("20.10.18")
{
}
}
diff --git a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs
index e73f7367a..19dee143f 100644
--- a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs
+++ b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs
@@ -3,6 +3,7 @@ namespace DotNet.Testcontainers.Tests.Unit
using System;
using System.Linq;
using System.Threading.Tasks;
+ using Docker.DotNet;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Clients;
using DotNet.Testcontainers.Configurations;
@@ -20,7 +21,7 @@ private static IDockerEndpointAuthenticationConfiguration GetAuthConfig(ProtectD
return new IDockerEndpointAuthenticationProvider[] { new MTlsEndpointAuthenticationProvider(customConfiguration), new TlsEndpointAuthenticationProvider(customConfiguration) }.First(authProvider => authProvider.IsApplicable()).GetAuthConfig();
}
- public sealed class MTlsOpenSsl1_1_1 : IClassFixture
+ public sealed class MTlsOpenSsl1_1_1 : IClassFixture, IDockerEndpointAuthenticationConfiguration
{
private readonly ProtectDockerDaemonSocket _fixture;
@@ -32,11 +33,25 @@ public MTlsOpenSsl1_1_1(OpenSsl1_1_1Fixture dockerMTlsFixture)
_authConfig = GetAuthConfig(dockerMTlsFixture);
}
+ // The outdated image isn't compatible with the default Docker Engine API version.
+ // For this test, we're overriding the version.
+ public Version Version
+ => null;
+
+ public Uri Endpoint
+ => _authConfig.Endpoint;
+
+ public Credentials Credentials
+ => _authConfig.Credentials;
+
+ public DockerClientConfiguration GetDockerClientConfiguration(Guid sessionId = default)
+ => _authConfig.GetDockerClientConfiguration(sessionId);
+
[Fact]
public async Task GetVersionReturnsVersion()
{
// Given
- var client = new TestcontainersClient(Guid.Empty, _authConfig, NullLogger.Instance);
+ var client = new TestcontainersClient(Guid.Empty, this, NullLogger.Instance);
// When
var version = await client.System.GetVersionAsync(TestContext.Current.CancellationToken)
From c7a749bfd8494200651f0cfb721104b09eb3e69c Mon Sep 17 00:00:00 2001
From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
Date: Fri, 14 Nov 2025 15:29:31 +0100
Subject: [PATCH 4/4] chore: Remove unnecessary change
---
.../Configurations/TestcontainersSettings.cs | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/src/Testcontainers/Configurations/TestcontainersSettings.cs b/src/Testcontainers/Configurations/TestcontainersSettings.cs
index cf316298b..cf72ac995 100644
--- a/src/Testcontainers/Configurations/TestcontainersSettings.cs
+++ b/src/Testcontainers/Configurations/TestcontainersSettings.cs
@@ -42,16 +42,6 @@ static TestcontainersSettings()
{
}
- ///
- /// Gets or sets the Docker API version.
- ///
- ///
- /// https://github.com/moby/moby/releases/tag/docker-v29.0.0.
- ///
- [CanBeNull]
- public static Version DockerApiVersion { get; set; }
- = EnvironmentConfiguration.Instance.GetDockerApiVersion() ?? PropertiesFileConfiguration.Instance.GetDockerApiVersion() ?? new Version(1, 44);
-
///
/// Gets or sets the Docker host override value.
///