首页 > 解决方案 > 在 Docker 容器中找不到共享库 libpython3.5(但覆盖工作正常)

问题描述

我正在尝试在 Docker 容器中部署一个使用 CNTK 的 Python Web 服务(带有烧瓶)。我使用来自 Microsoft 的 Ubuntu-Base-Image,它应该包含所有必要且正确的程序和库来运行 CNTK。

该脚本在本地工作(在 Windows 上)以及当我运行容器并从 cmd-line 启动 bash 时

docker exec -it <container_id> bash

并从“容器内”启动脚本。

一个重要的补充是 python 脚本使用两个预编译模块,它们是用于 windows 的 *.pyd 文件和用于 Linux 的 *.so 文件。因此,对于 docker 映像,我将前者替换为后者,以便从容器内运行脚本。

当我在 Dockerfile 中使用 CMD 启动脚本时,问题就开始了。图像的创建显示没有问题。但是当我启动容器时

docker run -p 1234:80 app

我收到以下错误:

...
ImportError:libpython3.5m.so.1.0:无法打开共享对象文件:没有这样的文件或目录

图书馆好像不见了。但是(我重复一遍)当我从容器中运行的 bash 中运行脚本时(据我所知,它应该只有容器库),一切正常。我什至可以用

ldd $(which python)

该文件肯定在文件夹中。所以问题是为什么python在运行docker容器时找不到它的依赖。

当我尝试通过在环境变量中明确地给出库的路径时,它甚至变得更奇怪:

ENV LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/root/anaconda3/pkgs/python-3.5.2-0/lib/"

然后图书馆似乎找到了图书馆,但它不被接受为正确的:

ImportError:动态模块未定义初始化函数(initcython_bbox)

“cython_bbox”是要导入的 *.pyd / *.so 文件/库之一的名称。这显然是这类文件类型的典型错误。但我对他们没有任何经验。

我也不能(在我的个人开发中)能够从外部源编译我自己的文件或自己创建 docker 映像。我依赖从 Microsoft 获得的部件。但我愿意接受建议。

在导入基本映像后,我也已经尝试在 Dockerfile 中重新安装库

RUN apt-get install -y libpython3.5

但它引发了与我将路径放入环境变量时相同的错误。

我真的很想知道这里出了什么问题。为什么一切都在“容器内”顺利运行,但在使用 CMD 初始化容器时自动启动却不行?

有关其他信息,我添加了 Dockerfile:

# 使用官方 Python 运行时作为父镜像 FROM microsoft/cntk:2.5.1-cpu-python3.5

# 设置工作

目录到 /app WORKDIR /app

# 将当前目录内容复制到 /app ADD 的容器中。/应用程序

运行 apt-get update && apt-get install -y python-pip 运行 pip install --upgrade pip

# 安装 requirements.txt 中指定的任何需要的包 RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 让这个容器之外的世界可以使用 80 端口 EXPOSE 80

# 当容器启动 CMD 时运行 app.py ["python", "test.py"]

项目的其余部分是一个非常简单的 flask-webapp,当我注释掉实际 CNTK 项目的所有导入时,它运行没有问题。顺便说一下,它是带有 Faster-RCNN 的 CNTK 对象检测,可以在 cntk-git-repository 中找到。

编辑:

我发现了实际问题是什么,但我仍然没有办法解决它。问题是,当我使用“docker exec”启动 bash 时,它会在启动时运行一个脚本,该脚本会使用 python3.5 和所有整洁的库激活 anaconda 环境。但是当 CMD 刚刚启动 python 时,这是由标准的 Bourne shell“sh”完成的,它(正如我尝试过的)与 python2.7 一起运行。

所以我需要一种方法来使用 bash 启动我的容器(包括它的自动启动脚本),或者以另一种方式在启动时激活环境。

我查看了脚本,它基本上检查 bash 是否是当前 shell,设置一些环境变量并激活环境。

if [ -z "$BASH_VERSION" ]; then
  echo Error: only Bash is supported.
elif [ "$(basename "$0" 2> /dev/null)" == "activate-cntk" ]; then
  echo Error: this script is meant to be sourced. Run 'source activate-cntk'
else
  export PATH="/cntk/cntk/bin:$PATH"
  export LD_LIBRARY_PATH="/cntk/cntk/lib:/cntk/cntk/dependencies/lib:$LD_LIBRARY_PATH"
  source "/root/anaconda3/bin/activate" "/root/anaconda3/envs/cntk-py35"

  cat <<MESSAGE

************************************************************
CNTK is activated.

Please checkout tutorials and examples here:
  /cntk/Tutorials
  /cntk/Examples

To deactivate the environment run

  source /root/anaconda3/bin/deactivate

************************************************************
MESSAGE
fi

我尝试了很多东西,比如将 sh 链接到 bash

RUN ln -fs /bin/bash /bin/sh

或使用 bash 作为 ENTRYPOINT。

标签: pythonlinuxdockeranacondacntk

解决方案


我找到了一个目前有效的解决方法。

首先,我在我的环境中手动将 python 链接到 python3:

RUN ln -fs /root/anaconda3/envs/cntk-py35/bin/python3.5 /usr/bin/python

然后我将环境库添加到 Library-Path:

ENV LD_LIBRARY_PATH "/cntk/cntk/lib:/cntk/cntk/dependencies/lib:$LD_LIBRARY_PATH"

并确保我将所有重要文件夹添加到 PATH:

ENV PATH "/cntk/cntk/bin:$PATH"
ENV PATH "/root/anaconda3/envs/cntk-py35/bin:$PATH"

然后我必须再次安装我的 python 包:

RUN pip install flask

最后可以开始我的脚本:

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

推荐阅读