Python C++ 的包装器。so 仅在将代码复制到 docker 图像时可用,而不是在按卷安装时可用?
Python wrapper for C++ .so is only useable when COPY'ing code into docker image and not when mounted by volume?
我已经有点成功地 docker 化了一个 software repository (KPConv) 我计划使用并扩展以下 Dockerfile
FROM tensorflow/tensorflow:1.12.0-devel-gpu-py3
# Install other required python stuff
RUN apt-get update && apt install -y --fix-missing --no-install-recommends\
python3-setuptools python3-pip python3-tk
RUN pip install --upgrade pip
RUN pip3 install numpy scikit-learn psutil matplotlib pyqt5 laspy
# Compile the custom operations and CPP wrappers
# For some reason this must be done within container, cannot access libcuda.so during docker build
# Ref:
#COPY . /kpconv
#WORKDIR /kpconv/tf_custom_ops
#RUN sh compile_op.sh
#WORKDIR /kpconv/cpp_wrappers
#RUN sh compile_wrappers.sh
# Set the working directory to kpconv
WORKDIR /kpconv
# Set root user password so we can su/sudo later if need be
RUN echo "root:pass" | chpasswd
# Create a user and group akin to the host within the container
ARG USER_ID
ARG GROUP_ID
RUN addgroup --gid $GROUP_ID user
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user
USER user
#Build
#sudo docker build -t kpconv-test \
# --build-arg USER_ID=$(id -u) \
# --build-arg GROUP_ID=$(id -g) \
# .
在这个 Dockerfile 的末尾,我遵循了 post found here,它描述了一种正确设置生成文件权限的方法 by/within 容器,以便主机 machine/user 无需更改文件权限即可访问它们。
此外,此软件存储库使用 custom tensorflow operations in C++ (KPConv/tf_custom_ops) along with Python wrappers for custom C++ code (KPConv/cpp_wrappers)。 KPConv 的作者 Thomas Hugues 提供了一个 bash 脚本,它编译每个文件以生成各种 .so
文件。
如果我 COPY
在构建过程中将存储库添加到映像中 (COPY . /kpconv
),启动容器,调用两个编译 bash 脚本和 运行 然后代码 Python 正确加载 C++ 包装器(生成的 .so grid_subsampling.cpython-35m-x86_64-linux-gnu.so
)并开始 运行 将软件作为 expected/intended。
$ sudo docker run -it \
> -v /<myhostpath>/data_sets:/data \
> -v /<myhostpath>/_output:/output \
> --runtime=nvidia kpconv-test /bin/bash
user@eec8553dcb5d:/kpconv$ cd tf_custom_ops
user@eec8553dcb5d:/kpconv/tf_custom_ops$ sh compile_op.sh
user@eec8553dcb5d:/kpconv/tf_custom_ops$ cd ..
user@eec8553dcb5d:/kpconv$ cd cpp_wrappers/
user@eec8553dcb5d:/kpconv/cpp_wrappers$ sh compile_wrappers.sh
running build_ext
building 'grid_subsampling' extension
<Redacted for brevity>
user@eec8553dcb5d:/kpconv/cpp_wrappers$ cd ..
user@eec8553dcb5d:/kpconv$ python training_ModelNet40.py
Dataset Preparation
*******************
Loading training points
1620.2 MB loaded in 0.6s
Loading test points
411.6 MB loaded in 0.2s
<Redacted for brevity>
这很好用,让我 运行 KPConv 软件。
还要注意稍后 .so
文件具有散列
user@eec8553dcb5d:/kpconv/cpp_wrappers/cpp_subsampling$ sha1sum grid_subsampling.cpython-35m-x86_64-linux-gnu.so
a17eef453f6d2370a15bc2a0e6714c978390c5c3 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
也有权限
user@eec8553dcb5d:/kpconv/cpp_wrappers/cpp_subsampling$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 user user 561056 Mar 14 02:16 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
虽然它产生了一个困难的工作流程,以便快速编辑和软件用于我的目的,并快速 运行将其安装在容器中。对代码的每次更改都需要重新构建图像。因此,我宁愿 mount/volume 在 运行 时间从主机到容器的 KPConv 代码,然后编辑在容器内“实时”,因为它是 运行ning.
这样做并使用post(没有COPY . /kpconv
)顶部的Dockerfile来编译镜像,执行相同的编译步骤,运行代码
$ sudo docker run -it \
> -v /<myhostpath>/data_sets:/data \
> -v /<myhostpath>/KPConv_Tensorflow:/kpconv \
> -v /<myhostpath>/_output:/output \
> --runtime=nvidia kpconv-test /bin/bash
user@a82e2c1af21a:/kpconv$ cd tf_custom_ops/
user@a82e2c1af21a:/kpconv/tf_custom_ops$ sh compile_op.sh
user@a82e2c1af21a:/kpconv/tf_custom_ops$ cd ..
user@a82e2c1af21a:/kpconv$ cd cpp_wrappers/
user@a82e2c1af21a:/kpconv/cpp_wrappers$ sh compile_wrappers.sh
running build_ext
building 'grid_subsampling' extension
<Redacted for brevity>
user@a82e2c1af21a:/kpconv/cpp_wrappers$ cd ..
user@a82e2c1af21a:/kpconv$ python training_ModelNet40.py
我收到以下 Python ImportError
user@a82e2c1af21a:/kpconv$ python training_ModelNet40.py
Traceback (most recent call last):
File "training_ModelNet40.py", line 36, in <module>
from datasets.ModelNet40 import ModelNet40Dataset
File "/kpconv/datasets/ModelNet40.py", line 40, in <module>
from datasets.common import Dataset
File "/kpconv/datasets/common.py", line 29, in <module>
import cpp_wrappers.cpp_subsampling.grid_subsampling as cpp_subsampling
ImportError: /kpconv/cpp_wrappers/cpp_subsampling/grid_subsampling.cpython-35m-x86_64-linux-gnu.so: failed to map segment from shared object
为什么 C++ 的 Python 包装器仅在将代码复制到 docker 图像时可用,而不是按卷安装时可用?
这个 .so
文件与第一个描述的情况具有相同的散列和权限
user@a82e2c1af21a:/kpconv/cpp_wrappers/cpp_subsampling$ sha1sum grid_subsampling.cpython-35m-x86_64-linux-gnu.so
a17eef453f6d2370a15bc2a0e6714c978390c5c3 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
user@a82e2c1af21a:/kpconv/cpp_wrappers/cpp_subsampling$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 user user 561056 Mar 14 02:19 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
在我的主机上,该文件具有以下权限(它在主机上,因为 /kpconv
作为卷安装)(出于某种原因,容器也在未来,请检查时间戳)
$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 <myusername> <myusername> 561056 Mar 13 21:19 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
在对错误消息进行一些研究之后,似乎每个结果都是针对特定情况的。尽管大多数人似乎都提到错误是某种 permissions issue.
的结果
我认为这个 Unix&Linux Stack answer 提供了实际问题的答案。但是我在大学实习时使用 C++ 的日子有点太远了,不一定了解如何使用它来解决这个问题。但我认为问题在于容器和主机之间以及每个用户之间的权限(即容器上的 root,容器上的 user
(Dockerfile),主机上的 root,以及 <myusername>
在主机上)。
我还尝试过先使用在 Dockerfile 中创建的 root 密码提升容器内的权限,然后编译代码,然后 运行 安装软件。但这会导致同样的问题。我也曾尝试在容器中将代码编译为 user
,但是 运行 以 root 身份将软件编译,同样的问题。
因此,我发现并提供的另一条线索是,.so
在“仅在”容器内编译时(没有 --volume
)和在容器内编译时似乎有些不同--volume
(这就是我尝试比较文件哈希值的原因)。所以也许它的权限不是那么多,而是内核如何将 .so
加载到容器中,或者它在 --volume
中的位置如何影响加载过程?
编辑: 至于 SSCCE,您应该能够将链接的存储库克隆到您的计算机并使用相同的 Dockerfile。您不需要指定 /data
或 /output
卷或以任何方式更改代码(它会尝试在加载数据之前加载 .so
(这只会出错并结束执行) )
如果您没有 GPU 或不想 install nvidia-runtime
you should be able to alter the Dockerfile base image to tensorflow:1.12.0-devel-py3
和 运行 CPU 上的代码。
您的问题是由尝试动态加载库的链接器造成的。这可能有几个根本原因:
- 权限。用户应该有加载库的权限,因此在 docker 中挂载文件系统时,主机中的所有者 ID 和组 ID 不必与容器中的相同 ID,尽管它们可能是相同的名称.
- 错误的二进制格式。主机 OS 正在以错误的格式编译二进制文件。如果您 运行 在(通过示例)macOS 上编译并在 linux 容器中使用它,就会发生这种情况。
- 安装错误。例如,使用
noexec
安装也会阻止加载库。
- 两种环境的库不同。由于库编译环境的不同,可能会漏掉一些库,所以使用
ldd grid_subsampling.cpython-35m-x86_64-linux-gnu.so
和ldd -r -d -v grid_subsampling.cpython-35m-x86_64-linux-gnu.so
检查所有链接的库。
我已经有点成功地 docker 化了一个 software repository (KPConv) 我计划使用并扩展以下 Dockerfile
FROM tensorflow/tensorflow:1.12.0-devel-gpu-py3
# Install other required python stuff
RUN apt-get update && apt install -y --fix-missing --no-install-recommends\
python3-setuptools python3-pip python3-tk
RUN pip install --upgrade pip
RUN pip3 install numpy scikit-learn psutil matplotlib pyqt5 laspy
# Compile the custom operations and CPP wrappers
# For some reason this must be done within container, cannot access libcuda.so during docker build
# Ref:
#COPY . /kpconv
#WORKDIR /kpconv/tf_custom_ops
#RUN sh compile_op.sh
#WORKDIR /kpconv/cpp_wrappers
#RUN sh compile_wrappers.sh
# Set the working directory to kpconv
WORKDIR /kpconv
# Set root user password so we can su/sudo later if need be
RUN echo "root:pass" | chpasswd
# Create a user and group akin to the host within the container
ARG USER_ID
ARG GROUP_ID
RUN addgroup --gid $GROUP_ID user
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user
USER user
#Build
#sudo docker build -t kpconv-test \
# --build-arg USER_ID=$(id -u) \
# --build-arg GROUP_ID=$(id -g) \
# .
在这个 Dockerfile 的末尾,我遵循了 post found here,它描述了一种正确设置生成文件权限的方法 by/within 容器,以便主机 machine/user 无需更改文件权限即可访问它们。
此外,此软件存储库使用 custom tensorflow operations in C++ (KPConv/tf_custom_ops) along with Python wrappers for custom C++ code (KPConv/cpp_wrappers)。 KPConv 的作者 Thomas Hugues 提供了一个 bash 脚本,它编译每个文件以生成各种 .so
文件。
如果我 COPY
在构建过程中将存储库添加到映像中 (COPY . /kpconv
),启动容器,调用两个编译 bash 脚本和 运行 然后代码 Python 正确加载 C++ 包装器(生成的 .so grid_subsampling.cpython-35m-x86_64-linux-gnu.so
)并开始 运行 将软件作为 expected/intended。
$ sudo docker run -it \
> -v /<myhostpath>/data_sets:/data \
> -v /<myhostpath>/_output:/output \
> --runtime=nvidia kpconv-test /bin/bash
user@eec8553dcb5d:/kpconv$ cd tf_custom_ops
user@eec8553dcb5d:/kpconv/tf_custom_ops$ sh compile_op.sh
user@eec8553dcb5d:/kpconv/tf_custom_ops$ cd ..
user@eec8553dcb5d:/kpconv$ cd cpp_wrappers/
user@eec8553dcb5d:/kpconv/cpp_wrappers$ sh compile_wrappers.sh
running build_ext
building 'grid_subsampling' extension
<Redacted for brevity>
user@eec8553dcb5d:/kpconv/cpp_wrappers$ cd ..
user@eec8553dcb5d:/kpconv$ python training_ModelNet40.py
Dataset Preparation
*******************
Loading training points
1620.2 MB loaded in 0.6s
Loading test points
411.6 MB loaded in 0.2s
<Redacted for brevity>
这很好用,让我 运行 KPConv 软件。
还要注意稍后 .so
文件具有散列
user@eec8553dcb5d:/kpconv/cpp_wrappers/cpp_subsampling$ sha1sum grid_subsampling.cpython-35m-x86_64-linux-gnu.so
a17eef453f6d2370a15bc2a0e6714c978390c5c3 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
也有权限
user@eec8553dcb5d:/kpconv/cpp_wrappers/cpp_subsampling$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 user user 561056 Mar 14 02:16 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
虽然它产生了一个困难的工作流程,以便快速编辑和软件用于我的目的,并快速 运行将其安装在容器中。对代码的每次更改都需要重新构建图像。因此,我宁愿 mount/volume 在 运行 时间从主机到容器的 KPConv 代码,然后编辑在容器内“实时”,因为它是 运行ning.
这样做并使用post(没有COPY . /kpconv
)顶部的Dockerfile来编译镜像,执行相同的编译步骤,运行代码
$ sudo docker run -it \
> -v /<myhostpath>/data_sets:/data \
> -v /<myhostpath>/KPConv_Tensorflow:/kpconv \
> -v /<myhostpath>/_output:/output \
> --runtime=nvidia kpconv-test /bin/bash
user@a82e2c1af21a:/kpconv$ cd tf_custom_ops/
user@a82e2c1af21a:/kpconv/tf_custom_ops$ sh compile_op.sh
user@a82e2c1af21a:/kpconv/tf_custom_ops$ cd ..
user@a82e2c1af21a:/kpconv$ cd cpp_wrappers/
user@a82e2c1af21a:/kpconv/cpp_wrappers$ sh compile_wrappers.sh
running build_ext
building 'grid_subsampling' extension
<Redacted for brevity>
user@a82e2c1af21a:/kpconv/cpp_wrappers$ cd ..
user@a82e2c1af21a:/kpconv$ python training_ModelNet40.py
我收到以下 Python ImportError
user@a82e2c1af21a:/kpconv$ python training_ModelNet40.py
Traceback (most recent call last):
File "training_ModelNet40.py", line 36, in <module>
from datasets.ModelNet40 import ModelNet40Dataset
File "/kpconv/datasets/ModelNet40.py", line 40, in <module>
from datasets.common import Dataset
File "/kpconv/datasets/common.py", line 29, in <module>
import cpp_wrappers.cpp_subsampling.grid_subsampling as cpp_subsampling
ImportError: /kpconv/cpp_wrappers/cpp_subsampling/grid_subsampling.cpython-35m-x86_64-linux-gnu.so: failed to map segment from shared object
为什么 C++ 的 Python 包装器仅在将代码复制到 docker 图像时可用,而不是按卷安装时可用?
这个 .so
文件与第一个描述的情况具有相同的散列和权限
user@a82e2c1af21a:/kpconv/cpp_wrappers/cpp_subsampling$ sha1sum grid_subsampling.cpython-35m-x86_64-linux-gnu.so
a17eef453f6d2370a15bc2a0e6714c978390c5c3 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
user@a82e2c1af21a:/kpconv/cpp_wrappers/cpp_subsampling$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 user user 561056 Mar 14 02:19 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
在我的主机上,该文件具有以下权限(它在主机上,因为 /kpconv
作为卷安装)(出于某种原因,容器也在未来,请检查时间戳)
$ ls -al grid_subsampling.cpython-35m-x86_64-linux-gnu.so
-rwxr-xr-x 1 <myusername> <myusername> 561056 Mar 13 21:19 grid_subsampling.cpython-35m-x86_64-linux-gnu.so
在对错误消息进行一些研究之后,似乎每个结果都是针对特定情况的。尽管大多数人似乎都提到错误是某种 permissions issue.
的结果我认为这个 Unix&Linux Stack answer 提供了实际问题的答案。但是我在大学实习时使用 C++ 的日子有点太远了,不一定了解如何使用它来解决这个问题。但我认为问题在于容器和主机之间以及每个用户之间的权限(即容器上的 root,容器上的 user
(Dockerfile),主机上的 root,以及 <myusername>
在主机上)。
我还尝试过先使用在 Dockerfile 中创建的 root 密码提升容器内的权限,然后编译代码,然后 运行 安装软件。但这会导致同样的问题。我也曾尝试在容器中将代码编译为 user
,但是 运行 以 root 身份将软件编译,同样的问题。
因此,我发现并提供的另一条线索是,.so
在“仅在”容器内编译时(没有 --volume
)和在容器内编译时似乎有些不同--volume
(这就是我尝试比较文件哈希值的原因)。所以也许它的权限不是那么多,而是内核如何将 .so
加载到容器中,或者它在 --volume
中的位置如何影响加载过程?
编辑: 至于 SSCCE,您应该能够将链接的存储库克隆到您的计算机并使用相同的 Dockerfile。您不需要指定 /data
或 /output
卷或以任何方式更改代码(它会尝试在加载数据之前加载 .so
(这只会出错并结束执行) )
如果您没有 GPU 或不想 install nvidia-runtime
you should be able to alter the Dockerfile base image to tensorflow:1.12.0-devel-py3
和 运行 CPU 上的代码。
您的问题是由尝试动态加载库的链接器造成的。这可能有几个根本原因:
- 权限。用户应该有加载库的权限,因此在 docker 中挂载文件系统时,主机中的所有者 ID 和组 ID 不必与容器中的相同 ID,尽管它们可能是相同的名称.
- 错误的二进制格式。主机 OS 正在以错误的格式编译二进制文件。如果您 运行 在(通过示例)macOS 上编译并在 linux 容器中使用它,就会发生这种情况。
- 安装错误。例如,使用
noexec
安装也会阻止加载库。 - 两种环境的库不同。由于库编译环境的不同,可能会漏掉一些库,所以使用
ldd grid_subsampling.cpython-35m-x86_64-linux-gnu.so
和ldd -r -d -v grid_subsampling.cpython-35m-x86_64-linux-gnu.so
检查所有链接的库。