简体   繁体   English

在docker容器中运行的Python程序依赖于'uname -r'

[英]Python program running inside docker container relies upon 'uname -r'

I have a Python program that's designed to run only in certain distros of Linux (ie CentOS, Ubuntu, etc..). 我有一个Python程序,旨在仅在某些Linux发行版(例如CentOS,Ubuntu等)中运行。 I'd like to get it running inside a CentOS7 container, but its failing because the following is returning '4.9.49-moby': 我想让它在CentOS7容器中运行,但由于以下返回“ 4.9.49-moby”而失败:

import platform
platform.release()

The program is expecting to find a linux kernel release, ie '3.10.0-327.el7.x86_64'. 该程序希望找到Linux内核发行版,即'3.10.0-327.el7.x86_64'。

Suppose I'm unable to modify the source code of the program. 假设我无法修改程序的源代码。

What are things that I can do that will workaround this issue? 我可以做些什么来解决此问题?

I tried writing a wrapper script around 'uname -r' to return what I want. 我尝试围绕“ uname -r”编写包装器脚本以返回我想要的内容。 But this isn't helping since apparently Python is sourcing this directly from the kernel. 但这没有帮助,因为显然Python是直接从内核中获取资源。

Python simply calls the uname system call to get that information, which is always going to return information about the currently running kernel. Python只是调用uname系统调用来获取该信息,该信息将始终返回有关当前正在运行的内核的信息。 Overriding the return value without modifying the source is going to be tricky. 在不修改源的情况下覆盖返回值将非常棘手。

You can accomplish this using function interposition, eg as described here . 可以做到这一点使用功能的设置,例如如这里 That requires either modifying the image to include both the wrapper library and the necessary environment setup, or it requires you to pass a number of additional parameters on the Docker run command line. 这需要修改映像以包括包装器库和必要的环境设置,或者需要您在Docker运行命令行中传递许多其他参数。

Here's a simple example. 这是一个简单的例子。 I start with a vanilla image and call os.uname() in Python: 我从香草图像开始,然后在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')
>>> 

I would like the release field to show 1.0.0 instead. 我希望release字段改为显示1.0.0 I start by creating a wrapper for the uname system call: 我首先为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;
}

And I compile the shared library: 然后我编译共享库:

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

Now I can inject that into the docker image and preload the shared library. 现在,我可以将其注入docker映像中并预加载共享库。 The key additions are are the -v to inject the library and -e LD_PRELOAD to cause the linker to preload it: 关键的附加项是-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

And as you can see, that gives us the desired result: 如您所见,这给了我们想要的结果:

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')
>>> 

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM