ทำไมรูปภาพของ Docker container จึงใหญ่มาก?


177

ฉันสร้างภาพอย่างง่ายผ่าน Dockerfile จาก Fedora (ขนาดเริ่มต้น 320 MB)

เพิ่มนาโน (ตัวแก้ไขเล็ก ๆ ขนาด 1MB) และขนาดของรูปภาพเพิ่มขึ้นเป็น 530 MB ฉันได้เพิ่ม Git ไว้ด้านบน (30-ish MB) แล้วขนาดภาพท้องฟ้าของฉันไปที่ 830 MB

นั่นมันไม่บ้าเหรอ?

ฉันพยายามส่งออกและนำเข้าที่เก็บเพื่อลบประวัติ / ภาพกลาง ความพยายามนี้ช่วยได้มากถึง 25 MB ตอนนี้ขนาดภาพของฉันคือ 804 MB ฉันได้ลองใช้คำสั่งหลายคำสั่งในครั้งเดียวRUNแต่ถึงกระนั้นฉันก็ยังเริ่มต้น 830MB เดิมได้

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

ทุกคนทนทุกข์ทรมานจากขนาดภาพที่ไร้สาระ? คุณจัดการกับมันอย่างไร

นอกเสียจากว่า Dockerfile ของฉันจะไม่ถูกต้องอย่างน่ากลัว?

FROM fedora:latest
MAINTAINER Me NotYou <email@dot.com>
RUN yum -y install nano
RUN yum -y install git

แต่มันยากที่จะจินตนาการว่ามีอะไรผิดปกติเกิดขึ้นที่นี่


คุณทำการวัดขนาดภาชนะของคุณอยู่ที่ไหนและอย่างไร ไม่yum clean allได้มีผลกระทบใด ๆ กับขนาด?
ดาวตก

2
คาดว่ารูปภาพจะมีขนาดที่ดีเนื่องจากเป็นการสะสมภาพของภาพหลักและภาพหลัก นอกจากนี้ยัมยังติดตั้งไม่เพียง แต่แอพดังกล่าว แต่ยังรวมถึงแอปที่ต้องพึ่งพา docs.docker.com/terms/container
rexposadas

2
"การวัด" ของฉันก็คือการประมวลผลdocker imagesซึ่งในคอลัมน์สุดท้ายระบุว่าหนัก 830MB ฉันอาจไม่รู้ตัวจริงขนาดของรูปภาพของฉันคืออะไรเนื่องจากนักเทียบท่ารูปภาพระบุว่า 830MB นี้เป็นขนาดเสมือนจริง แต่แล้วอีกครั้งขนาดภาพที่แท้จริงคืออะไร?
Zen

คำตอบ:


118

ดังที่ @rexposadas กล่าวไว้ภาพรวมเลเยอร์ทั้งหมดและแต่ละเลเยอร์มีการอ้างอิงทั้งหมดสำหรับสิ่งที่คุณติดตั้ง เป็นสิ่งสำคัญที่จะต้องทราบว่าภาพพื้นฐาน (เช่นfedora:latestมีแนวโน้มที่จะเป็นกระดูกเปล่ามาก ๆ ) คุณอาจประหลาดใจกับจำนวนการพึ่งพาของซอฟต์แวร์ที่ติดตั้งของคุณ

ฉันสามารถทำให้การติดตั้งของคุณเล็กลงอย่างมีนัยสำคัญโดยเพิ่มyum -y clean allลงในแต่ละบรรทัด:

FROM fedora:latest
RUN yum -y install nano && yum -y clean all
RUN yum -y install git && yum -y clean all

สิ่งสำคัญคือต้องทำเช่นนั้นสำหรับแต่ละ RUN ก่อนที่เลเยอร์จะได้รับการยืนยันมิฉะนั้นการลบจะไม่ลบข้อมูลออกจริง ๆ นั่นคือในระบบไฟล์แบบรวม / คัดลอกเมื่อเขียนการล้างท้ายไม่ได้ลดการใช้ระบบไฟล์จริงๆเพราะข้อมูลจริงมุ่งมั่นที่จะลดเลเยอร์ คุณต้องทำความสะอาดที่เลเยอร์แต่ละรอบ

