只有在尝试从运行在OpenShift容器中的Python 3.7连接到我的Azure DB时(FROM 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上尝试了完全相同的Docker代码 - 它始终有效!问题出在我在OpenShift中运行的容器中!我检查过我可以在1433年从Openshift telnet到我的Azure数据库服务器。
我也启用了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内部。谢谢你看看!
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