场景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

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