ory / dockertest

Write better integration tests! Dockertest helps you boot up ephermal docker images for your Go tests with minimal work.
https://www.ory.sh/?utm_source=github&utm_medium=banner&utm_campaign=dockertest
Apache License 2.0
4.18k stars 243 forks source link

dynamic port binding with ExposedPorts option stopped working #518

Open ruz opened 4 months ago

ruz commented 4 months ago

Preflight checklist

Ory Network Project

No response

Describe the bug

The following code stopped working:

    resource, err := pool.RunWithOptions(&dockertest.RunOptions{
        Repository: "minio/minio",
        Tag:        "latest",
        Env: []string{
            "MINIO_ROOT_USER=root",
            "MINIO_ROOT_PASSWORD=password",
        },
        ExposedPorts: []string{"9000", "9090"},
        Cmd:          []string{"server", "/data", "--console-address", ":9090"},
    })
    if err != nil {
        log.Panic("Could not start resource: " + err.Error())
    }

ExposedPort is important part.

Tests work if I bind to static ports, but I don't want to.

Tests work if I don't use ExposedPorts, but then I can not get console port. The following code returns empty result.

consolePort := resource.GetPort("9090/tcp")

Reproducing the bug

Run an example with dynamic port binding with docker on mac os X.

Relevant log output

PANIC   system/main.go:158  Could not start resource: API error (500): driver failed programming external connectivity on endpoint silly_ride (ef09fb567874580ad719b53df2552236aaa0f55f078a32dafd3ef2a3baaabe3a): failed to bind port 0.0.0.0:55010/tcp: listen tcp4 0.0.0.0:55010: bind: address already in use

Relevant configuration

No response

Version

v3.10.0

On which operating system are you observing this issue?

macOS

In which environment are you deploying?

Docker

Additional Context

$ docker version
Client:
 Version:           27.1.1
 API version:       1.46
 Go version:        go1.21.12
 Git commit:        6312585
 Built:             Tue Jul 23 19:54:12 2024
 OS/Arch:           darwin/amd64
 Context:           desktop-linux

Server: Docker Desktop 4.33.0 (160616)
 Engine:
  Version:          27.1.1
  API version:      1.46 (minimum version 1.24)
  Go version:       go1.21.12
  Git commit:       cc13f95
  Built:            Tue Jul 23 19:57:19 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.19
  GitCommit:        2bf793ef6dc9a18e00cb12efb64355c2c9d5eb41
 runc:
  Version:          1.7.19
  GitCommit:        v1.1.13-0-g58aa920
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Mac OS 14.5 (23F79) on Intel CPU

go.mod

github.com/ory/dockertest/v3 v3.10.0
github.com/minio/minio-go/v7 v7.0.74
ruz commented 4 months ago

Tried the latest commit on v3, still fails.

ruz commented 4 months ago

Tried 3.6.0 and it fails in the same way. May be it's caused by some change in Docker.

slashformotion commented 4 months ago

Exactly the same issue here

driver failed programming external connectivity on endpoint int-zookeeper (80fec4338c4c52fbdb8a5196a9cf701c675c69cf1eee0d61f663b405f181d115): failed to bind port 0.0.0.0:55029/tcp: listen tcp4 0.0.0.0:55029: bind: address already in use

here is the code that fails:

    zookeeperResource, err := env.pool.RunWithOptions(&dockertest.RunOptions{
        Name:       "int-zookeeper",
        Repository: "confluentinc/cp-zookeeper",
        Tag:        "7.4.0",
        NetworkID:  env.network.Network.ID,
        Hostname:   "zookeeper",
        ExposedPorts: []string{"2181"},
        Mounts:     []string{projectRootPath + "/deploy/secrets/kafka:/etc/kafka/secrets"},
        Env: []string{
            "ZOOKEEPER_CLIENT_PORT=2181",
            "ZOOKEEPER_TICK_TIME=2000",
            "KAFKA_OPTS=-Djava.security.auth.login.config=/etc/kafka/secrets/zookeeper_jaas.conf -Dzookeeper.authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider -Dzookeeper.allowSaslFailedClients=false -Dzookeeper.requireClientAuthScheme=sasl",
        },
    })
w84miracle commented 4 months ago

Same issue, but found a workaround. if you're 100% sure that port is not in use by other applications, append /tcp to your ExposedPorts works in my case. e.g. ExposedPorts: []string{"5432/tcp"}, @ruz @slashformotion could you test if that works in you case?

w84miracle commented 4 months ago

Based on the doc for POST /containers/create the ExposedPorts should be in this format {"<port>/<tcp|udp|sctp>": {}}

Apparently previous docker engine API fallbacks to tcp, I couldn't find any related changelog though.

ruz commented 4 months ago

adding "/tcp" to the value helps and results in expected behavior.

I believe that Docker doesn't validate input in the API call and at some point invalid input worked and now it doesn't.

This bug shouldn't be closed. This examples should be changed, so other people avoid falling into the same trap.

zerok commented 4 months ago

Might this be related to Docker v27.x? I also see this behavior popping up with v27.x but it was working with v26.x.

slashformotion commented 4 months ago

adding "/tcp" to the value makes the issue go away on my end.

tssa88 commented 3 months ago

Coincidentally, today I updated my local docker and started facing the same issue.

API error (500): driver failed programming external connectivity on endpoint sleepy_gould (86793e338116329442cc0759b961253ae250cb4d27b10839c32b4b90b882c956): failed to bind port 0.0.0.0:55065/tcp: listen tcp4 0.0.0.0:55065: bind: address already in use

I can confirm the port is not in use by other applications.

Adding "/tcp" works.

alnr commented 3 months ago

This must have been caused by a docker dependency upgrade. Thanks for working out the solution. PRs to update examples are appreciated.