Network communication
Network communication
There are two common cases to set up a communication with containers or between containers. The first case is simple and does not require additional configurations. The host that runs the test (test process) resolves the container address from the running container with the _container.Hostname property.
Warning
Do not use localhost, 127.0.0.1 or any other fix address to access the container. The address varies according to the environment.
To access apps or services running inside the container behind a certain port, expose and bind the container port to a random host port with _builder.WithPortBinding(ushort, bool) and resolve it with _container.GetMappedPublicPort(ushort). It is recommended to use the Hostname property and GetMappedPublicPort(ushort) together when constructing addresses:
1_ = new UriBuilder("tcp", _container.Hostname, _container.GetMappedPublicPort(2375));This is considered a best practice and prevents port collisions.
Custom network
A more advanced case, places one or more containers on custom networks. The communication between those containers will not require exposing ports through the host anymore. To configure and create Docker networks use NetworkBuilder. The following example creates a network and assigns it to two containers. The second container establishes a network connection to Deep Thought by using its network alias and receives the magic number 42.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35const string MagicNumber = "42";
const string MagicNumberHost = "deep-thought";
const ushort MagicNumberPort = 80;
var network = new NetworkBuilder()
.WithName(Guid.NewGuid().ToString("D"))
.Build();
var deepThoughtContainer = new ContainerBuilder("alpine:3.20.0")
.WithName(Guid.NewGuid().ToString("D"))
.WithEnvironment("MAGIC_NUMBER", MagicNumber)
.WithEntrypoint("/bin/sh", "-c")
.WithCommand($"while true; do echo \"$MAGIC_NUMBER\" | nc -l -p {MagicNumberPort}; done")
.WithNetwork(network)
.WithNetworkAliases(MagicNumberHost)
.Build();
var ultimateQuestionContainer = new ContainerBuilder("alpine:3.20.0")
.WithName(Guid.NewGuid().ToString("D"))
.WithEntrypoint("top")
.WithNetwork(network)
.Build();
await network.CreateAsync()
.ConfigureAwait(false);
await Task.WhenAll(deepThoughtContainer.StartAsync(), ultimateQuestionContainer.StartAsync())
.ConfigureAwait(false);
var execResult = await ultimateQuestionContainer.ExecAsync(new[] { "nc", MagicNumberHost, MagicNumberPort.ToString(CultureInfo.InvariantCulture) })
.ConfigureAwait(false);
Assert.Equal(MagicNumber, execResult.Stdout.Trim());Connecting a running container to an existing network
If a container is already running, use IContainer.ConnectAsync(...) to attach it to an existing network.
The network must already exist. You can reference it either by network name or by an INetwork instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var network = new NetworkBuilder()
.WithName(Guid.NewGuid().ToString("D"))
.Build();
var container = new ContainerBuilder("alpine:3.20.0")
.WithEntrypoint("top")
.Build();
await network.CreateAsync()
.ConfigureAwait(false);
await container.StartAsync()
.ConfigureAwait(false);
await container.ConnectAsync(network)
.ConfigureAwait(false);
// Equivalent when only the network name is available:
await container.ConnectAsync(network.Name)
.ConfigureAwait(false);Prefer WithNetwork(...) during container configuration whenever possible. Use ConnectAsync(...) when you explicitly need to attach a running container to an already existing network.
Exposing container ports to the host
It is common to connect to a container from your test process running on your test host. To bind and expose a container port, use the WithPortBinding(ushort, true) container builder member. To retrieve the actual port at runtime, use the container GetMappedPublicPort(ushort) member. Further information on network configurations is included in our best practices.
Exposing host ports to the container
Sometimes containerized tests require access to services running on the test host. Setting up this connection can be very complex. Fortunately, Testcontainers simplifies the configuration to a bare minimum. It utilizing SSH and setting up an encrypted connection that forwards requests from a container to the test host.
In order to expose ports of services that are running on the test host to containers, we need to configure Testcontainers first. It is important to set up this configuration before configuring any container resources, otherwise, we are not able to forward traffic properly.
Exposing the host port 8080
1
2await TestcontainersSettings.ExposeHostPortsAsync(8080)
.ConfigureAwait(false);From the perspective of a container, the test host is available through the hostname host.testcontainers.internal. Ports are forwarded one-to-one.
Sending a GET request to the test host
1
2_ = await curlContainer.ExecAsync(new[] { "curl", "http://host.testcontainers.internal:8080" })
.ConfigureAwait(false);Supported commands
| Builder method | Description |
|---|---|
WithDockerEndpoint | Sets the Docker daemon socket to connect to. |
WithCleanUp | Will remove the network automatically after all tests have been run. |
WithReuse | Reuses an existing network instead of creating a new one (experimental). |
WithLabel | Applies metadata to the network e.g. -l, --label "testcontainers=awesome". |
WithName | Sets the network name e.g. docker network create "testcontainers". |
WithDriver | Sets the network driver e.g. -d, --driver "bridge" |
WithOption | Adds a driver specific option -o, --opt "com.docker.network.driver.mtu=1350" |
WithCreateParameterModifier | Allows low level modifications of the Docker network create parameter. |
WithLogger | Sets the logger that replaces the default console logger. |
评论
登录后参与评论
KnowForge