python-oracledb模块无法在docker容器中使用instantclient

brccelvz  于 2023-11-17  发布在  Oracle
关注(0)|答案(3)|浏览(160)

我试图构建一个Docker镜像来在运行时访问Oracle数据库,我收到以下错误消息:DPI-1047: Cannot locate a 64-bit Oracle Client library: "/oracle/instantclient/libclntsh.so: cannot open shared object file: No such file or directory".
在容器内部,实际上在/oracle/instantclient/libclntsh.so处有一个符号链接
Dockerfile:

FROM python:3.12-slim

RUN apt-get update && \
    apt-get install -y wget unzip libaio1

ARG ORACLE_HOME=/oracle
ARG ORACLE_CLIENT_HOME=${ORACLE_HOME}/instantclient

# Download and install Oracle instantclient
RUN mkdir /tmp/oracle && \
    wget https://download.oracle.com/otn_software/linux/instantclient/1920000/instantclient-basic-linux.x64-19.20.0.0.0dbru.zip -P /tmp/oracle && \
    unzip /tmp/oracle/instantclient-basic-* -d /tmp/oracle && \
    mkdir ${ORACLE_HOME} && \
    mv /tmp/oracle/instantclient_* ${ORACLE_CLIENT_HOME}

ENV LD_LIBRARY_PATH="${ORACLE_CLIENT_HOME}"

RUN pip install --upgrade pip && \
    pip install pipenv
ENV PIPENV_VENV_IN_PROJECT=1

WORKDIR /app

ADD main.py Pipfile Pipfile.lock ./

RUN pipenv sync

ENTRYPOINT ["./.venv/bin/python", "main.py"]
CMD [""]

字符串
main.py:

import os

import oracledb

def print_db_version(db_config):
    params = oracledb.ConnectParams(host=db_config['host'], port=db_config['port'], service_name=db_config['name'])
    with oracledb.connect(user=db_config['username'], password=db_config['password'], params=params) as conn:
        print(f'Database version: {conn.version}')
        conn.close()

if __name__ == '__main__':
    # Both calls below fail...
    # oracledb.init_oracle_client()
    oracledb.init_oracle_client(os.environ['LD_LIBRARY_PATH'])

    db_config = {
        'host': os.environ['DB_HOST'],
        'port': os.environ['DB_PORT'],
        'name': os.environ['DB_NAME'],
        'username': os.environ['DB_USERNAME'],
        'password': os.environ['DB_PASSWORD'],
    }

    print_db_version(db_config)


Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
oracledb = "1.4.2"


命令行(最后一个允许浏览容器):

docker build -t my-version .
docker run my-version
docker run -it --entrypoint "" my-version bash


我不知道为什么这个错误弹出,而库实际上是安装在我的容器.任何想法?

编辑

我尝试了Anthony Tuininga的建议,得到了以下输出:

ODPI [00001] 2023-10-21 19:13:32.206: ODPI-C 5.0.1
ODPI [00001] 2023-10-21 19:13:32.206: debugging messages initialized at level 64
ODPI [00001] 2023-10-21 19:13:32.206: Context Parameters:
ODPI [00001] 2023-10-21 19:13:32.206:     Oracle Client Lib Dir: /oracle/instantclient
ODPI [00001] 2023-10-21 19:13:32.206: Environment Variables:
ODPI [00001] 2023-10-21 19:13:32.206:     LD_LIBRARY_PATH => "/oracle/instantclient"
ODPI [00001] 2023-10-21 19:13:32.206: load in parameter directory
ODPI [00001] 2023-10-21 19:13:32.206: load in dir /oracle/instantclient
ODPI [00001] 2023-10-21 19:13:32.206: load with name /oracle/instantclient/libclntsh.so
ODPI [00001] 2023-10-21 19:13:32.206: load by OS failure: /oracle/instantclient/libclntsh.so: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.206: load with name /oracle/instantclient/libclntsh.so.19.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.19.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.207: load with name /oracle/instantclient/libclntsh.so.18.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.18.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.207: load with name /oracle/instantclient/libclntsh.so.12.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.12.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.207: load with name /oracle/instantclient/libclntsh.so.11.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.11.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.207: load with name /oracle/instantclient/libclntsh.so.20.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.20.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-21 19:13:32.207: load with name /oracle/instantclient/libclntsh.so.21.1
ODPI [00001] 2023-10-21 19:13:32.207: load by OS failure: /oracle/instantclient/libclntsh.so.21.1: cannot open shared object file: No such file or directory
Traceback (most recent call last):
  File "/app/main.py", line 18, in <module>
