Puncte:3

Legați montarea unui arbore FS container într-un altul pentru depanare sau containere efemere?

drapel cn

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 nsentering 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 --legaAr 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ță:

Mikołaj Głodziak avatar
drapel id
Ce versiune de Kubernetes ați folosit?
Mikołaj Głodziak avatar
drapel id
Sistemele de fișiere container sunt vizibile pentru alte containere din pod prin `/proc/$pid/root`. Acest lucru face depanarea mai ușoară, dar înseamnă și că secretele sistemului de fișiere sunt protejate numai de permisiunile sistemului de fișiere. Ce este descris în [documentație](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/#understanding-process-namespace-sharing).
Mikołaj Głodziak avatar
drapel id
Deci ați putea folosi: `kubectl debug -it --image=debian --share-processes=true --copy-to=debug --container=debug` decât puteți accesa volumul atașat primului container prin `/proc/$pid/root/path_to_thedirectory`. Daca aceasta solutie ti se potriveste te rog anunta-ma
drapel cn
@MikoÅajGÅodziak AFAICS din testarea mea `--copy-to` are efecte „incitante” atunci când ținta are `initContainer`s sau containere secundare. De asemenea, nu vă oferă un container privilegiat cu `CAP_SYS_PTRACE` și alte privilegii decât dacă faceți un manifest personalizat. Apreciez indicatorul către `/proc/$pid/root` - se dovedește că nu-l poți lega, dar îl poți folosi ca link simbolic.
drapel cn
@MikoÅajGÅodziak De asemenea, îmi pare rău că ar fi trebuit să includ versiunea. Dev prost fără cookie. Sunt pe 1.21, dar am testat și cu 1.22.
drapel cn
Am trimis o corecție pentru paginile de manual Linux pentru documentele `mount_namespaces` pentru a face acest lucru mai clar pe viitor. De asemenea, am depus https://github.com/kubernetes/website/issues/32249 împotriva documentelor k8s.
Puncte:2
drapel cn

Este posibil să faci o link simbolic la contextul containerului țintă prin /proc/${target_container_pid}/root.

ln -s /proc/$pid/root /target

/proc/$pid/root arata ca o legătură simbolică. daca tu readlink /proc/$pid/root indica /. Dar este rădăcina procesului țintă și dacă îl dereferiți în stratul kernel vfs vedeți rădăcina procesului țintă. Dacă rezolvați linkul simbolic în spațiul utilizatorului, veți vedea rădăcina procesării care face dereferențierea.

Nu am reușit să-l leg pe brad - mount -o bind /proc/$pid/root/ /target va lega rădăcinile montură se procesează în /ţintă, nu rootf-urile procesului țintă. Dar nu contează prea mult, deoarece un link simbolic este suficient.

(Aș scrie un patch pentru depanare kubectl documentație, dar nu pot face ca organizația mea să fie de acord cu CLA obligatoriu necesar chiar și pentru patch-urile de documente banale...)

drapel cn
Mulțumesc! Folosesc acest lucru pentru a lansa `vim` instalat pe gazda mea docker pentru a `:Explora` sistemul de fișiere în containere fără `vi` sau `vim`.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.