Score:3

ผูกเมานต์ทรี FS ของคอนเทนเนอร์หนึ่งไปยังอีกคอนเทนเนอร์หนึ่งสำหรับการดีบักหรือคอนเทนเนอร์ชั่วคราว

ธง cn

ฉันกำลังทดสอบคุณสมบัติการดีบัก k8s รวมถึงพ็อดดีบั๊กและคอนเทนเนอร์ชั่วคราว และฉันไม่สามารถหาวิธีแมปพ็อด "เป้าหมาย" ได้อย่างถูกต้อง ระบบไฟล์ ลงในคอนเทนเนอร์การดีบัก

ฉันต้องการ เชื่อมโยงเนมสเปซเมานต์ disjoint สองอันด้วยการเมานต์การผูกแบบเรียกซ้ำ* ดังนั้นคอนเทนเนอร์ A จึงเห็นรูทของคอนเทนเนอร์ B เป็น /คอนเทนเนอร์ข หรือในทางกลับกัน รวมถึงวอลุ่มทั้งหมดและการเมานต์อื่นๆ

เป้าหมาย: เข้าถึงทั้งระบบไฟล์ดีบักและคอนเทนเนอร์เป้าหมายพร้อมกัน

เป้าหมายคือการมีฝักเป้าหมาย โครงสร้างระบบไฟล์แบบเต็ม รวมถึงวอลุ่มและการเมานต์อื่นๆ แมปกับส่วนย่อยของคอนเทนเนอร์ดีบั๊กเช่น /วิ่ง/เป้าหมาย. หากคอนเทนเนอร์เป้าหมายเมาต์ไดรฟ์ข้อมูลถาวร ควรแมปจุดเชื่อมต่อเหล่านั้น เช่น หากคอนเทนเนอร์เป้าหมายมี /ข้อมูล จากนั้นควรติดตั้งดีบักคอนเทนเนอร์ /รัน/เป้าหมาย/ข้อมูล.

อีกทางหนึ่ง จะเป็นการดีที่จะ "แทรก" โครงสร้างระบบไฟล์คอนเทนเนอร์ดีบักลงในคอนเทนเนอร์เป้าหมาย ดังนั้นจึงมีเช่น ก /รัน/ดีบั๊ก ที่แสดงการดีบักคอนเทนเนอร์รูทที่พร้อมใช้งานเมื่อ เซนเตอร์ใช้งานดีบักคอนเทนเนอร์ รวมถึงตัวยึดเช่น procfs ดังนั้นมันจึงทำงานได้อย่างสมบูรณ์

ฉันต้องการที่จะสามารถเช่น gdb -p $target_pid ที่ไหน จีดีบี มีให้โดยคอนเทนเนอร์การดีบัก จีดีบี จะต้องสามารถค้นหากระบวนการที่เรียกใช้งานได้จาก คอนเทนเนอร์เป้าหมาย สำหรับสิ่งนี้.

ฉันได้สำรวจแนวทางแก้ไขปัญหาบางอย่างแล้ว แต่สิ่งที่ฉัน จริงๆ ที่อยากทำคือ เมานต์ --rbind ต้นไม้ FS ของคอนเทนเนอร์เป้าหมายไปยังแขกหรือในทางกลับกัน รับคอนเทนเนอร์ดีบักสิทธิพิเศษที่สร้างขึ้นเอง เช่น:

api เวอร์ชัน: v1
ชนิด: ฝัก
ข้อมูลเมตา:
  ชื่อ: debugcontainer
  เนมสเปซ: ค่าเริ่มต้น
ข้อมูลจำเพาะ:
  ชื่อโหนด: TARGET_NODE_NAME_HERE
  enableServiceLinks: จริง
  hostIPC: จริง
  โฮสต์เครือข่าย: จริง
  hostPID: จริง
  นโยบายรีสตาร์ท: ไม่เคย
  ตู้คอนเทนเนอร์:
  - รูปภาพ: DIAG_CONTAINER_IMAGE_HERE # คุณสามารถทดลองใช้บางอย่างเช่น Ubuntu:20.04 
    ชื่อ: ดีบักเกอร์
    stdin: จริง
    tty: จริง
    ปริมาณการติดตั้ง:
    - mountPath: /เป้าหมาย
      ชื่อ: เป้าหมาย
    #- เส้นทางภูเขา: /host
    # mountการขยายพันธุ์: ไม่มี
    # ชื่อ: โฮสต์รูท
    บริบทความปลอดภัย:
      สิทธิพิเศษ: จริง
      เรียกใช้ AsGroup: 0
      เรียกใช้ AsUser: 0
  ปริมาณ:
  - ว่างDir: {}
    ชื่อ: เป้าหมาย
  #- เส้นทางโฮสต์:
  #    เส้นทาง: "/"
  #    พิมพ์: ""
  # ชื่อ: โฮสต์รูท

