testcontainers-python icon indicating copy to clipboard operation
testcontainers-python copied to clipboard

Containers fail to start: mssql/win11, mssql/m1, mssql with different port (not intended to work), postgres/win10, mariadb/win11, oracle

Open snifhex opened this issue 2 years ago • 13 comments

I'm unable to run the SqlServerContainer. After creating the MSSQL container, it gets stuck at the "waiting to be ready" state and does not proceed further.

image

To Reproduce

from sqlalchemy import create_engine, text
from testcontainers.mssql import SqlServerContainer

with SqlServerContainer() as mssql:
    engine = create_engine(mssql.get_connection_url())
    with engine.begin() as connection:
        version = connection.execute(text("select @@VERSION"))

Runtime environment

Docker Desktop 4.19.0 (106363)
Windows 11
Python 3.9
testcontainers==3.7.1

snifhex avatar May 29 '23 11:05 snifhex

it gets stuck at the "waiting to be ready" state and does not proceed further.

Does it finish execution at some point? Because your code does not actually print anything so you would see no output even if it works...

from sqlalchemy import create_engine, text
from testcontainers.mssql import SqlServerContainer

with SqlServerContainer() as mssql:
    engine = create_engine(mssql.get_connection_url())
    with engine.begin() as connection:
        version = connection.execute(text("select @@VERSION"))
        print(version.all())

This works fine for me (on linux though):

$ python baz.py
Pulling image mcr.microsoft.com/mssql/server:2019-latest
Container started: 813db1176b94
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
Waiting to be ready...
mssql+pymssql://SA:1Secure*Password1@localhost:49158/tempdb
[('Microsoft SQL Server 2019 (RTM-CU21) (KB5025808) - 15.0.4316.3 (X64) \n\tJun  1 2023 16:32:31 \n\tCopyright (C) 2019 Microsoft Corporation\n\tDeveloper Edition (64-bit) on Linux (Ubuntu 20.04.6 LTS) <X64>',)]

paketb0te avatar Jun 26 '23 09:06 paketb0te

Any updates on this? I am facing the same issue on mac m1 machine.

UsmanAbbasi1 avatar Jul 05 '23 16:07 UsmanAbbasi1

Hello,

Any news ?

Same for me here !

EDIT :

It works if I do not change the default port for me

robinalexandre avatar Jul 07 '23 10:07 robinalexandre

Same for me but for the PostgreSQL container:

Pulling image postgres:latest Container started: 502b64b3db55 Waiting to be ready... Waiting to be ready... Waiting to be ready...

Code is:

from testcontainers.postgres import PostgresContainer
postgres_container = PostgresContainer("postgres:latest", port=54321, dbname=database_name)
    with postgres_container as postgres:
        # Get the connection details for the container
        connection_details = postgres.get_connection_url()

env:

Docker Desktop 4.21.1 
Windows 10
Python 3.9
testcontainers==3.7.1

ieCecchetti avatar Aug 07 '23 10:08 ieCecchetti

There is a temporary solution mentioned for this issue: https://github.com/testcontainers/testcontainers-python/issues/108#issuecomment-768367971

JamesFlanders avatar Aug 17 '23 07:08 JamesFlanders

I've encountered this same issue with mariadb:11.1.2 on Windows 11, except in my case, I was using testcontainers.mysql.MySqlContainer. I got around this issue by just using the core API instead of relying on the addon package:

import subprocess
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs
from time import sleep
from tqdm import tqdm


IMAGE="mariadb:11.1.2"

# Run the docker pull as a separate process since relying on testcontainers to
# pull through the API on windows gives me some issue.
if subprocess.run(["docker", "pull", IMAGE]).returncode == 1:
    raise Exception(
        f"Unable to pull image '{IMAGE}'. Make sure the Docker daemon is "
        "running. If problems persist, you can pull the image manually."
    )

container = DockerContainer(image=IMAGE)
container.env={
   "MARIADB_ALLOW_EMPTY_ROOT_PASSWORD": "1",
   "MARIADB_ALLOW_EMPTY_PASSWORD": "1",
}
container.start()
waiting = wait_for_logs(container, "ready for connections")
print(container.get_container_host_ip)
for i in tqdm(range(20)):
   # Take this time to check docker that the container is running!
   sleep(1)
container.stop()

I hope this helps someone!

nsaccente avatar Nov 05 '23 02:11 nsaccente

