I have an SQL Server installed in Ubuntu 20.04 (which is installed in VirtualBox) and a Docker container with a python script in it. What I want to do is to connect from this python script to the SQL server running on the host.
Here is the Dockerfile I used to create an image:
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN apt-get update && apt-get install -y gnupg2 curl
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql17
RUN ACCEPT_EULA=Y apt-get install -y mssql-tools
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
RUN echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
RUN apt-get update \
&& apt-get -y install gcc \
&& apt-get -y install g++ \
&& apt-get -y install unixodbc unixodbc-dev \
&& apt-get clean
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "python3", "-m" , "test", "run", "--host=0.0.0.0"]
I know it looks messy, but I encountered several issues while installing pyodbc, and it looks like all this code has solved the problem.
I can now successfully create an image, but when launching a container, it produces the following output:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/local/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/app/test.py", line 10, in <module>
connection = pyodbc.connect(connection_string, autocommit=True)
pyodbc.OperationalError: ('HYT00', '[HYT00] [Microsoft][ODBC Driver 17 for SQL Server]Login timeout expired (0) (SQLDriverConnect)')
['ODBC Driver 17 for SQL Server']
It looks like there is something wrong with the connection string, which looks like this:
connection_string = 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:host.docker.internal,1433;UID=SA;PWD=<my_password>'
I've been struggling with this for some time now but still cannot make it work. Would appreciate any help or advice!
UPD
As Pato recommended, I tried changing the Server
option in the connection string with the IP address of the machine.
ip addr show
returned me the following output:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 08:00:27:29:e8:b8 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic noprefixroute enp0s3
valid_lft 71149sec preferred_lft 71149sec
inet6 fe80::2517:652e:ac69:8ec9/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:35:26:ba:86 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:35ff:fe26:ba86/64 scope link
valid_lft forever preferred_lft forever
So, I tried substituting host.docker.internal
with 127.0.0.1
, 10.0.2.15
and 172.17.0.1
. All of them gave me the following error:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/local/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/app/test.py", line 10, in <module>
connection = pyodbc.connect(connection_string, autocommit=True)
pyodbc.Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib 'ODBC Driver 17 for SQL Server;Server=tcp:172.17.0.1,1433;UID=SA;PWD=<my_password>' : file not found (0) (SQLDriverConnect)")
ifconfig
returned me this:
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:35ff:fe26:ba86 prefixlen 64 scopeid 0x20<link>
ether 02:42:35:26:ba:86 txqueuelen 0 (Ethernet)
RX packets 25340 bytes 1240556 (1.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 39308 bytes 691001962 (691.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255
inet6 fe80::2517:652e:ac69:8ec9 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:29:e8:b8 txqueuelen 1000 (Ethernet)
RX packets 649701 bytes 946934508 (946.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 55603 bytes 7183567 (7.1 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 27675 bytes 49732911 (49.7 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27675 bytes 49732911 (49.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0