Testez funcțiile de depanare k8s, inclusiv poduri de depanare și containere efemere, și pur și simplu nu pot să înțeleg cum să mapez corect un pod „țintă” Sistemul de fișiere în containerul de depanare.
vreau sa leagă două spații de nume de montare disjunse cu o montare de legare recursivă* deci containerul A vede rădăcina containerului B ca /containerB
sau vice versa. Inclusiv toate volumele și alte monturi.
Obiectiv: Acces la sistemele de fișiere containere de depanare și țintă în același timp
Scopul este de a avea podul țintă arbore complet al sistemului de fișiere, inclusiv volume și alte monturi mapat la un subdir al containerului de depanare, de ex. /run/target
. Dacă containerul țintă montează volume persistente, acele puncte de montare ar trebui mapate, deci de ex. dacă containerul țintă are /date
atunci containerul de depanare ar trebui să aibă un montat /run/target/data
.
Alternativ, ar fi bine să „injectați” arborele sistemului de fișiere al containerului de depanare în containerul țintă, deci există de ex. A /run/debug
care expune rădăcina containerului de depanare disponibilă atunci când nsenter
ing containerul de depanare. Inclusiv monturile sale ca procfs, deci este complet funcțional.
Vreau să pot de ex. gdb -p $target_pid
Unde gdb
este furnizat de containerul de depanare. gdb
trebuie să poată găsi executabilele procesului din container țintă pentru asta.
Am explorat câteva abordări alternative. Dar ce eu într-adevăr vreau sa fac este monte --bind
arborele FS container țintă pe oaspete sau invers. Având în vedere un container de depanare privilegiat personalizat, cum ar fi:
apiVersion: v1
fel: Pod
metadate:
nume: debugcontainer
spatiu de nume: implicit
specificație:
nodeName: TARGET_NODE_NAME_HERE
enableServiceLinks: adevărat
hostIPC: adevărat
hostNetwork: adevărat
hostPID: adevărat
restartPolicy: Niciodată
containere:
- imagine: DIAG_CONTAINER_IMAGE_HERE # puteți experimenta folosind ceva de genul ubuntu:20.04
nume: depanator
stdin: adevărat
tty: adevărat
volumMonturi:
- mountPath: /target
nume: tinta
#- mountPath: /gazdă
# mountPropagation: Nici unul
# nume: gazdă-rădăcină
securityContext:
privilegiat: adevărat
runAsGroup: 0
runAsUser: 0
volume:
- emptyDir: {}
nume: tinta
#-hostPath:
# cale: "/"
# tip: ""
# nume: gazdă-rădăcină
unde containerul de depanare este lansat în același nod ca container țintă, pot:
- Vedeți procesele containerului țintă în
ps
- atașați proceselor cu
strace
, gdb
etc deoarece containerul privilegiat de depanare are CAP_SYS_PTRACE
nsenter -t $some_target_container_pid --all
să „devin” un proc în containerul țintă, ca și cum aș fi făcut-o kubectl exec
. Nu mai pot „vedea” sau accesa fișierele/instrumentele containerului de depanare.
nsenter -t $some_target_container_pid -m --root=/ --wd=/
pentru a introduce spațiul de nume de montare al proc-ului țintă, dar păstrați confidențialitatea containerului de depanare. Nu mai pot „vedea” sau accesa fișierele/instrumentele containerului de depanare.
Dar nu pot:
- Vedeți fișierele din containerul țintă în același timp cu accesul la instrumentele din containerul de depanare - de ex.
gdb
nu pot găsi executabilele depanate
- Vedeți conținutul volumelor din containerul țintă și aplicați acestora instrumente de depanare
Există vreo modalitate recunoscută de a face asta?
Nu este complet specific pentru k8s: aceeași problemă se aplică și cu Docker, containerd, runc
, etc.
S-ar putea să vă așteptați ca acest lucru să fie posibil prin utilizarea monte --bind
pentru a „injecta” containerul de depanare în containerul țintă prin spațiul de nume al containerului gazdă folosind a hostPath
volum
cu mountPropagare: bidirecțională
. Dar containerd
montează imaginea rădăcină a containerului, setează propagarea de montare la privat apoi montează volumele interioare. Deci, spațiul de nume de montare a gazdei nu vede monturile făcute în interiorul imaginii rădăcină a containerului, iar procesele din container nu văd monturi noi adăugate de gazdă după începerea primului proces al containerului. Vedea https://man7.org/linux/man-pages/man7/mount_namespaces.7.html pentru detalii.
Am încercat să folosesc nsenter
pentru a „încrucișa” spațiile de nume de montare, dar nu pot face ca o montură de legătură să funcționeze. De exemplu. în containerul de depanare pot
nsenter -t $some_target_container_pid --root=/ -m /bin/bash
care îmi dă o coajă în care .
(CWD) este rootfs containerul de depanare și /
este container țintă rootfs. Dar se pare că nu le pot lega-mont:
$ mkdir /run/debug
$ mount --bind . /run/debug
mount: /run/debug: tip fs greșit, opțiune greșită, superbloc defectuos pe ., pagina de coduri sau program de ajutor lipsă sau altă eroare.
La fel se întâmplă și dacă folosesc nsenter --wd=/
fără --rădăcină
, și încearcă mount --rbind / ./run/debug
.
Am încercat să folosesc unshare -m
pentru a crea mai întâi un nou spațiu de nume de montare interior. Și am încercat mount --make-rprivate /
pe arborele containerului de depanare înainte de montarea bind. Aceeași afacere.
Nu pot să înțeleg de ce: nu există nimic în dmesg și eroarea este foarte generică. Bănuiesc că se datorează rădăcinilor disjunse și/sau spațiilor de nume de montare disjunse. Nu pare să se datoreze protecției nucleului împotriva circularității monturii de legare. Și folosesc legături recursive, deci nu ar trebui să se datoreze protecției împotriva evadărilor de arbore de montare în spațiile de nume de utilizatori Linux.
O modificare a --lega
Ar fi un arbore FS dacă aș avea o cale monte --lega
de id montură așa cum se arată în /proc/$target_pid/mountinfo
. Am putut apoi clona toate monturile din pid-ul țintă în spațiul de nume de montare al containerului de depanare. Dar nu pot monte --lega
folosind o cale absolută normală, deoarece spațiile de nume de montare ale containerului țintă și depanare sunt disjunse și ambele au subarbori de monturi cu propagare privată.
Am încercat să folosesc un proces țintă /proc/$pid/ns/mnt
mount namespace, așa cum am văzut referire la bind-mounting folosindu-l. Dar pe kernel-ul meu 5.16 este un arbore de legături simbolice false, nu un arbore fs:
$ readlink /proc/self/ns/mnt
mnt:[4026531840]
$ ls /proc/self/ns/mnt/
ls: nu poate accesa „/proc/self/ns/mnt/”: nu este un director
Cel mai apropiat lucru pe care îl am de o soluție în acest moment este nsenter
hack cu directorul de lucru. Aceasta oferă o injecție foarte limitată a sculelor în containerul țintă. Unde pid 1055 este un pid în containerul țintă:
# nsenter -t 1055 -p -m --wd=/ /bin/bash
shell-init: eroare la preluarea directorului curent: getcwd: nu pot accesa directoarele părinte: nu există un astfel de fișier sau director
# ls /
...țintă conținutul rootfs al containerului aici...
# ls .
...depanați rădăcinile containerului aici...
#ls ..
...depanați și aici rootf-urile containerului deoarece . este o radacina...
# pwd
pwd: eroare la preluarea directorului curent: getcwd: nu pot accesa directoarele părinte: nu există un astfel de fișier sau director
# ls usr/bin/gdb
usr/bin/gdb
# ls /usr/bin/gdb
ls: nu poate accesa „/usr/bin/gdb”: nu există un astfel de fișier sau director
dar nu pot lega montarea așa cum vreau, din aceeași sesiune nsenter:
# mkdir /run/debug
# mount --binnd . /run/debug
mount: /run/debug: tip fs greșit, opțiune greșită, superbloc defectuos pe ., pagina de coduri sau program de ajutor lipsă sau altă eroare.
Sfaturi?
Link-uri de referință: