Networking
FluentDocker provides full support for Docker networks, including custom networks, static IP assignment, and multi-network configurations.
Step by Step
- Basics: Kernel Setup, Basic Network Creation, Multiple Containers on Same Network
- Intermediate: Network with Subnet, Static IP Assignment, DNS and Aliases, Network Inspection
- Advanced: Network Drivers, Network Options, Multi-Network Containers, Testing with Isolated Networks
Kernel Setup
All v3 operations require a kernel instance. Multiple kernels per application are supported.
using FluentDocker.Kernel;
using FluentDocker.Builders;
var kernel = FluentDockerKernel.Create()
.WithDockerCli("docker", d => d.AsDefault())
.Build();
Basic Network Creation
Create a Network
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("my-network")
.RemoveOnDispose())
.Build();
var network = results.Networks.First();
Console.WriteLine($"Network: {network.Name}");
// Note: INetworkService also exposes a NetworkName property that returns
// the Docker network name. Both network.Name and network.NetworkName are available.
Use Network with Container
// Create the network
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("app-network")
.RemoveOnDispose())
.Build();
// Create a container on that network (reference by name)
using var containerResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("nginx:alpine")
.WithNetwork("app-network"))
.Build();
// Container is attached to app-network
Multiple Containers on Same Network
// Create the shared network
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("backend")
.RemoveOnDispose())
.Build();
// Database
using var dbResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("db")
.UseImage("postgres:15-alpine")
.WithEnvironment("POSTGRES_PASSWORD=secret")
.WithNetwork("backend")
.WaitForPort("5432/tcp", 30000))
.Build();
// Application (can connect to db by container name)
using var appResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("app")
.UseImage("myapp:latest")
.WithEnvironment("DATABASE_HOST=db")
.WithNetwork("backend")
.ExposePort("8080"))
.Build();
// Redis cache
using var cacheResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("cache")
.UseImage("redis:alpine")
.WithNetwork("backend"))
.Build();
// All three containers can communicate by name on "backend"
Network with Subnet
IPv4 Subnet
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("custom-network")
.WithSubnet("10.10.0.0/16")
.WithGateway("10.10.0.1")
.RemoveOnDispose())
.Build();
using var containerResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("nginx:alpine")
.WithNetwork("custom-network"))
.Build();
// Container gets IP from 10.10.0.0/16 range
Restricting IP Allocation Range
Use WithIPRange(string ipRange) on INetworkBuilder to restrict the IP range
for allocation within the subnet. This limits which IPs Docker will auto-assign
to containers, keeping the rest of the subnet available for static assignment:
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("my-net")
.WithSubnet("10.18.0.0/16")
.WithIPRange("10.18.1.0/24")
.WithGateway("10.18.0.1")
.RemoveOnDispose())
.Build();
// Docker will only auto-assign IPs from 10.18.1.0/24
// IPs outside that range (e.g. 10.18.2.x) can be used for static assignment
IPv6 Subnet
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("ipv6-network")
.WithSubnet("2001:db8::/64")
.WithGateway("2001:db8::1")
.WithIPv6()
.RemoveOnDispose())
.Build();
Static IP Assignment
Static IPv4
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("static-ip-net")
.WithSubnet("10.20.0.0/16")
.WithGateway("10.20.0.1")
.RemoveOnDispose())
.Build();
using var c1Results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("server1")
.UseImage("nginx:alpine")
.WithNetwork("static-ip-net")
.WithIPv4("10.20.0.10"))
.Build();
using var c2Results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("server2")
.UseImage("nginx:alpine")
.WithNetwork("static-ip-net")
.WithIPv4("10.20.0.11"))
.Build();
// Containers have predictable IPs
Console.WriteLine("Server1: 10.20.0.10");
Console.WriteLine("Server2: 10.20.0.11");
Static IPv6
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("ipv6-static-net")
.WithSubnet("2001:db8:1::/64")
.WithGateway("2001:db8:1::1")
.WithIPv6()
.RemoveOnDispose())
.Build();
using var containerResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("nginx:alpine")
.WithNetwork("ipv6-static-net")
.WithIPv6("2001:db8:1::100"))
.Build();
Dual Stack (IPv4 + IPv6)
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("dual-stack-net")
.WithSubnet("10.30.0.0/16")
.WithGateway("10.30.0.1")
.WithIPv6()
.RemoveOnDispose())
.Build();
using var containerResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("nginx:alpine")
.WithNetwork("dual-stack-net")
.WithIPv4("10.30.0.50")
.WithIPv6("2001:db8:2::50"))
.Build();
Network Drivers
Bridge Network (Default)
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("my-bridge")
.UseDriver("bridge")
.RemoveOnDispose())
.Build();
Host Network
// Container shares host's network namespace
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("nginx:alpine")
.WithNetworkMode("host"))
.Build();
// No port mapping needed - uses host ports directly
Overlay Network (Swarm)
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("swarm-overlay")
.UseDriver("overlay")
.WithOption("encrypted", "true")
.RemoveOnDispose())
.Build();
Macvlan Network
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("macvlan-net")
.UseDriver("macvlan")
.WithOption("parent", "eth0")
.WithSubnet("192.168.1.0/24")
.WithGateway("192.168.1.1")
.RemoveOnDispose())
.Build();
Network Options
Internal Network
// No external connectivity
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("internal-net")
.AsInternal()
.RemoveOnDispose())
.Build();
Network Labels
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("labeled-net")
.WithLabel("environment", "test")
.WithLabel("project", "myapp")
.RemoveOnDispose())
.Build();
Multi-Network Containers
// Frontend network (external access)
using var frontendResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("frontend")
.WithSubnet("10.40.0.0/24")
.RemoveOnDispose())
.Build();
// Backend network (internal only)
using var backendResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("backend")
.WithSubnet("10.41.0.0/24")
.AsInternal()
.RemoveOnDispose())
.Build();
// API server on frontend network
using var apiResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("api")
.UseImage("myapi:latest")
.WithNetwork("frontend")
.WithIPv4("10.40.0.10")
.ExposePort("8080"))
.Build();
// Connect API to backend network as well
var apiContainer = apiResults.Containers.First();
var backendNetwork = backendResults.Networks.First();
await backendNetwork.ConnectAsync(apiContainer.Id);
// Database only on backend network
using var dbResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("db")
.UseImage("postgres:15-alpine")
.WithEnvironment("POSTGRES_PASSWORD=secret")
.WithNetwork("backend")
.WithIPv4("10.41.0.20"))
.Build();
// API can reach both frontend and backend
// DB is only accessible from backend network
Network Inspection
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("inspect-me")
.WithSubnet("10.50.0.0/16")
.RemoveOnDispose())
.Build();
var network = results.Networks.First();
var info = await network.InspectAsync();
Console.WriteLine($"Name: {info.Name}");
Console.WriteLine($"Driver: {info.Driver}");
DNS and Aliases
Container Aliases
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("aliased-net")
.RemoveOnDispose())
.Build();
using var containerResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("myservice")
.UseImage("nginx:alpine")
.WithNetworkAlias("aliased-net", "web")
.WithNetworkAlias("aliased-net", "frontend")
.WithNetworkAlias("aliased-net", "nginx"))
.Build();
// Container reachable as: myservice, web, frontend, nginx
Microservices Example
// Create isolated network for microservices
using var netResults = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("microservices")
.WithSubnet("10.100.0.0/16")
.RemoveOnDispose())
.Build();
// API Gateway
using var gatewayResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("gateway")
.UseImage("kong:latest")
.WithNetwork("microservices")
.WithIPv4("10.100.0.10")
.ExposePort(8000, 8000)
.ExposePort(8443, 8443))
.Build();
// User Service
using var userResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("user-service")
.UseImage("user-service:latest")
.WithNetwork("microservices")
.WithIPv4("10.100.1.10"))
.Build();
// Order Service
using var orderResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("order-service")
.UseImage("order-service:latest")
.WithNetwork("microservices")
.WithIPv4("10.100.2.10"))
.Build();
// Product Service
using var productResults = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.WithName("product-service")
.UseImage("product-service:latest")
.WithNetwork("microservices")
.WithIPv4("10.100.3.10"))
.Build();
// Services communicate via DNS names or static IPs
// Gateway at 10.100.0.10 can route to all services
Network Cleanup
Auto-cleanup with RemoveOnDispose
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("temp-network")
.RemoveOnDispose())
.Build();
// Network removed when results is disposed
Disposing BuildResults
var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n
.WithName("manual-network")
.RemoveOnDispose())
.Build();
// Use network...
// Dispose all services (networks, containers, etc.)
results.Dispose();
// Or use async disposal
await results.DisposeAllAsync();
Testing with Isolated Networks
public class NetworkIsolatedTest : IDisposable
{
private readonly FluentDockerKernel _kernel;
private readonly BuildResults _netResults;
private readonly BuildResults _dbResults;
private readonly BuildResults _apiResults;
public NetworkIsolatedTest()
{
_kernel = FluentDockerKernel.Create()
.WithDockerCli("docker", d => d.AsDefault())
.Build();
// Each test run gets isolated network
var testId = Guid.NewGuid().ToString("N")[..8];
_netResults = new Builder()
.WithinDriver("docker", _kernel)
.UseNetwork(n => n
.WithName($"test-{testId}")
.WithSubnet("10.200.0.0/24")
.RemoveOnDispose())
.Build();
_dbResults = new Builder()
.WithinDriver("docker", _kernel)
.UseContainer(c => c
.WithName($"db-{testId}")
.UseImage("postgres:15-alpine")
.WithEnvironment("POSTGRES_PASSWORD=test")
.WithNetwork($"test-{testId}")
.WithIPv4("10.200.0.10")
.WaitForPort("5432/tcp", 30000))
.Build();
_apiResults = new Builder()
.WithinDriver("docker", _kernel)
.UseContainer(c => c
.WithName($"api-{testId}")
.UseImage("myapi:test")
.WithEnvironment("DB_HOST=10.200.0.10")
.WithNetwork($"test-{testId}")
.ExposePort("8080")
.WaitForPort("8080/tcp", 30000))
.Build();
}
[Fact]
public void Api_CanConnectToDatabase()
{
var api = _apiResults.Containers.First();
// Test connectivity via the API container
Assert.NotNull(api);
}
public void Dispose()
{
_apiResults?.Dispose();
_dbResults?.Dispose();
_netResults?.Dispose();
_kernel?.Dispose();
}
}
Next Steps
- Volumes - Data persistence
- Containers - Container management
- Docker Compose - Multi-container orchestration