ที่เปิดตัวคอนเทนเนอร์การแก้ไขข้อบกพร่องใน โหนดเดียวกัน ในฐานะคอนเทนเนอร์เป้าหมาย ฉันสามารถ:

  • ดูกระบวนการคอนเทนเนอร์เป้าหมายใน ปล
  • แนบไปกับกระบวนการด้วย สเตรส, จีดีบี ฯลฯ เนื่องจากคอนเทนเนอร์การดีบักที่มีสิทธิพิเศษมี CAP_SYS_PTRACE
  • nsenter -t $some_target_container_pid --ทั้งหมด เพื่อ "กลายเป็น" proc ในคอนเทนเนอร์เป้าหมายราวกับว่าฉันทำเสร็จแล้ว ผู้บริหาร kubectl. ฉันไม่สามารถ "ดู" หรือเข้าถึงไฟล์/เครื่องมือดีบักคอนเทนเนอร์ได้อีกต่อไป
  • nsenter -t $some_target_container_pid -m --root=/ --wd=/ เพื่อป้อนเนมสเปซเมานต์ของ proc เป้าหมาย แต่คงไว้ซึ่ง privs ของคอนเทนเนอร์ดีบั๊ก ฉันไม่สามารถ "ดู" หรือเข้าถึงไฟล์/เครื่องมือดีบักคอนเทนเนอร์ได้อีกต่อไป

แต่ฉันไม่สามารถ:

  • ดูไฟล์ในคอนเทนเนอร์เป้าหมายพร้อมกับเข้าถึงเครื่องมือในคอนเทนเนอร์แก้ไขข้อบกพร่อง เช่น จีดีบี ไม่พบไฟล์เรียกทำงานที่ถูกดีบั๊ก
  • ดูเนื้อหาของวอลุ่มในคอนเทนเนอร์เป้าหมายและใช้เครื่องมือดีบักคอนเทนเนอร์กับพวกเขา

มีวิธีการใดที่รู้จักในการทำเช่นนี้หรือไม่?

มันไม่ได้เจาะจง k8 ทั้งหมด: ปัญหาเดียวกันนี้ใช้กับ Docker, containerd, วิ่งฯลฯ

คุณอาจคาดหวังว่าสิ่งนี้จะเป็นไปได้โดยใช้ เมานต์ --rbind เพื่อ "ฉีด" คอนเทนเนอร์ดีบั๊กลงในคอนเทนเนอร์เป้าหมายผ่านเนมสเปซคอนเทนเนอร์โฮสต์โดยใช้ไฟล์ เส้นทางโฮสต์ ปริมาณ กับ การขยายพันธุ์: แบบสองทิศทาง. แต่ ตู้คอนเทนเนอร์ เมานต์อิมเมจรูทของคอนเทนเนอร์ ตั้งค่าการเผยแพร่เมานต์เป็นแบบส่วนตัว จากนั้นติดตั้งไดรฟ์ข้อมูลภายใน ดังนั้นเนมสเปซการเมานต์ของโฮสต์จึงไม่เห็นการเมานต์ที่สร้างขึ้นภายในอิมเมจรูทของคอนเทนเนอร์และ procs ในคอนเทนเนอร์จะไม่เห็นการเมานต์ใหม่ที่โฮสต์เพิ่มหลังจากกระบวนการแรกของคอนเทนเนอร์เริ่มต้น ดู https://man7.org/linux/man-pages/man7/mount_namespaces.7.html สำหรับรายละเอียด

ฉันได้ลองใช้ เซนเตอร์ เพื่อ "ข้าม" เมานต์เนมสเปซ แต่ฉันไม่สามารถเมานต์ผูกให้ทำงานได้ เช่น. ในคอนเทนเนอร์ดีบักฉันทำได้

nsenter -t $some_target_container_pid --root=/ -m /bin/bash

