6

Only when trying to connect to my Azure DB from Python 3.7 running in a OpenShift container (FROM rhel7:latest) I see the following error:

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

I tried the exact same code in Docker on my MAC, Windows and a RHEL7 Virtualbox running the RHEL7 base container - it always works! The problem is only in my container running in OpenShift! I checked that I can telnet to my Azure DB server in 1433 from Openshift.

I enabled the ODBC logs as well but there is no more information than the above error.

What else should I check?

Here is how I set up the MSODBC driver in my Dockerfile:

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

And here is the code that throws the error:

inside 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)

Inside my flask app (the error gets thrown in the call to '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"

As I mentioned in the beginning, the same Dockerfile gives me a working Container in Docker either locally on Mac or Windows or inside a RHEL7 VM. Thanks for having a look!

4

2 回答 2

8

unixODBC 正在尝试在当前用户主目录中查找 odbc.ini。它试图通过在 /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

于 2019-04-30T06:50:49.617 回答
0

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

于 2019-10-31T10:25:25.690 回答