Программа Python, работающая внутри контейнера Docker, использует 'uname -r'

У меня есть программа на Python, предназначенная для запуска только в определенных дистрибутивах Linux (например, CentOS, Ubuntu и т. Д.). Я бы хотел, чтобы он работал внутри контейнера CentOS7, но он не работает, потому что следующее возвращает "4.9.49-moby":

import platform
platform.release()

Программа ожидает найти выпуск ядра Linux, то есть '3.10.0-327.el7.x86_64'.

Предположим, я не могу изменить исходный код программы.

Что я могу сделать, чтобы обойти эту проблему?

Я попытался написать скрипт-обертку вокруг 'uname -r', чтобы вернуть то, что я хочу. Но это не помогает, так как, очевидно, Python получает это напрямую из ядра.

2 ответа

Решение

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

Я хотел бы 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

Теперь я могу вставить это в образ докера и предварительно загрузить общую библиотеку. Ключевые дополнения являются -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')
>>> 

Вы можете использовать docker:dind для запуска контейнера Ubuntu (или любого другого совместимого дистрибутива) внутри вашего контейнера CentOS.

Другие вопросы по тегам