v2.x.x to v3.0.0 API Mapping
This document provides a comprehensive mapping between the FluentDocker v2.x.x API and the v3.0.0 API. Use it as a quick-reference when migrating existing code.
1. Namespace Changes
Every namespace drops the Ductus. prefix. Two namespaces are new in v3.
| v2 Namespace | v3 Namespace |
|---|---|
Ductus.FluentDocker.Builders |
FluentDocker.Builders |
Ductus.FluentDocker.Services |
FluentDocker.Services |
Ductus.FluentDocker.Model.Common |
FluentDocker.Model.Common |
Ductus.FluentDocker.Model.Containers |
FluentDocker.Model.Containers |
Ductus.FluentDocker.Model.Compose |
FluentDocker.Model.Compose |
Ductus.FluentDocker.Model.Networks |
FluentDocker.Model.Networks |
Ductus.FluentDocker.Model.Volumes |
FluentDocker.Model.Volumes |
Ductus.FluentDocker.Model.Images |
FluentDocker.Model.Images |
Ductus.FluentDocker.Extensions |
FluentDocker.Extensions |
Ductus.FluentDocker.Commands |
Removed – replaced by Driver Layer |
| (none) | FluentDocker.Kernel – kernel setup (new) |
| (none) | FluentDocker.Services.Extensions – service extension methods (new) |
Rule of thumb: find-and-replace Ductus.FluentDocker with FluentDocker
across all using directives, then add the two new namespaces where needed.
2. Kernel Setup (New in v3)
v2 had no kernel concept; the library discovered the Docker CLI implicitly.
v3 requires you to create a FluentDockerKernel before building any resources.
Because v2 only supported Docker CLI, all migrations use WithDockerCli:
// v3 -- required before any builder usage
using var kernel = FluentDockerKernel.Create()
.WithDockerCli("docker", d => d.AsDefault())
.Build();
If you need sudo:
using var kernel = FluentDockerKernel.Create()
.WithDockerCli("docker", d => d
.AsDefault()
.WithSudo(SudoMechanism.NoPassword))
.Build();
The kernel is passed into the Builder via WithinDriver() (see next section).
3. Builder Pattern Changes
v2 used a flat, chained builder API. v3 uses lambda-scoped sub-builders
nested inside WithinDriver().
Container
// v2
var svc = new Builder()
.UseContainer()
.UseImage("postgres:alpine")
.WithEnvironment("POSTGRES_PASSWORD=secret")
.ExposePort(5432, 5432)
.Build();
svc.Start();
// v3
var results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c
.UseImage("postgres:alpine")
.WithEnvironment("POSTGRES_PASSWORD=secret")
.ExposePort(5432, 5432))
.Build();
// Build() auto-starts; no explicit Start() needed.
var container = results.Containers[0];
Network
// v2
var svc = new Builder()
.UseNetwork("my-net")
.Build();
// v3
var results = new Builder()
.WithinDriver("docker", kernel)
.UseNetwork(n => n.WithName("my-net"))
.Build();
var network = results.Networks[0];
Volume
// v2
var svc = new Builder()
.UseVolume("my-vol")
.Build();
// v3
var results = new Builder()
.WithinDriver("docker", kernel)
.UseVolume(v => v.WithName("my-vol"))
.Build();
var volume = results.Volumes[0];
Compose
// v2
var svc = new Builder()
.UseCompose()
.FromFile("docker-compose.yml")
.Build();
// v3
var results = new Builder()
.WithinDriver("docker", kernel)
.UseCompose(c => c.WithComposeFile("docker-compose.yml"))
.Build();
var compose = results.ComposeServices[0];
Quick-Reference Table
| v2 | v3 |
|---|---|
new Builder().UseContainer().UseImage("x").Build() |
new Builder().WithinDriver("docker", kernel).UseContainer(c => c.UseImage("x")).Build() |
.Build() returns service directly |
.Build() returns BuildResults |
.Build() then .Start() |
.Build() auto-starts |
.UseContainer().UseImage(...) chained |
.UseContainer(c => c.UseImage(...)) lambda |
.UseNetwork("name") chained |
.UseNetwork(n => n.WithName("name")) lambda |
.UseVolume("name") chained |
.UseVolume(v => v.WithName("name")) lambda |
.UseCompose().FromFile("x") |
.UseCompose(c => c.WithComposeFile("x")) lambda |
4. BuildResults (New in v3)
v2 returned a single service from Build(). v3 returns a BuildResults object
that holds every resource created during the build.
| Member | Type | Description |
|---|---|---|
results.Containers |
IReadOnlyList<IContainerService> |
All containers |
results.Networks |
IReadOnlyList<INetworkService> |
All networks |
results.Volumes |
IReadOnlyList<IVolumeService> |
All volumes |
results.ComposeServices |
IReadOnlyList<IComposeService> |
All compose stacks |
results.GetContainer("name") |
IContainerService |
Lookup by name |
results.All |
IReadOnlyList<IServiceAsync> |
Every service |
results.ForDriver("driverId") |
IReadOnlyList<IServiceAsync> |
Filter by driver |
BuildResults implements IDisposable / IAsyncDisposable, so wrapping it in
a using block tears down every resource:
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c.UseImage("redis:alpine"))
.Build();
// results.Containers[0] is already running
5. Service Method Changes
| v2 Method | v3 Method | Notes |
|---|---|---|
container.Start() |
container.Start() |
Sync still available |
await container.StartAsync() |
Async variant (new) | |
container.Stop() |
container.Stop() |
Sync still available |
await container.StopAsync() |
Async variant (new) | |
container.Pause() |
container.Pause() |
Sync still available |
await container.PauseAsync() |
Async variant (new) | |
container.Resume() |
container.Start() |
No Resume(); Start() unpauses |
container.GetConfiguration() |
container.GetConfiguration() |
Extension in Services.Extensions |
await container.InspectAsync() |
Async variant (new) | |
container.ToHostExposedEndpoint(port) |
container.ToHostExposedEndpoint(port) |
Extension in Services.Extensions |
container.Logs() |
await container.GetLogsAsync() |
No synchronous variant |
container.Execute(cmd) |
await container.ExecuteAsync(cmd) |
Note: ExecuteAsync, not ExecAsync |
host.ComposeUp(...) |
await composeDriver.UpAsync(ctx, config) |
Struct-based args (see section 9) |
Important
GetConfiguration()andToHostExposedEndpoint()moved to extension methods. Addusing FluentDocker.Services.Extensions;to resolve them.Resume()was removed. CallStart()to unpause a paused container.Logs()has no sync wrapper in v3; useGetLogsAsync().
6. Container Stats (New in v3)
v3 exposes container resource usage through GetStatsAsync():
var stats = await container.GetStatsAsync();
// CPU
double cpuPercent = stats.Cpu.UsagePercent; // NOT stats.CpuPercent
// Memory
long memUsage = stats.Memory.Usage; // NOT stats.MemoryUsage
long memLimit = stats.Memory.Limit;
// Network I/O
long rxBytes = stats.Network.RxBytes;
long txBytes = stats.Network.TxBytes;
// Disk I/O
long diskRead = stats.Disk.ReadBytes;
long diskWrite = stats.Disk.WriteBytes;
There is no v2 equivalent; this is entirely new functionality.
7. File Copy Operations
| v2 | v3 | Notes |
|---|---|---|
container.CopyTo(hostPath, containerPath) |
await container.CopyToAsync(hostPath, containerPath) |
Host to container |
container.CopyFrom(containerPath, hostPath) |
await container.CopyFromToPathAsync(containerPath, hostPath) |
Container to host path |
| (none) | await container.CopyFromAsync(containerPath) |
Returns byte[] (new) |
All copy operations are async-only in v3.
8. SudoMechanism
v2 used global static state to configure sudo. v3 moves this into the per-driver kernel configuration.
| v2 | v3 |
|---|---|
SudoMechanism.NoPassword.SetSudo() |
.WithDockerCli("docker", d => d.WithSudo(SudoMechanism.NoPassword)) |
SudoMechanism.Password.SetSudo("pw") |
.WithDockerCli("docker", d => d.WithSudo(SudoMechanism.Password, "pw")) |
| Global static state | Per-driver configuration in kernel builder |
The SudoMechanism enum values are unchanged: None, NoPassword, Password.
// v2
SudoMechanism.NoPassword.SetSudo();
var svc = new Builder().UseContainer().UseImage("x").Build();
// v3
using var kernel = FluentDockerKernel.Create()
.WithDockerCli("docker", d => d
.AsDefault()
.WithSudo(SudoMechanism.NoPassword))
.Build();
var results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c.UseImage("x"))
.Build();
9. Compose Changes
| Aspect | v2 | v3 |
|---|---|---|
| Binary | docker-compose (standalone) |
docker compose (Compose V2 plugin) |
| Argument style | Positional / named args | Struct-based configs |
| Up | host.ComposeUp(composeFile, ...) |
await driver.UpAsync(ctx, new ComposeUpConfig { ... }) |
| Down | host.ComposeDown(composeFile, ...) |
await driver.DownAsync(ctx, new ComposeDownConfig { ... }) |
| Build | host.ComposeBuild(composeFile, ...) |
await driver.BuildAsync(ctx, new ComposeBuildConfig { ... }) |
Example
// v2
var svc = new Builder()
.UseCompose()
.FromFile("docker-compose.yml")
.RemoveOrphans()
.Build();
svc.Start();
// v3
var results = new Builder()
.WithinDriver("docker", kernel)
.UseCompose(c => c
.WithComposeFile("docker-compose.yml")
.RemoveOrphans())
.Build();
10. Removed APIs
The following v2 APIs have no v3 equivalent and have been removed entirely.
| Removed API | Reason | Alternative |
|---|---|---|
IMachineDriver / Hosts().Discover() |
Docker Machine is deprecated | Use Docker Contexts |
| Docker Toolbox support | Docker Toolbox is EOL | Use Docker Desktop |
Ductus.FluentDocker.Commands namespace |
Replaced by Driver Layer | Use IDriverPack / driver interfaces |
docker-compose standalone binary |
Deprecated upstream | v3 uses docker compose V2 plugin |
11. Async Pattern
v3 adds first-class async support with CancellationToken throughout.
| v2 | v3 |
|---|---|
| Mostly synchronous | All operations have async variants |
No CancellationToken support |
All async methods accept CancellationToken |
using var svc = builder.Build() |
using var results = await builder.BuildAsync(ct) |
IDisposable cleanup |
IAsyncDisposable preferred (sync IDisposable still supported) |
Sync vs. Async Build
// Sync (still works)
using var results = new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c.UseImage("redis:alpine"))
.Build();
// Async (preferred)
using var results = await new Builder()
.WithinDriver("docker", kernel)
.UseContainer(c => c.UseImage("redis:alpine"))
.BuildAsync(cancellationToken);
CancellationToken
Every async method accepts an optional CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await container.StartAsync(cts.Token);
await container.StopAsync(cts.Token);
var logs = await container.GetLogsAsync(cts.Token);
var stats = await container.GetStatsAsync(cts.Token);
Quick Migration Checklist
- Replace
Ductus.FluentDockerwithFluentDockerin allusingdirectives. - Add
using FluentDocker.Kernel;andusing FluentDocker.Services.Extensions;. - Create a
FluentDockerKernelwithWithDockerCli(...)before any builder use. - Wrap builder sub-calls in lambdas:
.UseContainer(c => c.UseImage(...)). - Pass the kernel via
.WithinDriver("docker", kernel). - Change
Build()call sites to expectBuildResultsinstead of a single service. - Remove
.Start()calls afterBuild()(auto-started). - Replace
Resume()withStart(). - Replace
Logs()withawait GetLogsAsync(). - Replace
Execute(cmd)withawait ExecuteAsync(cmd). - Move sudo config from global static into kernel builder.
- Replace
docker-composereferences withdocker composeV2. - Remove any Docker Machine / Toolbox code paths.
- Consider switching to
BuildAsync()/IAsyncDisposablefor new code.