['libocci.so.19.1', 'libnnz19.so', 'adrci', 'libipc1.so', 'xstreams.jar', 'libclntsh.so.11.1', 'libclntsh.so.18.1', 'genezi', 'libocci.so.12.1', 'network', 'libocci.so.10.1', 'libocci.so', 'libociei.so', 'libclntsh.so', 'libclntsh.so.12.1', 'libocci.so.18.1', 'libclntsh.so.19.1', 'ucp.jar', 'BASIC_LICENSE', 'libocijdbc19.so', 'ojdbc8.jar', 'BASIC_README', 'libmql1.so', 'liboramysql19.so', 'libocci.so.11.1', 'libclntshcore.so.19.1', 'libclntsh.so.10.1', 'uidrvci']
    oracledb.init_oracle_client(os.environ['LD_LIBRARY_PATH'])
  File "src/oracledb/impl/thick/utils.pyx", line 476, in oracledb.thick_impl.init_oracle_client
  File "src/oracledb/impl/thick/utils.pyx", line 500, in oracledb.thick_impl.init_oracle_client
  File "src/oracledb/impl/thick/utils.pyx", line 421, in oracledb.thick_impl._raise_from_info
oracledb.exceptions.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "/oracle/instantclient/libclntsh.so: cannot open shared object file: No such file or directory". See https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html for help


