Рейтинг:3

Связать одно контейнерное дерево FS с другим для отладки или эфемерных контейнеров?

флаг cn

Я тестирую функции отладки 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.

Альтернатива --rbindFS дерево было бы, если бы у меня был способ монтировать --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: неправильный тип файловой системы, неправильный параметр, неверный суперблок в ., отсутствующая кодовая страница или вспомогательная программа или другая ошибка.

Подсказки?


Справочные ссылки:

Mikołaj Głodziak avatar
флаг id
Какую версию Kubernetes вы использовали?
Mikołaj Głodziak avatar
флаг id
Файловые системы контейнеров видны другим контейнерам в поде через файл `/proc/$pid/root`. Это упрощает отладку, но также означает, что секреты файловой системы защищены только разрешениями файловой системы. Что описано в [документации](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/#understanding-process-namespace-sharing).
Mikołaj Głodziak avatar
флаг id
Таким образом, вы можете использовать: `kubectl debug -it --image=debian --share-processes=true --copy-to=debug --container=debug`, то вы сможете получить доступ к тому, присоединенному к первому контейнеру, через `/proc/$pid/root/path_to_thedirectory`. Если это решение подходит для вас, дайте мне знать, пожалуйста
флаг cn
@ MikoÅajGÅodziak AFAICS из моего тестирования `--copy-to` имеет «захватывающие» эффекты, когда у цели есть `initContainer`s или вторичные контейнеры. Это также не дает вам привилегированного контейнера с `CAP_SYS_PTRACE` и другими привилегиями, если вы не создадите собственный манифест. Я ценю указатель на `/proc/$pid/root` - оказывается, вы не можете привязать его к монтированию, но вы можете использовать его как символическую ссылку.
флаг cn
@ MikoÅajGÅodziak Также извините, я должен был включить версию. Плохой разработчик без куки. У меня 1.21, но тестировал и 1.22.
флаг cn
Я представил исправление справочных страниц Linux для документации `mount_namespaces`, чтобы сделать это более понятным в будущем. Я также зарегистрировал https://github.com/kubernetes/website/issues/32249 против документов k8s.
Рейтинг:2
флаг cn

Можно сделать символическая ссылка в контекст целевого контейнера через /proc/${target_container_pid}/корень.

ln -s /proc/$pid/root/цель

/proc/$pid/корень выглядит как символическая ссылка. если ты ссылка для чтения /proc/$pid/root это указывает на /. Но это корень целевого процесса, и если вы разыменуете его в слое vfs ядра вы видите корень целевого процесса. Если вы разрешите символическую ссылку в пользовательском пространстве, вы увидите, что корень обработки выполняет разыменование.

Я не смог привязать крепление к дереву - mount -o привязать /proc/$pid/root/ /target свяжет rootfs устанавливать переработать себя в /цель, а не rootfs целевого процесса. Но это не имеет большого значения, достаточно симлинка.

(Я бы написал патч для отладка кубектла документации, но я не могу заставить свою организацию согласиться с обязательным CLA, требуемым даже для тривиальных исправлений документации...)

флаг cn
Спасибо! Я использую это для запуска `vim`, установленного на моем хосте докеров, для `: исследования` файловой системы в контейнерах без `vi` или `vim`.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.