如何从 Docker 容器中的 python 脚本连接到 Ubuntu 上的本地 SQL 服务器
Posted
技术标签:
【中文标题】如何从 Docker 容器中的 python 脚本连接到 Ubuntu 上的本地 SQL 服务器【英文标题】:How do I connect to the local SQL server on Ubuntu from a python script in Docker container 【发布时间】:2022-01-04 16:42:51 【问题描述】:我在 Ubuntu 20.04 中安装了一个 SQL Server(它安装在 VirtualBox 中)和一个带有 python 脚本的 Docker 容器。 我要做的是从这个python脚本连接到主机上运行的SQL服务器。
这是我用来创建镜像的 Dockerfile:
# 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"]
我知道它看起来很乱,但是我在安装 pyodbc 时遇到了几个问题,看起来所有这些代码都解决了问题。
我现在可以成功创建映像,但是在启动容器时,它会产生以下输出:
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']
连接字符串好像有问题,如下所示:
connection_string = 'Driver=ODBC Driver 17 for SQL Server;Server=tcp:host.docker.internal,1433;UID=SA;PWD=<my_password>'
我已经为此苦苦挣扎了一段时间,但仍然无法使其发挥作用。非常感谢任何帮助或建议!
更新
按照 Pato 的建议,我尝试将连接字符串中的 Server
选项更改为机器的 IP 地址。
ip addr show
给我返回了以下输出:
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
所以,我尝试用127.0.0.1
、10.0.2.15
和172.17.0.1
替换host.docker.internal
。他们都给了我以下错误:
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
回复了我这个:
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
【问题讨论】:
你可以远程连接到 SQL Server 对吧? @Pato 忘了说:Ubuntu 安装在 VirtualBox 中。我不确定是否可以远程连接到 SQL Server。我该如何检查? ***.com/a/43025206/9925593 SQL Server 实例配置为侦听哪些地址和端口?可能它被配置为仅接受127.0.0.1:1433
上的连接,这将无法从 Docker 容器访问 - 因为 127.0.0.0/24
是每台机器/来宾/容器的不可路由环回网络。在 Ubuntu 客户机中运行 less /var/opt/mssql/mssql.conf
并查找 the network.* settings。
谢谢,您能否在 SQL Server 所在的同一虚拟机中安装和运行您的 python 脚本?在 connection_string 中使用这个 ip 127.0.0.1,1433。如果不起作用,请将 SQL Server 驱动程序更改为 pymssql。
【参考方案1】:
我正在研究这个连接问题,错误找不到文件是in this post。我试图重新创建你的设置,但我得到了同样的错误。
一个快速的解决方案是将驱动程序更改为 pymssql==2.2.2(在我的 docker 容器中测试)。
pip3 install pymssql==2.2.2
示例如下:
import pymssql
conn = pymssql.connect('host.docker.internal', 'sa', 'yourPassword', "database")
cursor = conn.cursor()
cursor.execute("""
IF OBJECT_ID('persons', 'U') IS NOT NULL
DROP TABLE persons
CREATE TABLE persons (
id INT NOT NULL,
name VARCHAR(100),
salesrep VARCHAR(100),
PRIMARY KEY(id)
)
""")
cursor.executemany(
"INSERT INTO persons VALUES (%d, %s, %s)",
[(1, 'John Smith', 'John Doe'),
(2, 'Jane Doe', 'Joe Dog'),
(3, 'Mike T.', 'Sarah H.')])
# you must call commit() to persist your data if you don't set autocommit to True
conn.commit()
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
row = cursor.fetchone()
while row:
print("ID=%d, Name=%s" % (row[0], row[1]))
row = cursor.fetchone()
conn.close()
# Result
'''
ID=1, Name=John Smith
'''
更新
SQL Server Linux 版本疑难解答
-
检查 mssql-server.service 是否正在运行。
patricio@server2:~$ sudo systemctl status mssql-server.service
[sudo] password for patricio:
● mssql-server.service - Microsoft SQL Server Database Engine
Loaded: loaded (/lib/systemd/system/mssql-server.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2021-11-10 09:56:38 -03; 2 weeks 4 days ago
Docs: https://docs.microsoft.com/en-us/sql/linux
Main PID: 14885 (sqlservr)
Tasks: 164
CGroup: /system.slice/mssql-server.service
├─14885 /opt/mssql/bin/sqlservr
└─14913 /opt/mssql/bin/sqlservr
-
检查端口 1433 或您的默认端口是否打开。
patricio@server2:~$ telnet 127.0.0.1 1433
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
patricio@server2:~$ nmap 127.0.0.1
Starting Nmap 7.60 ( https://nmap.org ) at 2021-11-29 08:41 -03
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000085s latency).
Not shown: 994 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
1433/tcp open ms-sql-s
// ...
-
如果没有安装sqlcmd,请安装
patricio@server2:~$ sqlcmd -S 127.0.0.1 -U sa -p
Password:
1> SELECT CONVERT(varchar, SERVERPROPERTY('collation'))
2> GO
------------------------------
SQL_Latin1_General_CP1_CI_AS
(1 rows affected)
参考资料:
From inside of a Docker container, how do I connect to the localhost of the machine?
Trying to access host.docker.internal results in Connection refused
【讨论】:
非常感谢您的帮助!不幸的是,现在我收到以下错误:File "src/pymssql/_pymssql.pyx", line 652, in pymssql._pymssql.connect pymssql._pymssql.OperationalError: (20009, b'DB-Lib error message 20009, severity 9:\nUnable to connect: Adaptive Server is unavailable or does not exist (host.docker.internal)\n')
@OlegIvanytskyi 检查更新。如果您的 docker 容器无法 ping 或无法访问您的 SQL Server,也许这篇文章可以帮助您***.com/q/20430371/9925593
@Oleg 检查参考文献
天啊,非常感谢!事实证明,--network="host"
是运行容器时的必要选项。然后我可以使用127.0.0.1
而不是host.docker.internal
并且一切正常。你拯救了我的一天!
我很高兴它成功了以上是关于如何从 Docker 容器中的 python 脚本连接到 Ubuntu 上的本地 SQL 服务器的主要内容,如果未能解决你的问题,请参考以下文章
将参数传递给 Docker 容器中的 Python argparse
Python 脚本在 docker 容器中找不到使用 CRON 运行的 ENV 变量
如何将 python 库从主机共享到多个 docker 容器?