$ docker history bf5260c6651d
IMAGE               CREATED             CREATED BY                                      SIZE
bf5260c6651d        4 days ago          /bin/sh -c yum -y install git; yum -y clean a   260.7 MB
172743bd5d60        4 days ago          /bin/sh -c yum -y install nano; yum -y clean    12.39 MB
3f2fed40e4b0        2 weeks ago         /bin/sh -c #(nop) ADD file:cee1a4fcfcd00d18da   372.7 MB
fd241224e9cf        2 weeks ago         /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar   0 B
511136ea3c5a        12 months ago                                                       0 B

1
ขอขอบคุณสำหรับความพยายามของคุณในการตรวจสอบกรณีและใช่ฉันสามารถลดขนาดภาพลงเหลือประมาณ 635MB (นี่เป็นค่าที่แสดงเป็นขนาดภาพเสมือนจริงหลังจากประมวลผลแล้วdocker images) เป็นไปได้ที่จะลบ / ลบ / ทำลายเลเยอร์เก่าเหล่านั้นหรือไม่ มีความเฉพาะเจาะจงมากขึ้น: ฉันต้องการลบภาพทั้งหมด (โดยอิงตามตัวอย่างของคุณ): 172743bd5d60, 3f2fed40e4b0, fd241224e9cf, 511136ea3c5a จากประวัติเพื่อให้ขนาดภาพเสมือนจริงของฉันน้อยลงเช่นเดียวกับขนาดภาพสุดท้ายที่นี่ ~ 260MB .
Zen

(ยาวเกินไปสำหรับความคิดเห็น 1 รายการ) ยกเว้นขนาดภาพเสมือนจริงไม่เกี่ยวกับขนาดภาพที่แท้จริงใน HDD? หากเป็นกรณีนี้จะตรวจสอบขนาดจริงของภาพได้อย่างไร?
Zen

คุณสามารถdocker exportแล้วdocker importอีกครั้ง นั่นจะทำให้เลเยอร์เรียบ ฉันไม่คิดว่ามันจะลดขนาด แต่ฉันอาจผิด
Andy

10
ใช่ แต่การส่งออกไม่ได้ช่วยอะไรมาก อย่างไรก็ตามฉันสามารถอ่านเว็บได้ว่าสิ่งที่ฉันสามารถสังเกตได้ใน Docker คือขนาดภาพเสมือนจริง ขนาดที่แท้จริงใน HDD ดูเหมือนว่าจะมีความลึกลับสำหรับฉันตั้งแต่ส่วนที่เกี่ยวกับข้อมูลอย่างเป็นทางการdocker ps -sแสดงให้เห็นว่าขนาดจริงบน HDD -1Bซึ่งในกรณีของผมก็คือ ว่าเสียงที่เหมาะสมลบ 1 ไบต์ ฉันได้รับพื้นที่บน HDD ... ดูเหมือนจะถูกต้อง
Zen

@ เซนขออภัยฉันไม่ได้ติดตาม ดังนั้นขนาดและขนาดของดิสก์เสมือนจึงแตกต่างกัน 2 อย่าง? ขนาดเสมือนจริงวัดได้อย่างไร?
เจสัน

63

ภาพนักเทียบท่าไม่ใหญ่คุณแค่สร้างภาพขนาดใหญ่

scratchภาพ 0B และคุณสามารถใช้ที่แพคเกจค่ารหัสของคุณถ้าคุณสามารถรวบรวมรหัสของคุณให้เป็นไบนารีแบบคงที่ ตัวอย่างเช่นคุณสามารถรวบรวมโปรแกรม Go ของคุณและจัดวางไว้ด้านบนของscratchเพื่อสร้างภาพที่ใช้งานได้อย่างเต็มที่ที่น้อยกว่า 5MB

