Я тестирую функции отладки k8s, включая модули отладки и эфемерные контейнеры, и я просто не могу понять, как правильно сопоставить «целевые» модули. файловая система в контейнер отладки.
я хочу связать два непересекающихся пространства имен монтирования с рекурсивным монтированием привязки* поэтому контейнер A видит корень контейнера B как /контейнерБ
или наоборот. Включая все тома и прочие крепления.
Цель: одновременный доступ к файловым системам отладки и целевого контейнера.
Цель состоит в том, чтобы полное дерево файловой системы, включая тома и другие монтирования сопоставлен с подкаталогом контейнера отладки, например. /бег/цель
. Если целевой контейнер монтирует постоянные тома, эти точки монтирования должны быть сопоставлены, например. если целевой контейнер имеет /данные
тогда контейнер отладки должен иметь смонтированный /запустить/цель/данные
.
С другой стороны, было бы нормально «внедрить» дерево файловой системы контейнера отладки в целевой контейнер, так что, например. а /запуск/отладка
который предоставляет корень контейнера отладки, доступный, когда нэнтер
контейнер отладки. Включая его монтирования, такие как procfs, так что он полностью функционален.
Я хочу иметь возможность, например. gdb -p $target_pid
куда gdb
предоставляется контейнером отладки. gdb
должен быть в состоянии найти исполняемые файлы процесса из целевой контейнер за это.
Я изучил несколько обходных путей. Но что я В самом деле хочу сделать это монтировать --rbind
дерево FS целевого контейнера на гостевую или наоборот. Учитывая специально созданный привилегированный контейнер отладки, например:
апиВерсия: v1
вид: стручок
метаданные:
имя: отладочный контейнер
пространство имен: по умолчанию
спецификация:
имя_узла: TARGET_NODE_NAME_HERE
enableServiceLinks: правда
hostIPC: правда
хост-сеть: правда
hostPID: правда
политика перезапуска: никогда
контейнеры:
- изображение: DIAG_CONTAINER_IMAGE_HERE # вы можете поэкспериментировать, используя что-то вроде ubuntu:20.04
имя: отладчик
стандартный ввод: правда
телетайп: правда
томМаунты:
- путь монтирования: / цель
имя: цель
#- путь монтирования: /хост
# mountPropagation: нет
# имя: host-root
безопасностьКонтекст:
привилегированный: правда
группа запуска: 0
запустить как пользователь: 0
тома:
- пустойКаталог: {}
имя: цель
#-Путь к хосту:
# дорожка: "/"
# тип: ""
# имя: host-root
где контейнер отладки запускается в тот же узел в качестве целевого контейнера я могу:
- См. целевые процессы контейнера в
PS
- присоединяться к процессам с
стрейс
, gdb
и т. д., потому что привилегированный контейнер отладки имеет CAP_SYS_PTRACE
nsenter -t $some_target_container_pid --all
"стать" процедурой в целевом контейнере, как если бы я сделал kubectl exec
. Я больше не могу «видеть» или получать доступ к файлам/инструментам контейнера отладки.
nsenter -t $some_target_container_pid -m --root=/ --wd=/
чтобы войти в пространство имен монтирования целевого процесса, но сохранить привилегии контейнера отладки. Я больше не могу «видеть» или получать доступ к файлам/инструментам контейнера отладки.
Но я не могу:
- Просматривайте файлы в целевом контейнере одновременно с доступом к инструментам в контейнере отладки, например.
gdb
не удается найти отлаживаемые исполняемые файлы
- Просматривайте содержимое томов в целевом контейнере и применяйте к ним инструменты отладки контейнера.
Есть ли какой-нибудь признанный способ сделать это?
Это не совсем специфично для k8s: та же проблема возникает с Docker, containerd, бежать
, и т.д.
Вы можете ожидать, что это будет возможно с помощью монтировать --rbind
чтобы «внедрить» контейнер отладки в целевой контейнер через пространство имен хост-контейнера, используя путь к хосту
объем
с mountPropagation: двунаправленный
. Но контейнерd
монтирует корневой образ контейнера, устанавливает распространение монтирования как приватное затем монтирует внутренние тома. Таким образом, пространство имен монтирования хоста не видит монтирования, сделанного внутри корневого образа контейнера, а процессы в контейнере не видят новых монтирований, добавленных хостом после запуска первого процесса контейнера. Видеть https://man7.org/linux/man-pages/man7/mount_namespaces.7.html для деталей.
я пытался использовать нэнтер
для «пересечения» пространств имен монтирования, но я не могу заставить работать привязку монтирования. Например. в контейнере отладки я могу
nsenter -t $some_target_container_pid --root=/ -m /bin/bash
который дает мне оболочку, в которой .
(CWD) — rootfs контейнера отладки, а /
это целевой контейнер rootfs. Но я не могу связать их:
$ mkdir/запуск/отладка
$ монтировать --rbind . /запуск/отладка
mount: /run/debug: неправильный тип файловой системы, неправильный параметр, неверный суперблок в ., отсутствующая кодовая страница или вспомогательная программа или другая ошибка.
То же самое происходит, если я использую nsenter --wd=/
без --корень
и попробуй смонтировать --rbind / ./запуск/отладка
.
я пытался использовать отменить -м
чтобы сначала создать новое внутреннее пространство имен монтирования. И я пробовал смонтировать --make-rprivate /
в дереве контейнеров отладки перед монтированием привязки. Та же сделка.
Я не могу понять, почему: в dmesg ничего нет, и ошибка очень общая. Я предполагаю, что это связано с непересекающимися корнями и/или непересекающимися пространствами имен монтирования. Похоже, это не связано с защитой ядра от цикличности монтирования привязки. И я использую рекурсивные привязки, так что это не должно быть связано с защитой от экранирования дерева монтирования в пространствах имен пользователей Linux.
Альтернатива --rbind
FS дерево было бы, если бы у меня был способ монтировать --bind
к идентификатор монтирования как показано в /proc/$target_pid/mountinfo
. Затем я мог бы клонировать все монтирования из целевого pid в пространство имен монтирования контейнера отладки. Но я не могу монтировать --bind
используя обычный абсолютный путь, потому что пространства имен монтирования целевого и отладочного контейнеров не пересекаются, и оба имеют поддеревья монтирования с частным распространением.
Я пытался использовать целевой процесс /proc/$pid/ns/mnt
mount, так как я видел ссылку на связывание с его использованием. Но на моем ядре 5.16 это дерево поддельных симлинков, а не дерево fs:
$ readlink /proc/self/ns/mnt
мнт:[4026531840]
$ ls /proc/self/ns/mnt/
ls: невозможно получить доступ к '/proc/self/ns/mnt/': это не каталог
Самое близкое, что у меня есть для обходного пути на данный момент, это нэнтер
взломать рабочий каталог. Это предлагает очень ограниченную инъекцию инструментов в целевой контейнер. Где pid 1055 — это pid в целевом контейнере:
# nsenter -t 1055 -p -m --wd=/ /bin/bash
shell-init: ошибка при получении текущего каталога: getcwd: невозможно получить доступ к родительским каталогам: нет такого файла или каталога
# лс /
...содержимое целевого контейнера rootfs здесь...
# лс .
...отладка контейнера rootfs здесь...
# лс ..
... отлаживать rootfs контейнера и здесь, потому что . является корнем...
# пароль
pwd: ошибка при получении текущего каталога: getcwd: невозможно получить доступ к родительским каталогам: нет такого файла или каталога
# ls usr/bin/gdb
usr/bin/gdb
# лс /usr/bin/gdb
ls: невозможно получить доступ к '/usr/bin/gdb': нет такого файла или каталога
но я не могу привязать mount, как хочу, из того же сеанса nsenter:
# mkdir/запуск/отладка
# монтировать --rbind . /запуск/отладка
mount: /run/debug: неправильный тип файловой системы, неправильный параметр, неверный суперблок в ., отсутствующая кодовая страница или вспомогательная программа или другая ошибка.
Подсказки?
Справочные ссылки: