testcontainers / testcontainers/testcontainers-python

Bug: (windows/wsl/socket-dind) Devcontainers docker-outside-of-docker ConnectionRefusedError: [Errno 111] Connection refused

Open
#538 2 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.3k
Forks
386
Avg merge
4h 40m
Merged PRs (30d)
1

Description

Describe the bug

A clear and concise description of what the bug is. What did you expect to happen? What happened instead?

Main code exists inside a devcontainer. The host machine (windows) docker is mounted into the container to enable docker-outside-of-docker.

Expected the tests to run.

To Reproduce

Provide a self-contained code snippet that illustrates the bug or unexpected behavior. Ideally, send a Pull Request to illustrate with a test that illustrates the problem.

# tests/test_api_auth.py
from sqlmodel import Session, SQLModel, create_engine, select
from testcontainers.postgres import PostgresContainer

def test_session():

    with PostgresContainer("postgres:16") as postgres:
        DB_URL = postgres.get_connection_url()
        print(f"{DB_URL = }")

        test_engine = create_engine(f"{DB_URL}")

        SQLModel.metadata.create_all(test_engine)
        with Session(test_engine) as session:
            print(session)
$ hatch run test
=================================================================== test session starts ===================================================================
platform linux -- Python 3.12.2, pytest-8.1.1, pluggy-1.4.0
rootdir: /workspaces/microservice-py-docker
configfile: pyproject.toml
plugins: anyio-4.3.0
collected 1 item                                                                                                                                          

tests/test_api_auth.py F                                                                                                                            [100%]

======================================================================== FAILURES =========================================================================
______________________________________________________________________ test_session _______________________________________________________________________

    def test_session():
    
>       with PostgresContainer("postgres:16") as postgres:

tests/test_api_auth.py:6: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/home/vscode/.local/share/hatch/env/virtual/api/6jr5RRfn/api/lib/python3.12/site-packages/testcontainers/core/container.py:98: in __enter__
    return self.start()
/home/vscode/.local/share/hatch/env/virtual/api/6jr5RRfn/api/lib/python3.12/site-packages/testcontainers/core/generic.py:70: in start
    super().start()
/home/vscode/.local/share/hatch/env/virtual/api/6jr5RRfn/api/lib/python3.12/site-packages/testcontainers/core/container.py:76: in start
    Reaper.get_instance()
/home/vscode/.local/share/hatch/env/virtual/api/6jr5RRfn/api/lib/python3.12/site-packages/testcontainers/core/container.py:175: in get_instance
    Reaper._instance = Reaper._create_instance()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'testcontainers.core.container.Reaper'>

    @classmethod
    def _create_instance(cls) -> "Reaper":
        logger.debug(f"Creating new Reaper for session: {SESSION_ID}")
    
        Reaper._container = (
            DockerContainer(c.ryuk_image)
            .with_name(f"testcontainers-ryuk-{SESSION_ID}")
            .with_exposed_ports(8080)
            .with_volume_mapping(c.ryuk_docker_socket, "/var/run/docker.sock", "rw")
            .with_kwargs(privileged=c.ryuk_privileged, auto_remove=True)
            .with_env("RYUK_RECONNECTION_TIMEOUT", c.ryuk_reconnection_timeout)
            .start()
        )
        wait_for_logs(Reaper._container, r".* Started!")
    
        container_host = Reaper._container.get_container_host_ip()
        container_port = int(Reaper._container.get_exposed_port(8080))
    
        Reaper._socket = socket()
>       Reaper._socket.connect((container_host, container_port))
E       ConnectionRefusedError: [Errno 111] Connection refused

/home/vscode/.local/share/hatch/env/virtual/api/6jr5RRfn/api/lib/python3.12/site-packages/testcontainers/core/container.py:212: ConnectionRefusedError
------------------------------------------------------------------ Captured stderr call -------------------------------------------------------------------
Pulling image testcontainers/ryuk:0.7.0
Container started: 4544557450bc
Waiting for container <Container: 4544557450bc> with image testcontainers/ryuk:0.7.0 to be ready ...
-------------------------------------------------------------------- Captured log call --------------------------------------------------------------------
INFO     testcontainers.core.container:container.py:77 Pulling image testcontainers/ryuk:0.7.0
INFO     testcontainers.core.container:container.py:89 Container started: 4544557450bc
INFO     testcontainers.core.waiting_utils:waiting_utils.py:52 Waiting for container <Container: 4544557450bc> with image testcontainers/ryuk:0.7.0 to be ready ...
================================================================= short test summary info =================================================================
FAILED tests/test_api_auth.py::test_session - ConnectionRefusedError: [Errno 111] Connection refused
==================================================================== 1 failed in 0.99s ====================================================================

Runtime environment

Provide a summary of your runtime environment. Which operating system, python version, and docker version are you using? What is the version of testcontainers-python you are using? You can run the following commands to get the relevant information.

# Get the operating system information (on a unix os).
$ uname -a
Linux 63a6749e4833 5.15.146.1-microsoft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 GNU/Linux
# Get the python version.
$ python --version
Python 3.12.2
# Get the docker version and other docker information.
$ docker info
Client:
 Version:    24.0.9-2
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  0.13.1-1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  2.26.1-1
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 6
  Running: 1
  Paused: 0
  Stopped: 5
 Images: 13
 Server Version: 25.0.3
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  seccomp
   Profile: unconfined
 Kernel Version: 5.15.146.1-microsoft-standard-WSL2
 Operating System: Docker Desktop
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 15.48GiB
 Name: docker-desktop
 ID: 45754d98-604b-4d4d-b9df-e3dafed10e0b
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No blkio throttle.read_bps_device support
WARNING: No blkio throttle.write_bps_device support
WARNING: No blkio throttle.read_iops_device support
WARNING: No blkio throttle.write_iops_device support
WARNING: daemon is not using the default seccomp profile
# Get all python packages.
$ pip freeze
anyio==4.3.0
bcrypt==4.1.2
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
coverage==7.4.4
cryptography==42.0.5
dnspython==2.6.1
docker==7.0.0
ecdsa==0.19.0
email_validator==2.1.1
fastapi==0.88.0
greenlet==3.0.3
h11==0.14.0
httpcore==1.0.5
httptools==0.6.1
httpx==0.27.0
idna==3.7
iniconfig==2.0.0
itsdangerous==2.1.2
Jinja2==3.1.3
MarkupSafe==2.1.5
orjson==3.10.0
packaging==24.0
passlib==1.7.4
pika==1.3.2
pluggy==1.4.0
psycopg2==2.9.9
pyasn1==0.6.0
pycparser==2.22
pydantic==1.10.0
pytest==8.1.1
python-dotenv==1.0.1
python-jose==3.3.0
python-multipart==0.0.9
PyYAML==6.0.1
requests==2.31.0
rsa==4.9
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
sqlmodel==0.0.13
starlette==0.22.0
testcontainers==4.3.3
typing_extensions==4.11.0
ujson==5.9.0
urllib3==2.2.1
uvicorn==0.29.0
uvloop==0.19.0
watchfiles==0.21.0
websockets==12.0
wrapt==1.16.0

Devcontainer file

{
	"name": "Python 3",
	"image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye",
	"features": {
		"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
	}
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with tests/test_api_auth.py and the Reaper._create_instance path in testcontainers/core/container.py, then reproduce the failure using the supplied Windows/WSL devcontainer configuration. Trace how the Ryuk container host and exposed port are selected; done means the example test starts Postgres and completes without ConnectionRefusedError.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, python
Domain
devops, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.