กุญแจสำคัญคือการไม่ใช้ภาพ Docker อย่างเป็นทางการพวกมันใหญ่เกินไป การลบไม่ใช่สิ่งที่ใช้งานได้จริงดังนั้นฉันขอแนะนำให้ใช้ Alpine Linux เป็นอิมเมจพื้นฐานของคุณ มันคือ ~ 5MB จากนั้นเพิ่มเฉพาะสิ่งที่จำเป็นสำหรับแอปของคุณ โพสต์เกี่ยวกับMicrocontainersแสดงวิธีสร้างภาพขนาดเล็กมากบนอัลไพน์

อัปเดต: ภาพนักเทียบท่าอย่างเป็นทางการอ้างอิงจากอัลไพน์ในขณะนี้ดังนั้นจึงเหมาะที่จะใช้ในตอนนี้


2
ทางออกที่ดี! มันสำคัญมากที่จะหยุดการสูญเสียและรักษาความปลอดภัยให้มากขึ้น ---> รหัสน้อยลง -> กังวลน้อยลง
Ran Davidovitz

1
โชคดีที่ภาพ Docker Official กำลังเคลื่อนไหวเพื่อใช้ฐานอัลไพน์ดังนั้นคุณจึงสามารถใช้ภาพปกติได้มากขึ้นแทนที่จะขึ้นอยู่กับเวอร์ชันของ iron.io ดูbrianchristner.io/docker-is-moving-to-alpine-linux
Martijn Heemels

@ Travis R ลิงก์ของคุณเพื่อโพสต์เกี่ยวกับ microcontainers ดูเหมือนจะย้ายไปที่อื่นแล้ว คือนี้โพสต์ที่คุณหมายถึงการเชื่อมโยง?
Alexander F.

@AlexanderF ลิงก์ถาวรขอบคุณที่แจ้งให้เราทราบ
Travis Reeder

28

นี่คือสิ่งที่คุณสามารถทำได้เพิ่มเติม :

  • หลีกเลี่ยงRUNคำสั่งหลาย ๆ ตัวที่คุณสามารถทำได้ ใส่มากที่สุดเท่าที่เป็นไปได้ในRUNคำสั่งเดียว(โดยใช้&&)
  • ทำความสะอาดเครื่องมือที่ไม่จำเป็นเช่น wget หรือ git (ซึ่งคุณต้องการเพียงดาวน์โหลดหรือสร้างสิ่งต่าง ๆ แต่ไม่ต้องเรียกใช้กระบวนการของคุณ)

ด้วยสิ่งเหล่านี้ทั้งสองและคำแนะนำจาก @Andy และ @michau ฉันสามารถปรับขนาดอิมเมจของ nodejs จาก 1.062 GB เป็น 542 MB

แก้ไข: สิ่งหนึ่งที่สำคัญกว่า: "ฉันต้องใช้เวลาสักพักกว่าจะเข้าใจจริง ๆ ว่าคำสั่ง Dockerfile แต่ละคำสั่งจะสร้างคอนเทนเนอร์ใหม่ด้วย deltas [... ] ไม่สำคัญว่าคุณจะใช้ไฟล์ rm -rf ในคำสั่งในภายหลังหรือไม่ มันยังคงอยู่ในคอนเทนเนอร์ชั้นกลางบางอัน " ดังนั้นตอนนี้ฉันจัดการที่จะนำapt-get install, wget, npm install(ที่มีการอ้างอิงคอมไพล์) และapt-get removeเป็นหนึ่งRUNคำสั่งดังนั้นตอนนี้ภาพของฉันมีเพียง 438 MB

แก้ไข 29/06/17

ด้วย Docker v17.06 มีคุณสมบัติใหม่สำหรับ Dockerfiles: คุณสามารถมีหลายFROMประโยคใน Dockerfile เพียงไฟล์เดียวและสิ่งเดียวที่ผ่านมาFROMจะอยู่ในอิมเมจ Docker สุดท้ายของคุณ สิ่งนี้มีประโยชน์ในการลดขนาดรูปภาพเช่น:

