Ошибка драйвера SQLAllocHandle для SQL_HANDLE_HENV (0) (SQLDriverConnect) при подключении к базе данных SQL Azure из Python, работающего в OpenShift - PullRequest
1 голос
/ 02 апреля 2019

Только при попытке подключиться к моей базе данных Azure из Python 3.7, запущенного в контейнер OpenShift (ОТ rhel7: последний) Я вижу следующую ошибку:

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

Я попробовал точно такой же код в Docker на моем MAC, Windows и RHEL7 Virtualbox с базовым контейнером RHEL7 - он всегда работает! Проблема только в моем контейнере, работающем в OpenShift! Я проверил, что могу подключиться к серверу БД Azure в 1433 году из Openshift.

Я также включил журналы ODBC, но больше информации, чем вышеупомянутой ошибки, нет.

Что еще я должен проверить?

Вот как я настроил драйвер MSODBC в моем 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

А вот код, который выдает ошибку:

внутри модуля. База данных:

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. Спасибо за взгляд!

1 Ответ

1 голос
/ 30 апреля 2019

unixODBC пытается найти файл odbc.ini в домашнем каталоге текущего пользователя.Он пытается сделать это путем поиска пользователя в / etc / passwd .Так как Openshift использует специфичный для проекта UID, который не существует в / etc / passwd, поиск пользователя не будет работать, и соединение не будет установлено.

Чтобы решить эту проблему, добавьте следующее в файл 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

...