มีเทคนิคมากมายที่เกี่ยวข้องไม่มีวิธีแก้ปัญหาเดียว คุณอาจต้องการทำสิ่งต่อไปนี้หลายประการ:
ก่อนอื่นปรับเลเยอร์ภาพของคุณเพื่อนำมาใช้ซ้ำ ใส่ขั้นตอนการเปลี่ยนแปลงบ่อยครั้งในภายหลังใน Dockerfile เพื่อเพิ่มโอกาสที่เลเยอร์ก่อนหน้านี้จะถูกแคชจากการสร้างก่อนหน้านี้ เลเยอร์ที่นำกลับมาใช้ใหม่จะแสดงเป็นพื้นที่ดิสก์มากขึ้นใน a docker image ls
แต่ถ้าคุณตรวจสอบระบบไฟล์พื้นฐานจะมีเพียงหนึ่งสำเนาของแต่ละเลเยอร์เท่านั้นที่ถูกเก็บไว้ในดิสก์ นั่นหมายถึงรูปภาพ 3 รูปละ 2 GB แต่ที่มีเพียง 50 MB ที่แตกต่างกันในการสร้างเลเยอร์ไม่กี่ครั้งสุดท้ายจะใช้พื้นที่ดิสก์ 2.1 GB เท่านั้นแม้ว่ารายชื่อจะปรากฏว่าพวกเขาใช้ 6 GB ตั้งแต่คุณ การนับซ้ำแต่ละชั้นที่นำกลับมาใช้ใหม่
การใช้งานซ้ำของเลเยอร์คือสาเหตุที่คุณเห็นภาพที่มีการเปลี่ยนแปลงการพึ่งพาสร้างไม่บ่อยนักติดตั้งภาพเหล่านั้นก่อนที่จะคัดลอกในรหัส ดูตัวอย่างไพ ธ อนที่มีรูปแบบดังนี้
FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]
เลือกภาพฐานขั้นต่ำ นี่คือเหตุผลที่คุณเห็นคนไปจากubuntu
ไปdebian:slim
(บางสายพันธุ์มีขนาดเล็ก, การจัดส่งสินค้าที่มีเครื่องมือที่น้อยกว่า) alpine
หรือแม้กระทั่ง สิ่งนี้จะช่วยลดขนาดของจุดเริ่มต้นของคุณและเป็นประโยชน์อย่างมากหากคุณดึงภาพฐานเวอร์ชันใหม่อยู่เสมอ อย่างไรก็ตามหากภาพฐานของคุณไม่ค่อยเปลี่ยนแปลงการใช้เลเยอร์ซ้ำจะเป็นการลบความได้เปรียบส่วนใหญ่ของภาพฐานขั้นต่ำ
อิมเมจพื้นฐานที่เล็กที่สุดที่คุณสามารถเลือกได้scratch
คือไม่มีอะไรไม่มีเชลล์หรือไลบรารี่และมีประโยชน์เฉพาะกับไบนารีที่รวบรวมแบบคงที่เท่านั้น มิฉะนั้นเลือกรูปภาพพื้นฐานที่มีเครื่องมือที่คุณต้องการโดยไม่มีเครื่องมือมากมายที่คุณไม่ต้องการ
ถัดไปขั้นตอนใด ๆ ที่เปลี่ยนแปลงหรือลบไฟล์ควรรวมกับขั้นตอนก่อนหน้าที่สร้างไฟล์นั้น มิฉะนั้นระบบไฟล์แบบเลเยอร์ซึ่งใช้การคัดลอกเมื่อเขียนแม้ในสิ่งต่าง ๆ เช่นการเปลี่ยนแปลงการอนุญาตไฟล์จะมีไฟล์ต้นฉบับในเลเยอร์ก่อนหน้าและขนาดภาพจะไม่หดตัวเมื่อคุณลบไฟล์ นี่คือเหตุผลที่rm
คำสั่งของคุณไม่มีผลกับพื้นที่ดิสก์ที่ได้ แต่คุณสามารถโยงคำสั่งได้เช่น:
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
&& ... \
&& apt-get purge -y wget \
&& rm -r a-build-dir \
&& apt-get purge -y a-package
โปรดทราบว่าการผูกคำสั่งมากเกินไปอาจทำให้งานสร้างของคุณช้าลงเนื่องจากคุณต้องติดตั้งชุดเครื่องมือเดิมใหม่ทุกครั้งที่มีการเปลี่ยนแปลงข้อกำหนดเบื้องต้น (เช่นโค้ดที่ถูกดึงด้วย wget) ดูหลายขั้นตอนด้านล่างเพื่อเป็นทางเลือกที่ดีกว่า
ไฟล์ใด ๆ ที่คุณสร้างขึ้นซึ่งคุณไม่ต้องการในภาพผลลัพธ์ของคุณควรลบในขั้นตอนที่สร้างขึ้น ซึ่งรวมถึงแคชแพ็กเกจบันทึกหน้าคน ฯลฯ หากต้องการค้นหาว่าไฟล์ใดถูกสร้างขึ้นในแต่ละเลเยอร์คุณสามารถใช้เครื่องมือเช่น wagoodman / dive (ซึ่งฉันไม่ได้ตรวจสอบเป็นการส่วนตัวและจะแสดงความระมัดระวังเนื่องจากทำงานด้วยการเข้าถึงรูทแบบเต็ม บนโฮสต์ของคุณ) หรือคุณสามารถสร้างภาพนักเทียบท่าของคุณโดยไม่ตัดแต่งตู้คอนเทนเนอร์ระดับกลางจากนั้นดู diff ด้วย:
# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name .
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a
# examine any of those containers
docker container diff ${container_id}
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune
กับแต่ละภาชนะกลางเหล่านั้นต่างจะแสดงว่าไฟล์ที่มีการเพิ่มการเปลี่ยนแปลงหรือลบในขั้นตอนที่ (เหล่านี้จะมีการแสดงที่มีA
, C
หรือD
ก่อนแต่ละชื่อไฟล์) สิ่งที่แตกต่างกันก็แสดงให้เห็นว่าเป็นระบบไฟล์การอ่าน / เขียนเฉพาะคอนเทนเนอร์ซึ่งเป็นไฟล์ใด ๆ ที่เปลี่ยนแปลงโดยคอนเทนเนอร์จากสถานะรูปภาพโดยใช้ copy-on-write
วิธีที่ดีที่สุดในการลดขนาดภาพคือการกำจัดส่วนประกอบที่ไม่จำเป็นเช่นคอมไพเลอร์จากภาพที่คุณจัดส่ง สำหรับสิ่งนั้นบิลด์หลายสเตจช่วยให้คุณสามารถคอมไพล์ในสเตจเดียวแล้วคัดลอกเฉพาะสิ่งประดิษฐ์ที่เกิดขึ้นจากสเตจสร้างไปยังอิมเมจรันไทม์ที่มีเพียงความต้องการขั้นต่ำในการเรียกใช้แอปพลิเคชัน สิ่งนี้จะช่วยหลีกเลี่ยงความจำเป็นในการปรับขั้นตอนการสร้างใด ๆ ให้เหมาะสมเนื่องจากไม่ได้จัดส่งพร้อมกับอิมเมจผลลัพธ์
FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
&& apt-get install -y \
a-package \
wget \
RUN ... # perform any download/compile steps
FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]
มัลติสเตจเหมาะอย่างยิ่งกับไบนารีที่รวบรวมแบบสแตติกซึ่งคุณสามารถรันโดยมีรอยขีดข่วนเป็นอิมเมจพื้นฐานหรือเปลี่ยนจากสภาพแวดล้อมการคอมไพล์เช่น JDK ไปเป็นรันไทม์เช่น JRE นี่เป็นวิธีที่ง่ายที่สุดในการลดขนาดภาพลงอย่างมากในขณะที่ยังคงมีการสร้างที่รวดเร็ว คุณอาจยังคงดำเนินการตามขั้นตอนในขั้นตอนการเปิดตัวของคุณหากคุณมีขั้นตอนที่เปลี่ยนแปลงหรือลบไฟล์ที่สร้างในขั้นตอนก่อนหน้า แต่ส่วนใหญ่COPY
จากขั้นตอนอื่นจะแยกขั้นตอนการเปิดตัวออกจากชั้นใด ๆ
หมายเหตุฉันไม่แนะนำให้ใช้ภาพที่แบนเนื่องจากจะช่วยลดขนาดของภาพหนึ่งภาพโดยไม่ต้องใช้เลเยอร์ในการกำจัด นั่นหมายถึงการสร้างภาพในอนาคตที่เหมือนกันจะต้องมีการรับส่งข้อมูลดิสก์และเครือข่ายมากขึ้น หากต้องการย้อนกลับไปที่ตัวอย่างแรกการบีบอัดอาจลดขนาดรูปภาพของคุณจาก 2 GB เป็น 1 GB แต่อาจไม่มีภาพ 3 ภาพที่ถ่ายได้ 3 GB แทนที่จะเป็น 2.1 GB
2.37
vs.1.47 GB