Getting Started

This guide helps you install FluentDocker and run your first container. For the complete beginner-to-advanced map, see Learning Path.

Read This Guide in Order

  • Step 1: Installation and prerequisites
  • Step 2: Basic container example
  • Step 3: Add one wait strategy
  • Step 4: Optional next steps (named container, compose, async, multiple containers)

If you are new to FluentDocker, complete Step 1-3 before jumping to later sections.

Installation

NuGet Packages

# Core package (includes Testing.Core)
dotnet add package FluentDocker

# Optional: Test framework adapters
dotnet add package FluentDocker.Testing.Xunit   # xUnit adapter
dotnet add package FluentDocker.Testing.MsTest  # MSTest adapter
dotnet add package FluentDocker.Testing.NUnit   # NUnit adapter

Package References

<PackageReference Include="FluentDocker" Version="3.*" />
<PackageReference Include="FluentDocker.Testing.Xunit" Version="3.*" />
<PackageReference Include="FluentDocker.Testing.MsTest" Version="3.*" />
<PackageReference Include="FluentDocker.Testing.NUnit" Version="3.*" />

Prerequisites

  • Docker must be installed and running
  • .NET 10.0 or later

Verify Docker

docker --version
docker info

Your First Container

Basic Example

The v3 API uses a two-step approach: first create a kernel (multiple kernels per application are supported), then use the Builder to define and run containers.

using System.Linq;
using FluentDocker.Builders;
using FluentDocker.Kernel;
using FluentDocker.Services.Extensions;

// Step 1: Create a kernel (multiple kernels per app are supported)
using var kernel = FluentDockerKernel.Create()
    .WithDockerCli("docker", d => d.AsDefault())
    .Build();

// Step 2: Build and start an nginx container
using var results = new Builder()
    .WithinDriver("docker", kernel)
    .UseContainer(c => c
        .UseImage("nginx:alpine")
        .ExposePort("80"))
    .Build();

// Get the assigned host port
var container = results.Containers.First();
var endpoint = container.ToHostExposedEndpoint("80/tcp");
Console.WriteLine($"Nginx running at: http://localhost:{endpoint.Port}");

// All containers stop and are removed when results is disposed

With Wait Strategy

using FluentDocker.Builders;
using FluentDocker.Kernel;
using FluentDocker.Services.Extensions;

// kernel created as shown above

using var results = new Builder()
    .WithinDriver("docker", kernel)
    .UseContainer(c => c
        .UseImage("postgres:15-alpine")
        .WithEnvironment("POSTGRES_PASSWORD=mysecret")
        .ExposePort("5432")
        .WaitForPort("5432/tcp", 30000))
    .Build();

var container = results.Containers.First();
var endpoint = container.ToHostExposedEndpoint("5432/tcp");
var connectionString =
    $"Host=localhost;Port={endpoint.Port};Database=postgres;Username=postgres;Password=mysecret";

Named Container

// kernel created as shown above

using var results = new Builder()
    .WithinDriver("docker", kernel)
    .UseContainer(c => c
        .WithName("my-postgres")
        .UseImage("postgres:15-alpine")
        .WithEnvironment("POSTGRES_PASSWORD=secret")
        .ExposePort("5432")
        .WaitForPort("5432/tcp", 30000))
    .Build();

var container = results.Containers.First();
Console.WriteLine($"Container: {container.Name}");

Linux Users

Docker requires sudo by default. Configure FluentDocker:

using FluentDocker.Kernel;
using FluentDocker.Model.Common;

// Option 1: No sudo (recommended - add user to docker group)
// No configuration needed — this is the default

// Option 2: Sudo without password
using var kernel = FluentDockerKernel.Create()
    .WithDockerCli("docker", d => d.WithSudo(SudoMechanism.NoPassword).AsDefault())
    .Build();

// Option 3: Sudo with password
using var kernel = FluentDockerKernel.Create()
    .WithDockerCli("docker", d => d.WithSudo(SudoMechanism.Password, "your-password").AsDefault())
    .Build();

Best practice: Add your user to the docker group:

sudo usermod -aG docker $USER
# Log out and back in for changes to take effect

Async Operations

FluentDocker v3 supports full async/await via BuildAsync():

using FluentDocker.Builders;
using FluentDocker.Kernel;
using FluentDocker.Services.Extensions;

// kernel created as shown above

// Build containers asynchronously
using var results = await new Builder()
    .WithinDriver("docker", kernel)
    .UseContainer(c => c
        .UseImage("redis:alpine")
        .ExposePort("6379")
        .WaitForPort("6379/tcp", 30000))
    .BuildAsync();

var container = results.Containers.First();
var endpoint = container.ToHostExposedEndpoint("6379/tcp");
Console.WriteLine($"Redis running at: localhost:{endpoint.Port}");

Multiple Containers

The Builder lets you define a network and multiple containers in a single Build() call. Containers reference the network by its string name.

using FluentDocker.Builders;
using FluentDocker.Kernel;
using FluentDocker.Services.Extensions;

// kernel created as shown above

using var results = new Builder()
    .WithinDriver("docker", kernel)
    // Create a network first
    .UseNetwork(n => n
        .WithName("my-network")
        .RemoveOnDispose())
    // Start Redis on the network
    .UseContainer(c => c
        .WithName("my-redis")
        .UseImage("redis:alpine")
        .WithNetwork("my-network")
        .ExposePort("6379")
        .WaitForPort("6379/tcp", 30000))
    // Start app that uses Redis
    .UseContainer(c => c
        .WithName("my-app")
        .UseImage("myapp:latest")
        .WithNetwork("my-network")
        .WithEnvironment("REDIS_HOST=my-redis")
        .ExposePort("8080")
        .WaitForPort("8080/tcp", 30000))
    .Build();

// Both containers can communicate via the network
var redis = results.GetContainer("my-redis");
var app = results.GetContainer("my-app");

Docker Compose Quick Start

For multi-container applications, use Docker Compose:

using FluentDocker.Builders;
using FluentDocker.Kernel;

// kernel created as shown above

using var results = new Builder()
    .WithinDriver("docker", kernel)
    .UseCompose(c => c
        .WithComposeFile("docker-compose.yml")
        .WithRemoveOrphans())
    .Build();

// Access compose services
foreach (var compose in results.ComposeServices)
{
    Console.WriteLine($"Compose project: {compose.Name}");
}

See Docker Compose for detailed examples.

Logging

FluentDocker logs through Microsoft.Extensions.Logging.Abstractions. The kernel builder requires an ILoggerFactory — there is no library-side default. Pass NullLoggerFactory.Instance when you want silence:

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using FluentDocker.Kernel;

// Receive structured logs via any provider
using var factory = LoggerFactory.Create(b => b.AddConsole());
var kernel = await FluentDockerKernel.Create(factory)
    .WithDockerCli("docker", d => d.AsDefault())
    .BuildAsync();

// Or suppress all logs explicitly
var silent = await FluentDockerKernel.Create(NullLoggerFactory.Instance)
    .WithDockerCli("docker", d => d.AsDefault())
    .BuildAsync();

See Utilities → Logging for filtering, categories, and the per-level severity policy.

Exception Handling

Always use try-catch or using to ensure cleanup:

// kernel created as shown above

try
{
    using var results = new Builder()
        .WithinDriver("docker", kernel)
        .UseContainer(c => c
            .UseImage("postgres:15-alpine")
            .ExposePort("5432")
            .WaitForPort("5432/tcp", 10000))
        .Build();

    var container = results.Containers.First();
    // Use container...
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
    // Results and all containers are disposed even on exception
}

Next Steps