它表明:

  • LD_LIBRARY_PATH正确设置为/oracle/instantclient
  • 即时客户端实际上在此目录中搜索
  • /oracle/instantclient实际上包含libclntsh.so文件(它实际上是指向libclntsh.so.19.1的符号链接

我觉得很奇怪...
我在这里提供了源代码:https://github.com/galak75/python-oracle-img

编辑2

我尝试使用裸调用init_oracle_client(),然后它看起来像LD_LIBRARY_PATH变量没有使用:即时客户端在我的python virtualenv中搜索:

ODPI [00001] 2023-10-22 14:48:34.681: ODPI-C 5.0.1
ODPI [00001] 2023-10-22 14:48:34.681: debugging messages initialized at level 64
ODPI [00001] 2023-10-22 14:48:34.681: Context Parameters:
ODPI [00001] 2023-10-22 14:48:34.681: Environment Variables:
ODPI [00001] 2023-10-22 14:48:34.681:     LD_LIBRARY_PATH => "/oracle/instantclient"
ODPI [00001] 2023-10-22 14:48:34.681: check module directory
ODPI [00001] 2023-10-22 14:48:34.681: module name is /app/.venv/lib/python3.12/site-packages/oracledb/thick_impl.cpython-312-aarch64-linux-gnu.so
ODPI [00001] 2023-10-22 14:48:34.681: load in dir /app/.venv/lib/python3.12/site-packages/oracledb
ODPI [00001] 2023-10-22 14:48:34.681: load with name /app/.venv/lib/python3.12/site-packages/oracledb/libclntsh.so
ODPI [00001] 2023-10-22 14:48:34.681: load by OS failure: /app/.venv/lib/python3.12/site-packages/oracledb/libclntsh.so: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.681: load with OS search heuristics
ODPI [00001] 2023-10-22 14:48:34.681: load with name libclntsh.so
ODPI [00001] 2023-10-22 14:48:34.682: load by OS failure: libaio.so.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.682: load with name libclntsh.so.19.1
ODPI [00001] 2023-10-22 14:48:34.682: load by OS failure: libaio.so.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.682: load with name libclntsh.so.18.1
ODPI [00001] 2023-10-22 14:48:34.682: load by OS failure: libaio.so.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.682: load with name libclntsh.so.12.1
ODPI [00001] 2023-10-22 14:48:34.683: load by OS failure: libaio.so.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.683: load with name libclntsh.so.11.1
ODPI [00001] 2023-10-22 14:48:34.683: load by OS failure: libaio.so.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.683: load with name libclntsh.so.20.1
ODPI [00001] 2023-10-22 14:48:34.683: load by OS failure: libclntsh.so.20.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.683: load with name libclntsh.so.21.1
ODPI [00001] 2023-10-22 14:48:34.683: load by OS failure: libclntsh.so.21.1: cannot open shared object file: No such file or directory
ODPI [00001] 2023-10-22 14:48:34.683: check ORACLE_HOME
Traceback (most recent call last):
  File "/app/main.py", line 19, in <module>
    oracledb.init_oracle_client()
  File "src/oracledb/impl/thick/utils.pyx", line 476, in oracledb.thick_impl.init_oracle_client
LD_LIBRARY_PATH = /oracle/instantclient
['libocci.so.19.1', 'libnnz19.so', 'adrci', 'xstreams.jar', 'libclntsh.so.11.1', 'libclntsh.so.18.1', 'genezi', 'libocci.so.12.1', 'network', 'libocci.so.10.1', 'libocci.so', 'libociei.so', 'libclntsh.so', 'libclntsh.so.12.1', 'libocci.so.18.1', 'libclntsh.so.19.1', 'ucp.jar', 'BASIC_LICENSE', 'libocijdbc19.so', 'ojdbc8.jar', 'BASIC_README', 'liboramysql19.so', 'libocci.so.11.1', 'libclntshcore.so.19.1', 'libclntsh.so.10.1', 'uidrvci']
  File "src/oracledb/impl/thick/utils.pyx", line 500, in oracledb.thick_impl.init_oracle_client
  File "src/oracledb/impl/thick/utils.pyx", line 421, in oracledb.thick_impl._raise_from_info
oracledb.exceptions.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libaio.so.1: cannot open shared object file: No such file or directory". See https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html for help

编辑3

我在代码中添加了libaio1软件包安装,因为正如Christopher's answer所指出的,这显然是下一个问题(在目标OS平台问题之后

5cg8jx4n

5cg8jx4n1#

如果你不需要厚模式,你可以通过简单地删除对init_oracle_client()的调用来完全避免错误。
如果您确实需要它,因为在精简模式下的限制,在运行脚本之前将环境变量DPI_DEBUG_LEVEL设置为值64。这可能有助于您诊断问题。如果不是,请将输出包含在您的问题中,我会查看。
[更新:通过提供的输出,很明显,aio库丢失了,Chris在他的回答中也提出了这一点。添加该库,您的问题应该消失!]
使用os.listdir(os.environ["LD_LIBRARY_PATH"])列出在目录中找到的文件也可能很有帮助。
注意,在Linux上不能指定库目录,因此必须使用对init_oracle_client()的裸调用。

huus2vyu

huus2vyu2#

有关参考,请参见Docker for Oracle Database Applications in Node.js and Python
当我尝试你的Dockerfile时,我得到了一个相当明确的消息,libaio包没有安装。
下一个问题(除了丢失的锁文件!)是main.py正在为连接使用上下文管理器,但也显式关闭了连接。
这个Dockerfile适合我:

FROM python:3.12-slim

RUN apt-get update && \
    apt-get install -y wget unzip libaio1

ARG ORACLE_CLIENT_HOME=/opt/oracle/instantclient

WORKDIR /opt/oracle

# Download and install Oracle instantclient
RUN mkdir /tmp/oracle && \
    wget https://download.oracle.com/otn_software/linux/instantclient/1921000/instantclient-basic-linux.x64-19.21.0.0.0dbru.zip -P /tmp/oracle && \
    unzip /tmp/oracle/instantclient-basic-* -d /tmp/oracle && \
    mv /tmp/oracle/instantclient_* ${ORACLE_CLIENT_HOME} && \
    cd ${ORACLE_CLIENT_HOME} && rm -f *jdbc* *occi* *mysql* *jar uidrvci genezi adrci && \
    echo ${ORACLE_CLIENT_HOME} > /etc/ld.so.conf.d/oracle-instantclient.conf && \
    ldconfig

RUN pip install --upgrade pip && pip install oracledb

WORKDIR /app
ADD main.py ./

CMD ["python", "main.py"]

字符串
注意,我删除了重载使用的ORACLE_HOME,因为这在Oracle中有特定的含义。我也直接使用了python,因为容器可能只运行一个应用程序环境。
我也更喜欢ldconfig而不是LD_LIBRARY_PATH,因为后者容易出现各种问题。
main.py是:

import os

import oracledb

def print_db_version(db_config):
    params = oracledb.ConnectParams(host=db_config['host'], port=db_config['port'], service_name=db_config['name'])
    with oracledb.connect(user=db_config['username'], password=db_config['password'], params=params) as conn:
        print(f'Database version: {conn.version}')

if __name__ == '__main__':
    oracledb.init_oracle_client()

    db_config = {
        'host': 'whatever',
        'port': 1521,
        'name': 'orclpdb1',
        'username': 'cj',
        'password': 'cj',
    }

    print_db_version(db_config)


遵循Anthony的建议,不要在Linux上将lib_dir传递给init_oracle_client()
输出类似于:

$ docker run my-version
Database version: 21.3.0.0.0


最后,您应该重新访问在容器中运行的用户。

taor4pac

taor4pac3#

我终于想通了,经过这么多个小时的挣扎!
我正在一台带有M1芯片(arm64架构)的MacBook上运行,同时我正在为amd64架构安装一个instantclient发行版。
然后我通过强制目标Docker平台为amd64来实现它:

docker build -t my-version . --platform amd64
docker run --env-file .local/env my-version

字符串

注意:我还必须修复一些问题,例如安装libaio1 debian包,并删除conn.close() python语句
**编辑:**另一种解决方案是根据目标操作系统平台下载正确的即时客户端包:

RUN mkdir /tmp/oracle && \
    if [ "`uname -m`" = "aarch64" ] || [ "`uname -m`" = "arm64" ]; \
      then echo "ARM64 architecture detected" && wget https://download.oracle.com/otn_software/linux/instantclient/1919000/instantclient-basic-linux.arm64-19.19.0.0.0dbru.zip -P /tmp/oracle; \
    elif [ "`uname -m`" = "amd64" ] || [ "`uname -m`" = "x86_64" ] ; \
      then echo "AMD64 architecture detected" && wget https://download.oracle.com/otn_software/linux/instantclient/1920000/instantclient-basic-linux.x64-19.20.0.0.0dbru.zip -P /tmp/oracle; \
    else  \
      echo "target platform was not recognized : `uname -a`" && exit 1; \
    fi; \
    unzip /tmp/oracle/instantclient-basic-* -d /tmp/oracle && \
    mkdir -p ${ORACLE_CLIENT_HOME} && \
    mv /tmp/oracle/instantclient_*/* ${ORACLE_CLIENT_HOME}

相关问题