Same for me for Oracle

    from testcontainers.oracle import OracleDbContainer

    with OracleDbContainer() as oracle:
        engine = sqlalchemy.create_engine(oracle.get_connection_url())

        with engine.begin() as connection:
            result = connection.execute(sqlalchemy.text("select * from V$VERSION"))

env

Docker Desktop v4.26.1
Windows 10
Python 3.11
testcontainers==3.7.1

thuyng-ing avatar Jan 25 '24 17:01 thuyng-ing

<Quoted Reply>

I've encountered this same issue with mariadb:11.1.2 on Windows 11, except in my case, I was using testcontainers.mysql.MySqlContainer. I got around this issue by just using the core API instead of relying on the addon package:

import subprocess
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs
from time import sleep
from tqdm import tqdm


IMAGE="mariadb:11.1.2"

# Run the docker pull as a separate process since relying on testcontainers to
# pull through the API on windows gives me some issue.
if subprocess.run(["docker", "pull", IMAGE]).returncode == 1:
    raise Exception(
        f"Unable to pull image '{IMAGE}'. Make sure the Docker daemon is "
        "running. If problems persist, you can pull the image manually."
    )

container = DockerContainer(image=IMAGE)
container.env={
   "MARIADB_ALLOW_EMPTY_ROOT_PASSWORD": "1",
   "MARIADB_ALLOW_EMPTY_PASSWORD": "1",
}
container.start()
waiting = wait_for_logs(container, "ready for connections")
print(container.get_container_host_ip)
for i in tqdm(range(20)):
   # Take this time to check docker that the container is running!
   sleep(1)
container.stop()

I hope this helps someone!

Thanks to @nsaccente reply. I managed to make something that works for Oracle on Windows 10. I hope this helps someone.

oracle container sample code
import subprocess

import sqlalchemy
from sqlalchemy import create_engine
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs

IMAGE="gvenzl/oracle-xe:21-slim-faststart"

# Run the docker pull as a separate process since relying on testcontainers to
# pull through the API on windows gives me some issue.
if subprocess.run(["docker", "pull", IMAGE]).returncode == 1:
    raise Exception(
        f"Unable to pull image '{IMAGE}'. Make sure the Docker daemon is "
        "running. If problems persist, you can pull the image manually."
    )

db_port = 1521
db_username = "system"
db_password = "oracle"
db_name = "xe"
os.environ['TC_HOST'] = 'localhost'

container = DockerContainer(image=IMAGE)

container.with_exposed_ports(db_port)
container.env={
    "ORACLE_USERNAME": "system",
    "ORACLE_PASSWORD": "oracle",
    "DB_NAME": "xe",
    "DB_HOST": "oracle",
}

container.start()

waiting = wait_for_logs(container, "DATABASE IS READY TO USE!")

engine = create_engine(f'oracle+oracledb://system:oracle@(DESCRIPTION=(CONNECT_TIMEOUT=30)(RETRY_COUNT=20)(RETRY_DELAY=3)(ADDRESS_LIST=(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=TCP)(HOST={container.get_container_host_ip()})(PORT={container.get_exposed_port(db_port)})))(CONNECT_DATA=(SERVICE_NAME={db_name})))')
with engine.begin() as connection:
    result = connection.execute(sqlalchemy.text("select * from V$VERSION"))
    print(result)

container.stop()

thuyng-ing avatar Jan 26 '24 14:01 thuyng-ing

@thuyng-ing i think this is the module we are looking to merge for oracle but i guess we will be looking at these suggestions as well when we are able to publish again - https://github.com/testcontainers/testcontainers-python/pull/363

alexanderankin avatar Jan 26 '24 15:01 alexanderankin

<Quoted Reply>

I've encountered this same issue with mariadb:11.1.2 on Windows 11, except in my case, I was using testcontainers.mysql.MySqlContainer. I got around this issue by just using the core API instead of relying on the addon package:

import subprocess
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs
from time import sleep
from tqdm import tqdm


IMAGE="mariadb:11.1.2"

# Run the docker pull as a separate process since relying on testcontainers to
# pull through the API on windows gives me some issue.
if subprocess.run(["docker", "pull", IMAGE]).returncode == 1:
    raise Exception(
        f"Unable to pull image '{IMAGE}'. Make sure the Docker daemon is "
        "running. If problems persist, you can pull the image manually."
    )

