在 docker 容器内运行的 Python 程序依赖于“uname -r”

Posted

技术标签:

【中文标题】在 docker 容器内运行的 Python 程序依赖于“uname -r”【英文标题】:Python program running inside docker container relies upon 'uname -r' 【发布时间】:2018-05-26 12:51:58 【问题描述】:

我有一个 Python 程序,旨在仅在某些 Linux 发行版(即 CentOS、Ubuntu 等)中运行。我想让它在 CentOS7 容器中运行,但它失败了,因为以下返回 '4.9.49-moby':

import platform
platform.release()

该程序期望找到一个 linux 内核版本,即“3.10.0-327.el7.x86_64”。

假设我无法修改程序的源代码。

我可以做些什么来解决这个问题?

我尝试围绕“uname -r”编写一个包装脚本来返回我想要的。但这无济于事,因为显然 Python 是直接从内核中获取的。

【问题讨论】:

为什么不使用检测发行版然后运行脚本的 bash 脚本?如果您有兴趣这样做,我可以写一个答案;-) 不幸的是,围绕 uname 的包装脚本不会削减它(正如我所描述的)。除非你的意思是另一种方法。无论如何,我真的很喜欢@larsks 提供的解决方案。 【参考方案1】:

Python 只需调用uname 系统调用来获取该信息,它总是会返回有关当前运行内核的信息。在不修改源的情况下覆盖返回值会很棘手。

可以使用函数插入来完成此操作,例如如here 所述。这需要修改镜像以同时包含包装库和必要的环境设置,或者需要您在 Docker 运行命令行上传递一些额外的参数。

这是一个简单的例子。我从一个香草图像开始,并在 Python 中调用 os.uname()

$ docker run -it --rm fedora python3
Python 3.6.2 (default, Sep  1 2017, 12:03:48) 
[GCC 7.1.1 20170802 (Red Hat 7.1.1-7)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.uname()
posix.uname_result(sysname='Linux', nodename='fd2d40cb028b', release='4.13.15-100.fc25.x86_64', version='#1 SMP Tue Nov 21 22:45:32 UTC 2017', machine='x86_64')
>>> 

我希望 release 字段改为显示 1.0.0。我首先为uname 系统调用创建一个包装器:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>

/* Function pointers to hold the value of the glibc functions */
static int (*real_uname)(struct utsname *name) = NULL;

/* wrapping write function call */
int uname(struct utsname *name) 
    int res;
    real_uname = dlsym(RTLD_NEXT, "uname");
    res = real_uname(name);
    if (res == 0) 
        memset(name->release, 0, _UTSNAME_RELEASE_LENGTH);
        strncpy(name->release, "1.0.0", 5);
        

    return res;

然后我编译共享库:

$ gcc -fPIC -shared  -o wrap_uname.so wrap_uname.c -ldl

现在我可以将其注入 docker 映像并预加载共享库。关键添加是 -v 注入库和 -e LD_PRELOAD 导致链接器预加载它:

$ docker run -it --rm \
  -v $PWD/wrap_uname.so:/lib/wrap_uname.so \
  -e LD_PRELOAD=/lib/wrap_uname.so fedora python3

如您所见,这给了我们想要的结果:

Python 3.6.2 (default, Sep  1 2017, 12:03:48) 
[GCC 7.1.1 20170802 (Red Hat 7.1.1-7)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.uname()
posix.uname_result(sysname='Linux', nodename='dd88d697fb65', release='1.0.0', version='#1 SMP Tue Nov 21 22:45:32 UTC 2017', machine='x86_64')
>>> 

【讨论】:

@AliM 这很有趣! :)【参考方案2】:

您可以使用 docker:dind 在您的 CentOS 容器中运行 Ubuntu 容器(或任何其他兼容的发行版)。

【讨论】:

...其中uname系统调用将继续报告与您主机上运行的内核相关的信息,因此您仍然会遇到同样的问题。

以上是关于在 docker 容器内运行的 Python 程序依赖于“uname -r”的主要内容,如果未能解决你的问题,请参考以下文章

将本地 Elixir/Erlang 连接到 Docker 容器内正在运行的应用程序

如何通过Google Cloud调试在Docker容器内运行的Nodejs应用程序

docker容器内远程调试运行进程

如何在本地运行一次性 Docker 容器(从容器内触发)

如何在 Docker 容器内观察 NestJs 应用程序中开发的文件更改

使用docker容器运行Python程序