วิธีสร้างอิมเมจที่เล็กที่สุดในการทำงานทุกครั้ง?


19

มุ่ง:เพื่อสร้างอิมเมจที่เล็กที่สุดในการทำงานทุกครั้ง

ปัจจุบัน

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

พยายาม

การเพิ่มขั้นตอนการล้างข้อมูลในตอนท้ายของ Dockerfile:

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

ลดขนาดภาพลงเล็กน้อย:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

อภิปรายผล

ฉันได้สร้างภาพนักเทียบท่าต่างๆ ทุกครั้งที่ฉันพยายามลดขนาดของภาพที่สร้างขึ้น แต่ฉันมักจะรู้สึกว่ามันมีขนาดใหญ่เกินไป ฉันกำลังมองหาสคริปที่ถูกสร้างขึ้นโดยใครบางคนใน github ที่จะลบแพ็คเกจฟุ่มเฟือยทั้งหมดออกจากภาพดังนั้นขนาดของภาพที่สร้างขึ้นจะมีขนาดเล็กที่สุดเท่าที่จะทำได้

อย่างที่ฉันบอกว่าฉันพยายามลดขนาดของภาพเสมอ แต่ฉันต้องการใช้ความสอดคล้องนี้เพื่อให้ทุกภาพที่ฉันสร้างจากนี้ไปจะเล็กที่สุดเท่าที่จะทำได้

คำถาม

วิธีสร้างอิมเมจที่เล็กที่สุดในการทำงานทุกครั้ง?

คำตอบ:


1

มีเทคนิคมากมายที่เกี่ยวข้องไม่มีวิธีแก้ปัญหาเดียว คุณอาจต้องการทำสิ่งต่อไปนี้หลายประการ:


ก่อนอื่นปรับเลเยอร์ภาพของคุณเพื่อนำมาใช้ซ้ำ ใส่ขั้นตอนการเปลี่ยนแปลงบ่อยครั้งในภายหลังใน 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


25

Dockerfileสร้างเลเยอร์ใหม่สำหรับแต่ละคำสั่งในไฟล์ เนื่องจากเลเยอร์เป็นอย่างดีเลเยอร์อยู่ด้านบนของกันและกัน - คุณไม่สามารถลบไฟล์ที่เพิ่มเลเยอร์ก่อนหน้า นี่คือเหตุผลที่เมื่อคุณติดตั้งแพคเกจหรือดาวน์โหลดไฟล์หรือสร้างบิลด์แต่ละคำสั่งแยกต่างหาก - สิ่งเหล่านี้ยังคงอยู่ในรูปภาพแม้ว่าในเลเยอร์ในอนาคตคุณจะลบมันออก

ดังนั้นหากคุณเพียงแค่เปลี่ยนสิ่งนี้:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

สำหรับสิ่งนี้:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

คุณจะได้ภาพที่เล็กกว่ามาก


อีกทางเลือกหนึ่งคือการสควอชภาพหลังจากที่คุณสร้างขึ้น ถาม: การdocker --squashทำงานใหม่เป็นอย่างไร


อีกตัวเลือกหนึ่งคือการเลือกภาพฐานที่บางเฉียบ ตัวอย่างเช่นรูปภาพที่ใช้Alpine Linuxเป็นฐานแทนที่จะเป็น Debian ใช้เวลาเพียง 10-15mb แทน 180-250mb และนี่คือก่อนเพิ่มแอปพลิเคชันและข้อมูลของคุณเอง ภาพฐานที่เป็นทางการจำนวนมากในDocker Hubมีเวอร์ชันอัลไพน์


3
2.37vs.1.47 GB
030

4

อาจไม่ใช่คำตอบที่แน่ชัด แต่ควรให้ทางเลือกอื่น

ที่อยู่อาศัยของเชฟถูกสร้างขึ้นด้วยสิ่งนี้ในใจการสร้างแพคเกจที่มีการพึ่งพาที่จำเป็นทั้งหมดโดยไม่ต้องโหลดภาพภายนอก distro / base ที่คุณไม่ต้องการ

คลายบีบอัดสิ่งที่สำคัญขนาดของคอนเทนเนอร์จากโพสต์บล็อกนี้ด้วยแอป nodejs อย่างง่าย:

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-exampleเป็นภาพนักเทียบท่าจากนักเทียบท่าคลาสสิกในขณะmfdii/mytutorialappที่ภาพนักเทียบท่าที่ผลิตขึ้นกับที่อยู่อาศัย

หากขนาดเป็นปัญหาหลักของคุณและคุณพร้อมที่จะก้าวไปสู่แผนการเรียนรู้ของที่อยู่อาศัยนี่อาจเป็นทางออกสำหรับคุณ


0

หนึ่งสามารถใช้การดำน้ำ

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

เพื่อรับรายงานเกี่ยวกับสิ่งที่สามารถนำไปทิ้งขยะจากภาพนักเทียบท่าเพื่อลดขนาด


0

หากคุณต้องการมีเลเยอร์การพัฒนาที่สามารถนำมาใช้ซ้ำได้ แต่ลดการใช้งานดิสก์ของคุณสำหรับการจัดส่งคุณสามารถสร้าง "การจัดส่งเลเยอร์" แบบผสานดังนี้:

  1. ตรวจสอบให้แน่ใจว่าคุณมีคอนเทนเนอร์ที่ใช้อิมเมจของคุณ (ถ้าคุณไม่มีมันอาจใช้สิ่งที่คล้ายdocker run IMAGE echoกันถ้าคำสั่ง echo พร้อมใช้งาน)
  2. ค้นหา ID คอนเทนเนอร์ (อาจใช้docker container ls -l)
  3. ท่อdocker exportเพื่อdocker importที่จะสร้างชั้นที่ผสาน (สิ่งที่ต้องการdocker export 20f192c6530a | docker import - project:merged)

สิ่งนี้จะทำให้เลเยอร์การพัฒนาของคุณอยู่รอบ ๆ แต่ให้ภาพที่มีขนาดเล็กและผสานซึ่งคุณสามารถนำเสนอได้


0

สร้างหลายขั้นตอน ใช้รูปภาพที่มีส่วนประกอบการสร้างของคุณทั้งหมดเพื่อสร้างแอปพลิเคชันของคุณและรูปภาพรันไทม์ที่มีน้ำหนักเบากว่า คัดลอกเฉพาะสิ่งประดิษฐ์ของคุณไปยังอิมเมจรันไทม์ ไม่จำเป็นต้องลบอะไรเลย

https://docs.docker.com/develop/develop-images/multistage-build/


0

ง่าย .. นักเทียบท่า ps ตรวจสอบภาพที่กำลังรันอยู่ .. สำหรับตัวอย่างไฟล์อย่างง่ายด้านล่าง ..

จาก ubuntu16

MAINTAINER sreeni (อีเมล / โดเมน)

RUN apt-get update

RUN apt-get install -y nginx

เข้าสู่ระบบ [“ / usr / sbin / nginx”,” - g”,” daemon off;”]

เปิดเผย 80 (พอร์ต)

ไฟล์นักเทียบท่าง่าย ...

ใช้คำสั่งนักเทียบท่าด้านล่าง

นักเทียบท่าวิ่ง -d -p 80:80 - ชื่อเว็บเซิร์ฟเวอร์ ubuntu16 (ชื่อภาพ) หลังจากนั้นตรวจสอบ localhost หรือที่อยู่ ip: 80 (เปิดเบราว์เซอร์และตรวจสอบ)


1
โปรดแก้ไขการจัดรูปแบบคำตอบของคุณ ...
Pierre.Vriens
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.