【问题标题】:Driver's SQLAllocHandle on SQL_HANDLE_HENV failed (0) (SQLDriverConnect) when connecting to Azure SQL database from Python running in OpenShift从在 OpenShift 中运行的 Python 连接到 Azure SQL 数据库时,驱动程序的 SQL_HANDLE_HENV 上的 SQLAllocHandle 失败 (0) (SQLDriverConnect)
【发布时间】:2019-04-02 12:23:27
【问题描述】:

仅当尝试从运行的 Python 3.7 连接到我的 Azure DB 时 一个 OpenShift 容器(来自 rhel7:latest)我看到以下错误:

sqlalchemy.exc.DBAPIError: (pyodbc.Error) ('IM004', "[IM004][unixODBC][Driver Manager]Driver's SQLAllocHandle on SQL_HANDLE_HENV failed (0) (SQLDriverConnect)

我在我的 MAC、Windows 和运行 RHEL7 基本容器的 RHEL7 Virtualbox 上尝试了完全相同的代码 - 它总是有效!问题只出在我在 OpenShift 中运行的容器中! 我检查了我是否可以从 Openshift 远程登录到 1433 年的 Azure DB 服务器。

我也启用了 ODBC 日志,但没有比上述错误更多的信息。

我还应该检查什么?

这是我在 Dockerfile 中设置 MSODBC 驱动程序的方法:

RUN curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo && \
 yum remove unixODBC-utf16 unixODBC-utf16-devel && \
 ACCEPT_EULA=Y yum install -y msodbcsql17 && \
 yum install -y unixODBC-devel

这是引发错误的代码:

在 modules.database 内:

pyodbc_connstring_safe = 'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER='+config.settings["DB_HOST"]+\
                        ';PORT=1433;DATABASE='+config.settings["DB_NAME"]+';UID='+config.usernames["database"]+\
                        ';PWD={};MARS_Connection=Yes'

if config.settings["debug"]:
    print("Using DB connection string: {}".format(pyodbc_connstring_safe.format("SAFE_DB_PASS")))

pyodbc_connstring = pyodbc_connstring_safe.format(config.passwords["database"])

Base = declarative_base()
quoted = urllib.parse.quote_plus(pyodbc_connstring)

def get_engine():
    return create_engine('mssql+pyodbc:///?odbc_connect={}'.format(quoted), echo=config.settings["debug"], pool_pre_ping=True)

在我的烧瓶应用程序中(在调用“has_table”时会引发错误):

@app.route("/baselinedb", methods=["POST"])
def create_db():
    from modules.database import Base
    engine = database.get_engine()
    if not engine.dialect.has_table(engine, database.get_db_object_name("BaselineDefinition"), schema = 'dbo'):
        Base.metadata.create_all(engine)
    db.session.commit()
    return "OK"

正如我在开头提到的,同一个 Dockerfile 为我提供了一个工作在 Docker 中的容器,无论是在 Mac 或 Windows 上本地还是在 RHEL7 VM 内。 感谢您的观看!

【问题讨论】:

  • 您使用的是 Flask-SQLAlchemy 扩展还是 OpenShift 的 Flask-Login 扩展?本教程涵盖了两者,可能会帮助您在 OpenShift 环境中仔细检查您的配置:blog.openshift.com/…
  • 感谢@MikeUbezziMSFT,我正在使用 Flask-SQLAlchemy。我去看看链接!

标签: python-3.x azure-sql-database pyodbc openshift-3 msodbcsql17


【解决方案1】:

unixODBC 正在尝试在当前用户主目录中查找 odbc.ini。它正试图通过looking up the user in /etc/passwd 做到这一点。由于 Openshift 正在使用 /etc/passwd 中不存在的项目特定 UID,因此用户查找将不起作用并且连接将失败。

要解决此问题,请将以下内容添加到 dockerfile

ADD entrypoint.sh .
RUN chmod 766 /etc/passwd
..
..
ENTRYPOINT entrypoint.sh

以及入口点脚本中的以下内容

export $(id)
echo "default:x:$uid:0:user for openshift:/tmp:/bin/bash" >> /etc/passwd
python3.7 app.py

上面会在容器启动时将当前用户插入/etc/passwd。

另一种可能更好的方法可能是使用 nss_wrapper: https://cwrap.org/nss_wrapper.html

【讨论】:

  • 一个很好的例子说明如何在你的 Docker 镜像中使用 nss_wrapper 解决这个问题:github.com/openshift/jenkins/pull/1024/files
  • @filip-reimer 你知道我们如何为 debian 10 做到这一点吗?您提供的解决方案似乎仅适用于 openshift
【解决方案2】:

我在 Windows 上使用 django 时遇到了同样的问题。 将“SQL Server 2017 客户端”升级到最新客户端后解决了我的问题。 使用以下链接下载最新补丁: https://www.microsoft.com/en-us/download/details.aspx?id=56567

【讨论】:

    猜你喜欢
    • 2012-11-17
    • 2018-07-22
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    相关资源
    最近更新 更多