container = DockerContainer(image=IMAGE)
container.env={
   "MARIADB_ALLOW_EMPTY_ROOT_PASSWORD": "1",
   "MARIADB_ALLOW_EMPTY_PASSWORD": "1",
}
container.start()
waiting = wait_for_logs(container, "ready for connections")
print(container.get_container_host_ip)
for i in tqdm(range(20)):
   # Take this time to check docker that the container is running!
   sleep(1)
container.stop()

I hope this helps someone!

Thanks to @nsaccente reply. I managed to make something that works for Oracle on Windows 10. I hope this helps someone.

import subprocess

import sqlalchemy
from sqlalchemy import create_engine
from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_for_logs

IMAGE="gvenzl/oracle-xe:21-slim-faststart"

# Run the docker pull as a separate process since relying on testcontainers to
# pull through the API on windows gives me some issue.
if subprocess.run(["docker", "pull", IMAGE]).returncode == 1:
    raise Exception(
        f"Unable to pull image '{IMAGE}'. Make sure the Docker daemon is "
        "running. If problems persist, you can pull the image manually."
    )

db_port = 1521
db_username = "system"
db_password = "oracle"
db_name = "xe"
os.environ['TC_HOST'] = 'localhost'

container = DockerContainer(image=IMAGE)

container.with_exposed_ports(db_port)
container.env={
    "ORACLE_USERNAME": "system",
    "ORACLE_PASSWORD": "oracle",
    "DB_NAME": "xe",
    "DB_HOST": "oracle",
}

container.start()

waiting = wait_for_logs(container, "DATABASE IS READY TO USE!")

engine = create_engine(f'oracle+oracledb://system:oracle@(DESCRIPTION=(CONNECT_TIMEOUT=30)(RETRY_COUNT=20)(RETRY_DELAY=3)(ADDRESS_LIST=(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=TCP)(HOST={container.get_container_host_ip()})(PORT={container.get_exposed_port(db_port)})))(CONNECT_DATA=(SERVICE_NAME={db_name})))')
with engine.begin() as connection:
    result = connection.execute(sqlalchemy.text("select * from V$VERSION"))
    print(result)

container.stop()
@pytest.fixture(scope="session", autouse=True)
def setup_testdb(): 
    image = "mcr.microsoft.com/mssql/server:2022-latest"
    container = DockerContainer(image=image)
    container.env = {
        "ACCEPT_EULA": "Y",
        "MSSQL_SA_PASSWORD":"1TestTest!"
    }
    container.with_bind_ports(1433, host=1433)
    with container as mssql:
        wait_for_logs(container, "SQL Server is now ready for client connections")
        print(mssql.get_container_host_ip())
        yield mssql

The above listing adapted for usage within a pytest.fixture and mssql. Thank you very much for your help!

Wormfriend avatar Feb 01 '24 11:02 Wormfriend

I have the same problem

Just wanted to add a clue to the problem solving (I know below isn't really practical as a solution)...

If I debug into the SqlServerContainer and further into the _connect method of the underlying DbContainer base class and simply step through the lines the container class successfully instantiates and connects to the docker container. This led me to believe that the time delay introduced by manually stepping through the code in debug made the testcontainer successfully capture the log message it was listening for.

In fact, adding a sleep to the start method of the DbContainer makes it run successfully on my end (I know this is hacky and is likely hiding another problem - but wanted to mention it as a clue)

image

mlt-dk avatar Apr 03 '24 12:04 mlt-dk

The SQL Server images take a looong time to start in most cases. To try pinpointing the errors here further, you could try the following:

  • Try using a specific SQL Server container image tag, like mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04
  • Try using a lighter SQL Server compatible image like mcr.microsoft.com/azure-sql-edge:1.0.7

Also note that the default SqlServerContainer expects sqlalchemy to use the pymssql driver, where the package pymssql needs to be installed. If you want to use another driver (which also needs to be installed), try using pyodbc:

with SqlServerContainer("mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04", dialect="mssql+pyodbc",) as mssql:
    engine = sqlalchemy.create_engine(mssql.get_connection_url())
    with engine.begin() as connection:
        result = connection.execute(sqlalchemy.text("select @@VERSION"))

Lastly, to check that you are able to start the image at all, try starting it manually with docker and observe the log output:

docker run -e ACCEPT_EULA=y -e SQLSERVER_USER=SA -e SA_PASSWORD="1Secure*Password1" mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04

santi avatar Apr 04 '24 08:04 santi

On another note: If https://github.com/testcontainers/testcontainers-python/pull/525 lands, the wait strategy will change and testing will be more robust for more image versions which might fix your problems.

santi avatar Apr 04 '24 08:04 santi