FROM nodejs as builder
WORKDIR /var/my-project
RUN apt-get install ruby python git openssh gcc && \
    git clone my-project . && \
    npm install

FROM nodejs
COPY --from=builder /var/my-project /var/my-project

จะส่งผลให้อิมเมจมีเฉพาะอิมเมจพื้นฐาน nodejs รวมถึงเนื้อหาจาก / var / my-project จากขั้นตอนแรก - แต่ไม่มี ruby, python, git, openssh และ gcc!


22

ใช่ขนาดเหล่านั้นไร้สาระและฉันก็ไม่รู้จริงๆว่าทำไมคนไม่กี่คนถึงสังเกตว่า

ฉันสร้างรูป Ubuntu ที่มีขนาดเล็กที่สุด (ไม่เหมือนกับรูปอื่น ๆ ที่เรียกว่า "ขั้นต่ำ") มันถูกเรียกtextlab/ubuntu-essentialและมี 60 MB

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano

ภาพด้านบนคือ 82 MB หลังจากติดตั้งนาโน

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano git

Git มีสิ่งที่จำเป็นต้องมีเพิ่มเติมอีกมากมายดังนั้นภาพจึงใหญ่ขึ้นประมาณ 192 MB ยังน้อยกว่าขนาดเริ่มต้นของรูปภาพส่วนใหญ่

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


13

ต่อไปนี้ช่วยฉันได้มาก:

หลังจากลบแพ็กเกจที่ไม่ได้ใช้ (เช่น redis 1200 mb freed) ในคอนเทนเนอร์ของฉันฉันได้ทำสิ่งต่อไปนี้แล้ว:

  1. นักเทียบท่าส่งออก [containerID] -o containername.tar
  2. นักเทียบท่านำเข้า -m "ส่งข้อความที่นี่" containername.tar imagename: tag

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

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


คุณสามารถรวมขั้นตอนทั้งสองเป็นขั้นตอนเดียวdocker export <CONTAINER ID> | docker import - some-image-name:latest
Anuj Kumar

8

สำหรับแนวปฏิบัติที่ดีที่สุดคุณควรดำเนินการคำสั่ง RUN เดียวเนื่องจากคำสั่ง RUN ทุกคำสั่งใน Dockerfile เขียนเลเยอร์ใหม่ในภาพและทุกชั้นต้องการพื้นที่เพิ่มเติมบนดิสก์ เพื่อให้เลเยอร์ตัวเลขมีค่าน้อยที่สุดการจัดการไฟล์ใด ๆ เช่นการติดตั้งการย้ายการแยกการลบ ฯลฯ ควรทำภายใต้คำสั่ง RUN เดียว

FROM fedora:latest
RUN yum -y install nano git && yum -y clean all

4

Docker Squash เป็นทางออกที่ดีมากสำหรับเรื่องนี้ คุณสามารถ$packagemanager cleanในขั้นตอนสุดท้ายแทนที่จะเป็นในทุกบรรทัดแล้วเรียกใช้สควอชนักเทียบท่าเพื่อกำจัดเลเยอร์ทั้งหมด

https://github.com/jwilder/docker-squash


0

ใช่ระบบชั้นค่อนข้างน่าแปลกใจ หากคุณมีภาพฐานและคุณเพิ่มโดยทำดังต่อไปนี้:

# Test
#
# VERSION       1

# use the centos base image provided by dotCloud
FROM centos7/wildfly
MAINTAINER JohnDo 

# Build it with: docker build -t "centos7/test" test/

# Change user into root
USER root

# Extract weblogic
RUN rm -rf /tmp/* \
    && rm -rf /wildfly/* 

ภาพมีขนาดเท่ากันทุกประการ คุณต้องจัดการใส่ RUN ของคุณเป็นจำนวนมากแยก, ติดตั้งและล้างมายากลเพื่อทำให้ภาพมีขนาดเล็กเท่ากับซอฟต์แวร์ที่ติดตั้ง

ทำให้ชีวิตยากขึ้น ...

dockerBuild ขาดขั้นตอน RUN โดยไม่มีการส่ง

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