Skip to content

[Feature]: Support multiple docker daemon #2629

Open

Description

Problem

I'm currently working on Sablier and this project needs to interact with a Docker host.
It can list, start and stop containers.

Interacting with direct socket may cause some issues: the workspace is polluted with my containers, and I don't want that.

So I've though of using a Docker in Docker container as my sandbox for my test.

Testcontainers does not enable me to spawn a Docker in Docker container to make subsequent request to it.
The current Docker host detection does not allow you to have multiple docker daemon.


Here's my sample:

// This create a Docker in Docker container and returns me 
// a docker client. This container is created with testcontainers.
cli, err := NewDind()
if err != nil {
t.Error(err)
}

// My app API that uses the client
p, err := SablierAPI(cli)
if err != nil {
t.Error(err)
}

// Tried to dynamically make requests using the rule `3.` for Docker host detection, does not work
ctx := context.WithValue(context.Background(), "DOCKER_HOST", cli.DaemonHost())

// Create multiple containers using testcontainers targeting the 
c, err := createRunningContainer(ctx)
...

And I though that Docker host detection rule 3 would actually make the trick.

  1. Read the Go context for the DOCKER_HOST key. E.g. ctx.Value("DOCKER_HOST"). This is used internally for the library to pass the Docker host to the resource reaper.

But it turns out that it does not for multiple reasons:

  1. The context is not propagated to the provider (on purpose ?)
    When issuing creation request, the provider itself uses a new blank context:

ctx := context.Background()

  1. The docker host is cached

// ExtractDockerHost Extracts the docker host from the different alternatives, caching the result to avoid unnecessary
// calculations. Use this function to get the actual Docker host. This function does not consider Windows containers at the moment.
// The possible alternatives are:
//
// 1. Docker host from the "tc.host" property in the ~/.testcontainers.properties file.
// 2. DOCKER_HOST environment variable.
// 3. Docker host from context.
// 4. Docker host from the default docker socket path, without the unix schema.
// 5. Docker host from the "docker.host" property in the ~/.testcontainers.properties file.
// 6. Rootless docker socket path.
// 7. Else, the default Docker socket including schema will be returned.
func ExtractDockerHost(ctx context.Context) string {
dockerHostOnce.Do(func() {
dockerHostCache = extractDockerHost(ctx)
})
return dockerHostCache
}

  1. The context docker_host is overriden with the one from the provider

r, err := reuseOrCreateReaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), core.SessionID(), p)

Solution

The solution would be to be for testcontainers to be able to pick up multiple containers and fully propagate the docker host at every call.

  1. Read the Go context for the DOCKER_HOST key. E.g. ctx.Value("DOCKER_HOST"). This is used internally for the library to pass the Docker host to the resource reaper.

So that this would be dynamic, it must not be cached.

Benefit

This would allow applications that tests docker interactions to work properly by using testcontainers features.

Alternatives

I could create the Docker in Docker container myself first, but it would defeat the original purpose of testcontainers in my opinion.

Would you like to help contributing this feature?

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    featureNew functionality or new behaviors on the existing one

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions