พวกเขามีเหตุผลมากที่สุดสำหรับฉันด้วยตัวอย่าง ...
ตรวจสอบเลเยอร์ของบิลด์ของคุณเองด้วย docker diff
ให้นำตัวอย่าง Dockerfile ที่วางแผนมา:
FROM busybox
RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one
CMD ls -alh /data
แต่ละdd
คำสั่งเหล่านั้นส่งออกไฟล์ 1M ไปยังดิสก์ ให้สร้างรูปภาพด้วยการตั้งค่าสถานะพิเศษเพื่อบันทึกคอนเทนเนอร์ชั่วคราว:
docker image build --rm=false .
ในผลลัพธ์คุณจะเห็นคำสั่งที่รันอยู่เกิดขึ้นในที่เก็บชั่วคราวที่ตอนนี้เราเก็บแทนการลบโดยอัตโนมัติ:
...
Step 2/7 : RUN mkdir /data
---> Running in 04c5fa1360b0
---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
---> ea2506fc6e11
หากคุณรัน a docker diff
บนแต่ละ ID คอนเทนเนอร์คุณจะเห็นไฟล์ที่สร้างในคอนเทนเนอร์เหล่านั้น:
$ docker diff 04c5fa1360b0 # mkdir /data
A /data
$ docker diff f1b72db3bfaa # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637 # rm /data/one
C /data
D /data/one
แต่ละบรรทัดนำหน้าด้วยการA
เพิ่มไฟล์การC
บ่งชี้การเปลี่ยนแปลงไปยังไฟล์ที่มีอยู่และD
บ่งชี้การลบ
นี่คือส่วน TL; DR
แต่ละระบบไฟล์คอนเทนเนอร์เหล่านี้มีความแตกต่างด้านบนจะเป็น "เลเยอร์" หนึ่งเดียวที่รวมเข้าด้วยกันเมื่อคุณเรียกใช้อิมเมจเป็นคอนเทนเนอร์ ไฟล์ทั้งหมดอยู่ในแต่ละเลเยอร์เมื่อมีการเพิ่มหรือเปลี่ยนแปลงดังนั้นแต่ละchmod
คำสั่งเหล่านั้นแม้จะเพิ่งเปลี่ยนบิตสิทธิ์ แต่ผลลัพธ์ในไฟล์ทั้งหมดจะถูกคัดลอกไปยังเลเยอร์ถัดไป ไฟล์ที่ถูกลบ / data / หนึ่งยังคงอยู่ในเลเยอร์ก่อนหน้านี้ 3 ครั้งในความเป็นจริงและจะถูกคัดลอกผ่านเครือข่ายและเก็บไว้ในดิสก์เมื่อคุณดึงภาพ
ตรวจสอบภาพที่มีอยู่
คุณสามารถดูคำสั่งที่จะสร้างเลเยอร์ของภาพที่มีอยู่ด้วยdocker history
คำสั่ง คุณยังสามารถเรียกใช้docker image inspect
บนรูปภาพและดูรายการของเลเยอร์ภายใต้ส่วน RootFS
นี่คือประวัติของภาพด้านบน:
IMAGE CREATED CREATED BY SIZE COMMENT
a81cfb93008c 4 seconds ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "ls -… 0B
f36265598aef 5 seconds ago /bin/sh -c rm /data/one 0B
c79aff033b1c 7 seconds ago /bin/sh -c chmod -R 0777 /data 2.1MB
b821dfe9ea38 10 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
a5602b8e8c69 13 seconds ago /bin/sh -c chmod -R 0777 /data 1.05MB
08ec3c707b11 15 seconds ago /bin/sh -c dd if=/dev/zero bs=1024 count=102… 1.05MB
ed27832cb6c7 18 seconds ago /bin/sh -c mkdir /data 0B
22c2dd5ee85d 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f… 1.16MB
เลเยอร์ใหม่ล่าสุดจะแสดงอยู่ด้านบน ด้านล่างมีสองชั้นที่ค่อนข้างเก่า พวกเขามาจากภาพไม่ว่างตัวเอง เมื่อคุณสร้างภาพหนึ่งภาพคุณจะสืบทอดเลเยอร์ทั้งหมดของภาพที่คุณระบุในFROM
บรรทัด นอกจากนี้ยังมีการเพิ่มเลเยอร์สำหรับการเปลี่ยนแปลงข้อมูลเมตาของข้อมูลเช่นCMD
บรรทัด พวกเขาแทบจะไม่ใช้พื้นที่ใด ๆ และเป็นอีกการบันทึกการตั้งค่าที่ใช้กับภาพที่คุณกำลังทำงานอยู่
ทำไมต้องเลเยอร์
เลเยอร์มีข้อดีสองสามข้อ ครั้งแรกพวกเขาไม่เปลี่ยนรูป เมื่อสร้างแล้วเลเยอร์นั้นจะถูกระบุโดยแฮช sha256 จะไม่มีการเปลี่ยนแปลง การเปลี่ยนรูปไม่ได้นั้นทำให้ภาพสามารถสร้างและแยกออกจากกันได้อย่างปลอดภัย หากนักเทียบท่าสองคนมีชุดบรรทัดเริ่มต้นเหมือนกันและสร้างขึ้นบนเซิร์ฟเวอร์เดียวกันพวกเขาจะแชร์เลเยอร์เริ่มต้นชุดเดียวกันซึ่งจะช่วยประหยัดพื้นที่ดิสก์ ซึ่งหมายความว่าหากคุณสร้างรูปภาพขึ้นใหม่โดยมีเพียงไม่กี่บรรทัดสุดท้ายของ Dockerfile ที่พบว่ามีการเปลี่ยนแปลงเฉพาะชั้นเหล่านั้นเท่านั้นที่จะต้องสร้างใหม่และส่วนที่เหลือสามารถนำกลับมาใช้ใหม่จากเลเยอร์แคช สิ่งนี้สามารถสร้างภาพนักเทียบท่าได้อย่างรวดเร็ว
ภายในคอนเทนเนอร์คุณจะเห็นระบบไฟล์รูปภาพ แต่ระบบไฟล์นั้นไม่ได้คัดลอก ที่ด้านบนของเลเยอร์รูปภาพเหล่านั้นคอนเทนเนอร์จะเมาท์เป็นเลเยอร์ของระบบไฟล์แบบอ่าน - เขียน การอ่านไฟล์ทุกครั้งจะผ่านเลเยอร์จนกว่าจะพบเลเยอร์ที่ทำเครื่องหมายไฟล์สำหรับการลบมีสำเนาของไฟล์ในเลเยอร์นั้นหรือการอ่านจนเลเยอร์หมดเพื่อค้นหา การเขียนทุกครั้งจะทำการปรับเปลี่ยนในเลเยอร์การอ่าน - เขียนเฉพาะคอนเทนเนอร์
ลดชั้นป่อง
ข้อเสียของเลเยอร์หนึ่งคือการสร้างรูปภาพที่ทำซ้ำไฟล์หรือส่งไฟล์ที่ถูกลบในเลเยอร์ในภายหลัง การแก้ปัญหามักจะรวมหลายคำสั่งเป็นRUN
คำสั่งเดียว โดยเฉพาะอย่างยิ่งเมื่อคุณแก้ไขไฟล์ที่มีอยู่หรือลบไฟล์คุณต้องการให้ขั้นตอนเหล่านั้นทำงานในคำสั่งเดียวกับที่สร้างขึ้นครั้งแรก การเขียนทับ Dockerfile ด้านบนจะมีลักษณะดังนี้:
FROM busybox
RUN mkdir /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/one \
&& chmod -R 0777 /data \
&& dd if=/dev/zero bs=1024 count=1024 of=/data/two \
&& chmod -R 0777 /data \
&& rm /data/one
CMD ls -alh /data
และถ้าคุณเปรียบเทียบภาพผลลัพธ์:
- busybox: ~ 1MB
- ภาพแรก: ~ 6MB
- ภาพที่สอง: ~ 2MB
เพียงแค่ผสานบางบรรทัดเข้าด้วยกันในตัวอย่างที่ถูกประดิษฐ์เราได้รับผลลัพธ์ที่เหมือนกันในรูปภาพของเราและหดภาพของเราจาก 5MB เป็นไฟล์ 1MB ที่คุณเห็นในภาพสุดท้าย