Программа 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.