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

jer*_*ean 0 python linux containers uname docker

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

import platform
platform.release()
Run Code Online (Sandbox Code Playgroud)

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

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

我可以做哪些事情来解决这个问题?

我尝试围绕“uname -r”编写一个包装脚本来返回我想要的内容。但这并没有帮助,因为显然 Python 是直接从内核获取它的。

lar*_*sks 6

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

可以使用函数插入来完成此操作,例如,如此处所述。这需要修改映像以包含包装器库和必要的环境设置,或者需要您在 Docker 运行命令行上传递许多其他参数。

这是一个简单的例子。我从普通图像开始并os.uname()用 Python 调用:

$ 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')
>>> 
Run Code Online (Sandbox Code Playgroud)

我希望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;
}
Run Code Online (Sandbox Code Playgroud)

我编译共享库:

$ gcc -fPIC -shared  -o wrap_uname.so wrap_uname.c -ldl
Run Code Online (Sandbox Code Playgroud)

现在我可以将其注入到 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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这给了我们期望的结果:

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')
>>> 
Run Code Online (Sandbox Code Playgroud)