ซึ่งทำให้ฉันมีเปลือกที่ . (CWD) เป็น rootfs ของคอนเทนเนอร์ดีบัก และ / คือ คอนเทนเนอร์เป้าหมาย ราก แต่ฉันไม่สามารถผูกมัดพวกเขาได้:

$ mkdir /รัน/ดีบัก
$ เมาท์ --rbind . /รัน/ดีบั๊ก
mount: /run/debug: ประเภท fs ผิด, ตัวเลือกไม่ดี, superblock เสียบน ., ไม่มีหน้ารหัสหรือโปรแกรมตัวช่วย หรือข้อผิดพลาดอื่นๆ

สิ่งเดียวกันนี้จะเกิดขึ้นหากฉันใช้ nsenter --wd=/ ปราศจาก --รากและพยายามที่จะ เมานต์ --rbind / ./run/debug.

ฉันได้ลองใช้ ยกเลิกการแบ่งปัน -m เพื่อสร้างเนมสเปซเมานต์ภายในใหม่ก่อน และฉันได้พยายาม เมานต์ --make-rprivate / บนแผนผังคอนเทนเนอร์การดีบักก่อนการเมานต์การผูก ข้อตกลงเดียวกัน

ฉันไม่สามารถหาสาเหตุได้: ไม่มีอะไรใน dmesg และข้อผิดพลาดนั้นธรรมดามาก ฉันเดาว่าเป็นเพราะรากที่แยกจากกันและ/หรือเนมสเปซเมานต์ที่แยกจากกัน ดูเหมือนจะไม่ได้เกิดจากการป้องกันของเคอร์เนลต่อการผูกเป็นวงกลม และฉันใช้การผูกแบบเรียกซ้ำ ดังนั้นจึงไม่ควรเกิดจากการป้องกันการเมานต์ทรีเอสเคปในเนมสเปซผู้ใช้ linux

ทางเลือกในการ --rbindการใช้ทรี FS จะเป็นถ้าฉันมีวิธี เมานต์-ผูก โดย รหัสเมานต์ ตามที่ปรากฏใน /proc/$target_pid/mountinfo. จากนั้นฉันสามารถโคลนการเมานต์ทั้งหมดจาก pid เป้าหมายไปยังเนมสเปซเมานต์ของคอนเทนเนอร์ดีบั๊ก แต่ฉันทำไม่ได้ เมานต์-ผูก ใช้พาธสัมบูรณ์ปกติ เนื่องจากเนมสเปซการเมาต์ของคอนเทนเนอร์เป้าหมายและดีบักนั้นแยกจากกัน และทั้งคู่มีทรีย่อยของการเมาต์ที่มีการเผยแพร่ส่วนตัว

ฉันได้ลองใช้กระบวนการเป้าหมายแล้ว /proc/$pid/ns/mnt เมานต์เนมสเปซตามที่ฉันเห็นการอ้างอิงถึงการผูกมัดโดยใช้มัน แต่ในเคอร์เนลของฉัน 5.16 มันเป็นต้นไม้ของ symlinks ปลอมไม่ใช่ต้นไม้ 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 ของคอนเทนเนอร์ที่นี่...

#ล .
...debug rootfs ของคอนเทนเนอร์ที่นี่...

#ล ..
...debug คอนเทนเนอร์ rootfs ที่นี่เช่นกันเพราะ . เป็นราก...

# pwd
pwd: ข้อผิดพลาดในการเรียกไดเรกทอรีปัจจุบัน: getcwd: ไม่สามารถเข้าถึงไดเรกทอรีหลัก: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว

# ls usr/bin/gdb
usr/bin/gdb

# ls /usr/bin/gdb
ls: ไม่สามารถเข้าถึง '/usr/bin/gdb': ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว

แต่ฉันไม่สามารถผูกเมานต์ได้อย่างที่ฉันต้องการจากภายในเซสชัน nsenter เดียวกัน:

# mkdir /รัน/ดีบัก
# mount --rbind . /รัน/ดีบั๊ก
mount: /run/debug: ประเภท fs ผิด, ตัวเลือกไม่ดี, superblock เสียบน ., ไม่มีหน้ารหัสหรือโปรแกรมตัวช่วย หรือข้อผิดพลาดอื่นๆ

คำใบ้?


ลิงค์อ้างอิง:

