testcontainers / testcontainers-go

Testcontainers for Go is a Go package that makes it simple to create and clean up container-based dependencies for automated integration/smoke tests. The clean, easy-to-use API enables developers to programmatically define containers that should be run as part of a test and clean up those resources when the test is done.
https://golang.testcontainers.org
MIT License
3.7k stars 507 forks source link

[Feature]: Support multiple docker daemon #2629

Open acouvreur opened 5 months ago

acouvreur commented 5 months ago

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:

https://github.com/testcontainers/testcontainers-go/blob/d94455b5799ffe6909eb403dbdba38e2e69fd77a/provider.go#L142

  1. The docker host is cached

https://github.com/testcontainers/testcontainers-go/blob/d94455b5799ffe6909eb403dbdba38e2e69fd77a/internal/core/docker_host.go#L59-L76

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

https://github.com/testcontainers/testcontainers-go/blob/d94455b5799ffe6909eb403dbdba38e2e69fd77a/docker.go#L983

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

acouvreur commented 5 months ago

I've tried to allow overriding the context variable, but this is not working properly.

Because in the end, you need to be able to manage multiple instances of one docker client, which is not the case here.

I think this feature would need more than just allowing overriding.