เครื่องมือสำรวจเนื้อหาอิมเมจ Docker และเลเยอร์ 'Dive'
(github.com/wagoodman)- Dive เป็นเครื่องมือสำหรับสำรวจเลเยอร์และเนื้อหาไฟล์ของอิมเมจ Docker/OCI และค้นหาโอกาสในการลดขนาดอิมเมจ
- สามารถรัน
dive <your-image-tag>ด้วยแท็กอิมเมจ, ID หรือไดเจสต์ หรือใช้dive build -t <some-tag>.เพื่อทำ การวิเคราะห์ทันทีหลัง build ได้ในคำสั่งเดียว - เมื่อเลือกเลเยอร์ จะแสดง file tree ที่รวมเลเยอร์นั้นกับเลเยอร์ก่อนหน้าไว้ด้วยกัน และสามารถตรวจสอบไฟล์ที่เพิ่ม แก้ไข ลบ รวมถึงการเปลี่ยนแปลงสะสมได้จาก file tree
- ตัวชี้วัดเชิงทดลอง image efficiency จะประเมินพื้นที่ที่สูญเปล่าจากไฟล์ซ้ำ การย้ายไฟล์ข้ามเลเยอร์ และไฟล์ที่ไม่ได้ถูกลบออกอย่างสมบูรณ์ เป็นคะแนนและขนาดรวม
- สามารถตั้ง
CI=trueเพื่อข้าม UI และคืนผลผ่าน/ไม่ผ่านตามเกณฑ์ประสิทธิภาพของอิมเมจและพื้นที่สูญเปล่า ช่วยทำให้การจัดการขนาดอิมเมจใน CI pipeline เป็นอัตโนมัติได้
Dive ทำอะไรได้บ้าง
- Dive เป็นเครื่องมือสำหรับสำรวจอิมเมจ Docker, เนื้อหาเลเยอร์ และวิธีลดขนาดอิมเมจ Docker/OCI
- การรันพื้นฐานคือส่งแท็กอิมเมจ, ID หรือไดเจสต์เข้าไป
dive <your-image-tag>
- สามารถรันผ่าน Docker container ได้เช่นกัน โดยต้อง mount Docker socket
- ใช้อิมเมจ
docker.io/wagoodman/dive - มีการยก
nginx:latestเป็นตัวอย่างอิมเมจเป้าหมาย
- ใช้อิมเมจ
- หากต้องการวิเคราะห์ทันทีหลัง build อิมเมจ สามารถใช้คำสั่ง
dive buildในรูปแบบเดียวกันแทนdocker buildได้dive build -t <some-tag> .
- วิธีรันการวิเคราะห์ build ผ่าน container บน macOS รองรับเฉพาะ Docker container engine เท่านั้น
- สถานะของโปรเจกต์เป็น beta quality และสามารถส่งคำขอฟีเจอร์ใหม่หรือบั๊กผ่าน issue ได้
สำรวจเลเยอร์และการเปลี่ยนแปลงไฟล์
- เมื่อเลือกเลเยอร์ทางซ้าย ทางขวาจะแสดง file tree ที่รวมเลเยอร์นั้นกับเลเยอร์ก่อนหน้าไว้ด้วยกัน
- สามารถใช้ปุ่มลูกศรเพื่อสำรวจ file tree ได้
- สถานะของไฟล์ที่เปลี่ยนแปลงในแต่ละเลเยอร์จะแสดงอยู่ใน file tree
- เปลี่ยนแปลงแล้ว
- แก้ไขแล้ว
- เพิ่มแล้ว
- ลบแล้ว
- รูปแบบการแสดงการเปลี่ยนแปลงสามารถปรับได้ว่าจะอิงตามเลเยอร์เฉพาะ หรืออิงตาม การเปลี่ยนแปลงสะสม จนถึงเลเยอร์นั้น
ประเมินประสิทธิภาพอิมเมจและพื้นที่สูญเปล่า
- แผงด้านซ้ายล่างจะแสดงข้อมูลเลเยอร์พื้นฐานและตัวชี้วัดเชิงทดลอง image efficiency
- ตัวชี้วัดนี้ประเมินพื้นที่สูญเปล่าภายในอิมเมจ
- ไฟล์ซ้ำระหว่างเลเยอร์
- การย้ายไฟล์ระหว่างเลเยอร์
- ไฟล์ที่ไม่ได้ถูกลบออกอย่างสมบูรณ์
- ผลลัพธ์จะแสดงเป็น score แบบเปอร์เซ็นต์และพื้นที่ไฟล์สูญเปล่าทั้งหมด
ใช้เป็นเกณฑ์ผ่าน/ไม่ผ่านใน CI
- เมื่อรันด้วย environment variable
CI=trueDive จะข้าม UI วิเคราะห์อิมเมจ แล้วให้ผลลัพธ์ pass/fail ผ่าน return code - สามารถตั้งค่าเกณฑ์ 3 แบบได้ด้วยไฟล์
.dive-ciที่ root ของ repositorylowestEfficiency: ล้มเหลวหากประสิทธิภาพต่ำกว่าอัตราที่กำหนดhighestWastedBytes: ล้มเหลวหากพื้นที่สูญเปล่ามากกว่าหรือเท่ากับขนาดที่กำหนดhighestUserWastedPercent: ล้มเหลวหากสัดส่วนพื้นที่สูญเปล่าตาม user layer มากกว่าหรือเท่ากับอัตราที่กำหนด
- ในการคำนวณ
highestUserWastedPercentจะไม่นับ base image layer รวมในขนาดอิมเมจทั้งหมด - สามารถ override path ของไฟล์ตั้งค่า CI ได้ด้วยตัวเลือก
--ci-config
แหล่งอิมเมจและ container engine
- สามารถเลือกตำแหน่งที่จะดึง container image ได้ด้วยตัวเลือก
--sourcedive <your-image> --source <source>dive <source>://<your-image>
- ตัวเลือก
sourceที่รองรับมีดังนี้docker: Docker engine, ค่าเริ่มต้นdocker-archive: Docker Tar Archive บนดิสก์podman: Podman engine, รองรับเฉพาะ Linux
การติดตั้งและวิธีรัน
- Ubuntu/Debian สามารถติดตั้งด้วยแพ็กเกจ
.debหรือ Snap ได้ - วิธี Snap ไม่แนะนำหากติดตั้ง Docker ด้วย
apt-getและมีคำเตือนว่าอาจทำให้ Docker daemon เดิมเสียหายได้ - RHEL/Centos สามารถติดตั้งด้วยแพ็กเกจ
.rpmได้ - Arch Linux มีให้ใน extra repository และติดตั้งได้ด้วย pacman
- macOS สามารถติดตั้งด้วย Homebrew, MacPorts หรือ build สำหรับ Darwin จาก releases page
- Windows สามารถติดตั้งด้วย Chocolatey, scoop,
wingetหรือ build สำหรับ Windows จาก releases page - หากต้องการติดตั้งด้วยเครื่องมือ Go ต้องใช้ Go 1.10 ขึ้นไป
go install github.com/wagoodman/dive@latest- เมื่อติดตั้งด้วยวิธีนี้ การรัน
dive -vจะไม่แสดงเวอร์ชันที่ถูกต้อง
- มีวิธีติดตั้งผ่าน Nix/NixOS และ x-cmd ให้ด้วย
- เมื่อรันด้วย Docker image ต้องรวมไฟล์ Docker socket เข้าไปด้วย
-v /var/run/docker.sock:/var/run/docker.sock
- ขึ้นอยู่กับเวอร์ชัน Docker ในเครื่อง อาจต้องใช้ environment variable เช่น
DOCKER_API_VERSION=1.37 - หากใช้ runtime ทางเลือกอย่าง Colima อาจต้องกำหนด environment variable
DOCKER_HOSTเพื่อดึงอิมเมจในเครื่อง
การใช้งานและตั้งค่า UI
- key binding หลักใช้สำหรับสลับไปมาระหว่างมุมมองเลเยอร์กับมุมมอง file tree เพื่อสำรวจ กรอง และ toggle การแสดงผล
Ctrl+CหรือQ: ออกTab: สลับระหว่างมุมมองเลเยอร์และมุมมอง file treeCtrl+F: ตัวกรองไฟล์Ctrl+A: ในมุมมองเลเยอร์ แสดงการเปลี่ยนแปลงอิมเมจแบบสะสม; ในมุมมอง file tree toggle การแสดงไฟล์ที่เพิ่มCtrl+L: แสดงการเปลี่ยนแปลงของเลเยอร์ปัจจุบันCtrl+R,Ctrl+M,Ctrl+U: toggle การแสดงไฟล์ที่ลบ แก้ไข และไม่มีการเปลี่ยนแปลงCtrl+B: toggle การแสดงคุณสมบัติไฟล์
- ไม่จำเป็นต้องตั้งค่าแยกต่างหาก แต่สามารถ override ค่าได้ด้วยไฟล์ตั้งค่า YAML
- รายการที่ตั้งค่าได้รวมถึง container engine, การเพิกเฉยต่อข้อผิดพลาดในการ parse image archive, log, key binding, การแสดง diff, ความกว้างของ file tree, สถานะพับของไดเรกทอรีโดยค่าเริ่มต้น และการแสดงการเปลี่ยนแปลงสะสมของเลเยอร์
- ตำแหน่งที่ค้นหาไฟล์ตั้งค่ามีดังนี้
$XDG_CONFIG_HOME/dive/*.yaml$XDG_CONFIG_DIRS/dive/*.yaml~/.config/dive/*.yaml~/.dive.yaml
- สามารถใช้นามสกุล
.ymlแทน.yamlได้
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
เมื่อต้องจัดการอิมเมจกับเลเยอร์ crane เป็นเครื่องมือที่ยอดเยี่ยม และไลบรารีพื้นฐานอย่าง go-containerregistry ก็ดีเช่นกัน
สามารถเพิ่มเลเยอร์ใหม่ให้กับอิมเมจเดิม หรือแก้ไขเมทาดาทา (env vars, labels, entrypoint ฯลฯ) ได้ และยังสามารถ “ทำให้แบน” โดยรวมอิมเมจหลายเลเยอร์ให้เป็นเลเยอร์เดียวได้ด้วย
นอกจากนี้ยังทำ “rebase” ที่นำการเปลี่ยนแปลงไปใช้ซ้ำกับเบสอิมเมจใหม่ได้ และทั้งหมดนี้ทำได้โดยตรงบน registry จึงไม่ต้องใช้ Docker
https://github.com/google/go-containerregistry/blob/main/cmd...
craneด้วยเหตุนี้จึงใช้ Nix จัดการได้ทั้ง dependency สำหรับ build (เช่น Go) และเครื่องมือสำหรับแพ็กเกจ/ดีพลอย (เช่น gnu tar, crane) ไปพร้อมกัน
dive มีประโยชน์มากจริง ๆ ในการทำความเข้าใจว่า Docker image ทำงานอย่างไร และจะเขียน Dockerfile ให้มีประสิทธิภาพได้อย่างไร
การอ่านเอกสารก็สำคัญ แต่การได้เห็นเองว่าโครงสร้างเลเยอร์ของผลลัพธ์เปลี่ยนไปอย่างไรหลังแก้ Dockerfile เป็นสิ่งชี้ขาดต่อความเข้าใจ
Dive ยอดเยี่ยมมาก เครื่องมือแบบนี้สำคัญต่อการเรียนรู้และสร้างความมั่นใจว่าฉันกำลัง build และ deploy อะไรกันแน่
Dredge ก็เป็นเครื่องมือที่น่าดู และใช้ตอนเปรียบเทียบความต่างของเลเยอร์
https://github.com/mthalman/dredge/blob/main/docs/commands/i...
https://blog.haschek.at/2019/the-curious-case-of-the-RasPi-i...
อาจเป็นคำถามโง่ ๆ แต่สงสัยว่าทำไมเครื่องมือด้านคอนเทนเนอร์/โครงสร้างพื้นฐานส่วนใหญ่จึงเขียนด้วย Go
นึกถึง Docker, Podman, nerdctl, Terraform, Kubernetes เลยอยากรู้ว่า Go มีข้อได้เปรียบที่ชัดเจนอะไรในการสร้างเครื่องมือประเภทนี้หรือไม่
เหตุผลหลักที่เขียนใหม่ด้วย Go คือเพื่อเกาะกระแส ความนิยมของ Go ที่กำลังเติบโตในตอนนั้น (ปี 2012) ผมอยู่ตรงนั้นด้วย
ลองจินตนาการว่า Docker และ Kubernetes เขียนด้วยภาษายอดนิยมอื่น ๆ จะเห็นความต่างชัดเจน
ทางเลือกสมัยใหม่ที่โตพอแล้วดูเหมือนจะมีแค่ Rust เท่านั้น
การที่ทีมภายในมีวิศวกร Go จำนวนมากก็ด้วยเหตุผลเดียวกัน
แถมยังมีผลจาก ecosystem ด้วย จึงนำแพ็กเกจจาก implementation อื่นมาใช้ในบางส่วนของโค้ดได้ทันที
ชอบ Dive และหยิบออกมาใช้จากกล่องเครื่องมือหลายครั้งต่อเดือน
แต่สงสัยว่ามีวิธีดูเนื้อหาของไฟล์ที่เลือกได้ทันทีหรือไม่ หลายครั้งต้องการตรวจว่าไฟล์มีอยู่ในเลเยอร์ไหมแล้วดูเนื้อหา ตอนนี้มักจะรันคอนเทนเนอร์แล้วใช้
catหรือแตกเนื้อหาออกมาแล้วไล่เข้าโฟลเดอร์catมากนักตอนขยาย Docker container สาธารณะหลายตัว Dive ช่วยชีวิตไว้หลายครั้งระหว่างแกะดูว่าข้างในทำอะไรอยู่
เป็นซอฟต์แวร์ระดับ A+ จริง ๆ
ยังมี เครื่องมือ TUI บนเทอร์มินัล ดี ๆ แบบ dive อีกหลายตัว นึกถึง lazydocker และ dry
ในหมวด Docker ก็มีอยู่หลายตัว
[0] https://terminaltrove.com/
ลองดูแล้ว เห็นเลเยอร์ได้ แต่แสดงเฉพาะคำสั่งของแต่ละเลเยอร์
Dive เป็นเครื่องมือที่น่าทึ่งในโลกคอนเทนเนอร์/Docker ทำให้การดีบักว่าจริง ๆ แล้วมีอะไรอยู่ในคอนเทนเนอร์ง่ายขึ้นมาก
ตอนเริ่ม Depot [0] ใหม่ ๆ มักถูกถามบ่อยว่าจะลดขนาดอิมเมจและทำให้ build เร็วขึ้นได้อย่างไร เลยเขียนบทความสั้น ๆ [1] อธิบายวิธีแก้ปัญหานั้นด้วย Dive ไว้ ตอนนี้อาจจะเก่าไปบ้างแล้ว แต่ก็อาจเป็นประโยชน์กับใครบางคน
ได้แรงบันดาลใจจาก Dive เราจึงทำให้มองเห็นได้ง่ายขึ้นด้วยว่าใน build context มีอะไรอยู่จริง ๆ ในทุก build และปล่อยเป็นฟีเจอร์ของ Depot เมื่อไม่กี่สัปดาห์ก่อน
[0] https://depot.dev
[1] https://depot.dev/blog/reducing-image-size-with-dive
[2] https://depot.dev/blog/build-context
นอกจาก Dive จะมีประโยชน์มากแล้ว ยังมีข้อดีที่ถูกประเมินต่ำไปอีกอย่างคือ ผู้เขียนเป็น นักพัฒนาที่ยอดเยี่ยม และเป็นคนที่ร่วมงานด้วยแล้วสนุกจริง ๆ
เครื่องมือของ Google ที่ชื่อ container-diff ก็มีประโยชน์มากจริง ๆ
ใช้เวลาต้องการดูว่าสคริปต์สุ่ม ๆ ที่แนะนำให้ pipe เข้า bash แล้วรัน จะทำอะไรกับระบบบ้าง
เป็นวิธีที่สะดวกในการรัน integration test กับแอปหรืออิมเมจคอนเทนเนอร์
น่าเสียดายที่โปรเจกต์โอเพนซอร์สของ Google แบบนี้ดูเหมือนคนที่เคยดูแลเดิมออกไปกันมาก จึงต้องการคนช่วยดูแล พอมีโอกาสก็พยายามส่ง PR และปิด issue เป็นครั้งคราว โดยเฉพาะเครื่องมือทดสอบตัวนี้มีค่ามากในการรักษาสติเมื่อต้องจัดการเบสอิมเมจจำนวนมากที่ต้องดูแลภายใน