Mikołaj Głodziak avatar
id flag
คุณใช้ Kubernetes เวอร์ชันใด
Mikołaj Głodziak avatar
id flag
ระบบไฟล์ของคอนเทนเนอร์สามารถมองเห็นได้สำหรับคอนเทนเนอร์อื่นๆ ในพ็อดผ่าน `/proc/$pid/root` สิ่งนี้ทำให้การดีบักง่ายขึ้น แต่ก็หมายความว่าความลับของระบบไฟล์ได้รับการปกป้องโดยสิทธิ์ของระบบไฟล์เท่านั้น สิ่งที่อธิบายไว้ใน[เอกสารประกอบ](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/#understanding-process-namespace-sharing)
Mikołaj Głodziak avatar
id flag
ดังนั้นคุณสามารถใช้: `kubectl debug -it --image=debian --share-processes=true --copy-to=debug --container=debug` กว่าที่คุณสามารถเข้าถึงไดรฟ์ข้อมูลที่แนบมากับคอนเทนเนอร์แรกผ่าน `/proc/$pid/root/path_to_thedirectory` หากโซลูชันนี้เหมาะกับคุณโปรดแจ้งให้เราทราบ
cn flag
@MikoÅajGÅodziak AFAICS จากการทดสอบของฉัน `--copy-to` มีเอฟเฟกต์ "น่าตื่นเต้น" เมื่อเป้าหมายมี `initContainer`s หรือคอนเทนเนอร์รอง นอกจากนี้ยังไม่ให้คอนเทนเนอร์สิทธิพิเศษที่มี `CAP_SYS_PTRACE` และสิทธิพิเศษอื่นๆ แก่คุณ เว้นแต่คุณจะสร้างรายการที่กำหนดเอง ฉันขอขอบคุณตัวชี้ไปที่ `/proc/$pid/root` - ปรากฎว่าคุณไม่สามารถผูกเมานต์ได้ แต่คุณสามารถใช้เป็น symlink ได้
cn flag
@MikoÅajGÅodziak ขออภัยด้วย ฉันควรจะรวมเวอร์ชันนี้ไว้ด้วย นักพัฒนาไม่ดีไม่มีคุกกี้ ฉันใช้ 1.21 แต่ได้ทำการทดสอบด้วย 1.22
cn flag
ฉันได้ส่งแพตช์ man-pages ของ linux สำหรับเอกสาร `mount_namespaces` เพื่อให้ชัดเจนยิ่งขึ้นในอนาคต ฉันยื่น https://github.com/kubernetes/website/issues/32249 กับเอกสาร k8s ด้วย
Score:2
ธง cn

เป็นไปได้ที่จะสร้าง ลิงค์สัญลักษณ์ ไปยังบริบทของคอนเทนเนอร์เป้าหมายผ่านทาง /proc/${target_container_pid}/root.

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

/proc/$pid/root ดู เช่น symlink ถ้าคุณ อ่านลิงค์ /proc/$pid/root มันชี้ไปที่ /. แต่มันเป็นรากเหง้าของกระบวนการเป้าหมาย และถ้าคุณละเลยมัน ในชั้นเคอร์เนล vfs คุณเห็นรูทของกระบวนการเป้าหมาย หากคุณแก้ไข symlink ในพื้นที่ผู้ใช้ คุณจะเห็นรูทของการประมวลผลที่ทำการยกเลิกการอ้างอิง

ฉันไม่สามารถผูกมัดต้นไม้ได้ - เมานต์ -o ผูก /proc/$pid/root/ /target จะผูกรากของ ภูเขา แปรรูปตัวเองเป็น /เป้าไม่ใช่รากของกระบวนการเป้าหมาย แต่ก็ไม่สำคัญมากนัก เนื่องจาก symlink ก็เพียงพอแล้ว

(ฉันจะเขียนแพทช์สำหรับ การแก้ปัญหา kubectl เอกสารประกอบ แต่ฉันไม่สามารถให้องค์กรของฉันยอมรับ CLA บังคับที่จำเป็นแม้แต่สำหรับแพตช์เอกสารเล็กน้อย...)

cn flag
ขอขอบคุณ! ฉันใช้สิ่งนี้เพื่อเปิดใช้งาน `vim` ที่ติดตั้งบนโฮสต์นักเทียบท่าของฉันเพื่อ `: สำรวจ ` ระบบไฟล์ในคอนเทนเนอร์ที่ไม่มี `vi` หรือ `vim`

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา