python连接oracle遇到的问题(docker内)
场景1:通过docker-compose.yaml启动一些基础服务,然后执行python逻辑代码文件,python连接oracle数据库时报错:cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file:
场景1:
通过docker-compose.yaml启动一些基础服务,然后执行python逻辑代码文件,python连接oracle数据库时报错:cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file: No such file or directory". See https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html for help
解决:
说是找不到 64 位 Oracle 客户端,问题就出现在Dockerfile文件中,需要安装一个客户端,将下列代码放到Dockerfile中基本就可以解决这个问题了。
COPY ./ /app/
COPY ./instantclient_11_2 /oracle/instantclient_11_2
ENV ORACLE_HOME=/oracle/instantclient_11_2
ENV PATH=$ORACLE_HOME:$PATH
ENV TNS_ADMIN=$ORACLE_HOME/network/admin
ENV LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
ENV NLS_LANGE="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
RUN apt-get update && apt-get install -y libaio1
# RUN pip install cx_Oracle -y
RUN pip install cx_Oracle -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/
RUN set -ex \
&& rm -rf /app/docker/ /app/README.md /app/*.sh /app/env.sh-dist /app/release.ini /app/.gitignore /app/.gitlab-ci.yml \
&& rm -rf /app/deployments /app/.git /app/__pycache__ /app/*/__pycache__ /app/*/*/__pycache__ \
&& rm -rf /app/debug* /app/tests /app/main.py /app/config /app/deployments \
&& rm -rf /app/instantclient_11_2
我当时在解决这个问题时,把这段代码放到了Dockerfile文件中,但问题还是没解决,原因是代码放错位置了。Dockerfile可以进行多阶段部署(可以百度学习一下多阶段部署),刚开始我把那段代码放在开头,代码如下:
FROM hub.dev.laningtech.net/apps/project-face-dbsync:v1.0.2
COPY ./ /app/
COPY ./instantclient_11_2 /oracle/instantclient_11_2
ENV ORACLE_HOME=/oracle/instantclient_11_2
ENV PATH=$ORACLE_HOME:$PATH
ENV TNS_ADMIN=$ORACLE_HOME/network/admin
ENV LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
ENV NLS_LANGE="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
RUN apt-get update && apt-get install -y libaio1
# RUN pip install cx_Oracle -y
RUN pip install cx_Oracle -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/
RUN set -ex \
&& rm -rf /app/docker/ /app/README.md /app/*.sh /app/env.sh-dist /app/release.ini /app/.gitignore /app/.gitlab-ci.yml \
&& rm -rf /app/deployments /app/.git /app/__pycache__ /app/*/__pycache__ /app/*/*/__pycache__ \
&& rm -rf /app/debug* /app/tests /app/main.py /app/config /app/deployments \
&& rm -rf /app/instantclient_11_2
FROM hub.dev.laningtech.net/apps/fastapi:1.1.6 as builder1
COPY ./ /app/
RUN set -ex \
#&& bash /app/build.sh \
&& rm -rf /app/tests/ /app/docker/ /app/README.md /app/*.sh /app/unittest.sh /app/main.py /app/.gitignore /app/.gitlab-ci.yml /app/release.ini \
&& rm -rf /app/docker-compose.yaml /app/init /app/deployments /app/config /app/.git /app/__pycache__ /app/*/__pycache__ \
&& cd / \
&& python -m zipapp app -m "index:main"
可以看到我第一阶段FROM hub.dev.laningtech.net/apps/project-face-dbsync:v1.0.2,我把解决“找不到 64 位 Oracle 客户端”的问题的代码放在那里,但随之后面还有第二阶段FROM hub.dev.laningtech.net/apps/fastapi:1.1.6 as builder1。问题就出现在这,Dockerfile多阶段并不是生成多个镜像,而是按照最后一个FROM的结果生成镜像,那么第二个FROM就会把第一个FROM我编写的一些环境变量和下载的模块进行覆盖,相当于没编写。所以才会导致我明明已经导入客户端了为什么还会报错。
解决办法就是把两个FROM写一起,因为导入客户端并不需要什么基础镜像,所以并不需要FROM镜像,所以把那段代码放在最后就行,代码如下:这样就不会存在覆盖问题了。(总之理解了Dockerfile多阶段部署,就明白了为什么要这么编写)
FROM hub.dev.laningtech.net/apps/fastapi:1.1.6 as builder1
COPY ./ /app/
RUN set -ex \
#&& bash /app/build.sh \
&& rm -rf /app/tests/ /app/docker/ /app/README.md /app/*.sh /app/unittest.sh /app/main.py /app/.gitignore /app/.gitlab-ci.yml /app/release.ini \
&& rm -rf /app/docker-compose.yaml /app/init /app/deployments /app/config /app/.git /app/__pycache__ /app/*/__pycache__ \
&& cd / \
&& python -m zipapp app -m "index:main"
FROM hub.dev.laningtech.net/base_library/goencrypt:v1.1 as builder2
COPY --from=builder1 /app.pyz /
RUN goencrypt -i /app.pyz -o /app.ez
#解决问题的代码
COPY ./ /app/
COPY ./instantclient_11_2 /oracle/instantclient_11_2
ENV ORACLE_HOME=/oracle/instantclient_11_2
ENV PATH=$ORACLE_HOME:$PATH
ENV TNS_ADMIN=$ORACLE_HOME/network/admin
ENV LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
ENV NLS_LANGE="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
RUN apt-get update && apt-get install -y libaio1
# RUN pip install cx_Oracle -y
RUN pip install cx_Oracle -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/
RUN set -ex \
&& rm -rf /app/docker/ /app/README.md /app/*.sh /app/env.sh-dist /app/release.ini /app/.gitignore /app/.gitlab-ci.yml \
&& rm -rf /app/deployments /app/.git /app/__pycache__ /app/*/__pycache__ /app/*/*/__pycache__ \
&& rm -rf /app/debug* /app/tests /app/main.py /app/config /app/deployments \
&& rm -rf /app/instantclient_11_2
场景2:
解决完连接问题后,又遇到了一个新的问题,就是我启动项目后,oracle就像是初始化了一样,我之前在oracle容器内创建的用户全不见了,导致我每启动一次项目,就要先进oracle容器内创建个用户。
解决:
解决办法就是docker数据持久化。
这个问题就要在docker-compose.yaml上解决。需要挂载一个目录,来确保信息同步,挂载目录可以这么理解,以下面volumes举例,./data/oracle是宿主机目录,/u01/app/oracle是虚拟机目录,将宿主机./data/oracle挂载到虚拟机/u01/app/oracle,这样你启动项目然后进入oracle容器内创建一个新用户,新用户的信息就会记录在/u01/app/oracle,同步的也会记录在宿主机./data/oracle,这样当你下次启动项目时,宿主机就会将包含所有信息的./data/oracle挂载到/u01/app/oracle下,这样你上次创建的用户信息也还存在,这就是数据持久化。
oracle_db:
image: registry.cn-hangzhou.aliyuncs.com/qida/oracle-xe-11g
ports:
- "1521:1521"
volumes:
- ./data/oracle:/u01/app/oracle
在当前项目路径下创建一个/data目录,然后docker cp 24aa2ea8ff0f:/u01/app/oracle ./data
24aa2ea8ff0f这个是docker ps -a 显示的oracle的id号,这么做的目的是先将oracle的信息先导出来放到/data目录下,如果不这样做/data就是个空目录,进行挂载的话/u01/app/oracle这个目录下也将会是个空目录,无法记录信息。
挂载完以后,问题就解决了。
场景3:我将本地的oracle打包成镜像,然后另一个机器(192.168.1.19)pull下来,我用我本地去连接19机器的oracle,报连接超时
解决方案:
这个很有可能跟oracle限制ip连接有关系,需修改一个配置文件,文件是/u01/app/oracle/product/11.2.0/xe/network/admin/samples下sqlnet.ora*文件,在文件末尾添加
tcp.validnode_checking = yes
#tcp.invited_nodes=() #允许访问的IP列表,各IP之间用逗号分隔
tcp.excluded_nodes=() #限制访问的IP列表,个IP之间用逗号分隔
注意:
•不能同时使用tcp.invited_nodes和tcp.excluded_nodes
•只能指定具体的IP地址,不能指定IP段
•只能限制TCP协议
•需要重启监听生效
添加完后,lsnrctl stop,lsnrctl start
更多推荐
所有评论(0)