Docker hình ảnh các lớp thế giới là gì?


165

Tôi hoàn toàn mới với Docker và đang cố gắng hiểu chính xác hình ảnh Docker là gì. Mỗi định nghĩa duy nhất của hình ảnh Docker sử dụng thuật ngữ "lớp", nhưng dường như không định nghĩa được ý nghĩa của lớp .

Từ các tài liệu Docker chính thức :

Chúng ta đã thấy rằng hình ảnh Docker là các mẫu chỉ đọc từ đó các container Docker được khởi chạy. Mỗi hình ảnh bao gồm một loạt các lớp. Docker sử dụng các hệ thống tập tin hợp nhất để kết hợp các lớp này thành một hình ảnh duy nhất. Các hệ thống tệp liên minh cho phép các tệp và thư mục của các hệ thống tệp riêng biệt, được gọi là các nhánh, được phủ trong suốt, tạo thành một hệ thống tệp kết hợp duy nhất.

Vì vậy, tôi hỏi, một lớp (chính xác) là gì; ai đó có thể đưa ra một vài ví dụ cụ thể về họ? Và làm thế nào để các lớp này "chụp lại với nhau" để tạo thành một hình ảnh?

Câu trả lời:


132

Tôi có thể bị trễ, nhưng đây là 10 xu của tôi (bổ sung cho câu trả lời của ashishjain):

Về cơ bản, một lớp hoặc lớp hình ảnh là một sự thay đổi trên một hình ảnh, hoặc một hình ảnh trung gian . Mỗi lệnh bạn chỉ định ( FROM, RUN, COPY, vv) trong Dockerfile của bạn làm cho hình ảnh trước đó để thay đổi, do đó tạo ra một lớp mới. Bạn có thể coi đó là thay đổi theo giai đoạn khi bạn sử dụng git: Bạn thêm thay đổi của tệp, sau đó là một thay đổi khác ...

Hãy xem xét Dockerfile sau:

FROM rails:onbuild
ENV RAILS_ENV production
ENTRYPOINT ["bundle", "exec", "puma"]

Đầu tiên, chúng tôi chọn một hình ảnh bắt đầu : rails:onbuild, lần lượt có nhiều lớp . Chúng tôi thêm một lớp khác lên trên hình ảnh bắt đầu của chúng tôi, thiết lập biến môi trường RAILS_ENVbằng ENVlệnh. Sau đó, chúng tôi bảo docker chạy bundle exec puma(khởi động máy chủ rails). Đó là một lớp khác.

Khái niệm về các lớp có ích tại thời điểm xây dựng hình ảnh. Vì các lớp là hình ảnh trung gian, nếu bạn thực hiện thay đổi cho Dockerfile của mình, docker sẽ chỉ tạo lớp được thay đổi và các lớp sau đó. Điều này được gọi là bộ nhớ đệm lớp.

Bạn có thể đọc thêm về nó ở đây .


13
Nếu bạn thay đổi hoặc thêm một lớp, Docker cũng sẽ xây dựng bất kỳ lớp nào sau đó vì chúng có thể bị ảnh hưởng bởi thay đổi.
Adam

Cảm ơn đã giải thích lý do đằng sau khái niệm các lớp bị thiếu trong các câu trả lời khác.
Seeta Somagani

@David, trong ví dụ trên, có bao nhiêu lớp sẽ được thêm vào? 2? hay 1?
Gourav Singla

1
@GouravSingla Phải là 2. Thay đổi ENV cũng là một thay đổi. Có vẻ như lớp là cam kết của git.
PokerFace

Liên kết web cuối cùng ( https://labs.ctl.io/caching-docker-images/) bị hỏng. Bất cứ ai có đề nghị cho một sự thay thế?
Johnny Utahh

72

Một hình ảnh container docker được tạo bằng cách sử dụng một dockerfile . Mỗi dòng trong một dockerfile sẽ tạo ra một lớp. Hãy xem xét ví dụ giả sau:

FROM ubuntu             #This has its own number of layers say "X"
MAINTAINER FOO          #This is one layer 
RUN mkdir /tmp/foo      #This is one layer 
RUN apt-get install vim #This is one layer 

Điều này sẽ tạo ra một hình ảnh cuối cùng trong đó tổng số lớp sẽ là X + 3


32
Trong khi tôi không downvote, tôi đoán sẽ là điều này giải thích làm thế nào để tạo ra các lớp, nhưng không theo cách không trả lời những câu hỏi về những gì một lớp là.
Lasse V. Karlsen

2
Tôi đồng ý với @ LasseV.Karlsen, ashishjain. Tôi đã không đánh giá cao bạn và thực tế là bạn ủng hộ bạn vì đã cố gắng giúp tôi (nên +1) - nhưng để tôi có thể đưa cho bạn tấm séc màu xanh lá cây, tôi cần phải hiểu một lớp thực sự là gì! Cảm ơn một lần nữa, tiếp tục đi!
smeeb 04/07/2015

3
câu trả lời tốt nhất imo. đối với nhiều người trong chúng ta chuyển sang "sử dụng docker", nó cho chúng ta ý chính về cách các lớp hoạt động.
dtc

6
"Mỗi dòng trong một dockerfile sẽ tạo ra một lớp" - điều này rất hữu ích cho tôi biết
akirekadu

2
@akirekadu Đó không phải là câu chuyện đầy đủ. Hầu hết các dòng sẽ tạo một lớp, nhưng chỉ các lệnh ADD, COPY hoặc RUN sẽ tạo các lớp làm tăng kích thước của hình ảnh chứa kết quả. Tôi đã nói hầu hết các dòng bởi vì nếu bạn xâu chuỗi các lệnh lại với nhau hoặc thoát các dòng mới bằng dấu gạch chéo ngược, chuỗi các lệnh được xâu chuỗi / các dòng mới thoát sẽ tạo thành một lệnh duy nhất.
Scott Simontis

41

Họ có ý nghĩa nhất với tôi bằng một ví dụ ...

Kiểm tra các lớp của bản dựng của riêng bạn với docker diff

Hãy lấy một ví dụ giả định 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

Mỗi ddlệnh đó xuất ra tệp 1M vào đĩa. Cho phép xây dựng hình ảnh với một cờ phụ để lưu các thùng chứa tạm thời:

docker image build --rm=false .

Trong đầu ra, bạn sẽ thấy từng lệnh đang chạy xảy ra trong một thùng chứa tạm thời mà chúng ta hiện giữ thay vì tự động xóa:

...
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

Nếu bạn chạy một docker difftrên mỗi id của các container đó, bạn sẽ thấy các tệp được tạo trong các container đó:

$ 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

Mỗi dòng có tiền tố Alà thêm tệp, Cdấu hiệu cho biết thay đổi đối với tệp hiện có và Dbiểu thị xóa.

Đây là phần TL; DR

Mỗi hệ thống tập tin chứa khác nhau ở trên đi vào một "lớp" được lắp ráp khi bạn chạy hình ảnh dưới dạng một thùng chứa. Toàn bộ tệp nằm trong mỗi lớp khi có thêm hoặc thay đổi, do đó, mỗi chmodlệnh đó, mặc dù chỉ thay đổi một bit quyền, dẫn đến toàn bộ tệp được sao chép vào lớp tiếp theo. Thực tế, tệp đã bị xóa / dữ liệu / một vẫn ở các lớp trước đó, thực tế là 3 lần và sẽ được sao chép qua mạng và được lưu trên đĩa khi bạn kéo hình ảnh.

Kiểm tra hình ảnh hiện có

Bạn có thể thấy các lệnh đi vào việc tạo các lớp của một hình ảnh hiện có bằng docker historylệnh. Bạn cũng có thể chạy mộtdocker image inspect hình ảnh và xem danh sách các lớp trong phần RootFS.

Đây là lịch sử cho hình ảnh trên:

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

Các lớp mới nhất được liệt kê trên đầu trang. Đáng chú ý, có hai lớp ở phía dưới khá cũ. Họ đến từ chính hình ảnh busybox. Khi bạn xây dựng một hình ảnh, bạn kế thừa tất cả các lớp của hình ảnh bạn chỉ định trong FROMdòng. Ngoài ra còn có các lớp được thêm vào để thay đổi dữ liệu meta hình ảnh, như CMDdòng. Chúng hầu như không chiếm bất kỳ dung lượng nào và nhiều hơn cho việc lưu giữ hồ sơ về những cài đặt nào áp dụng cho hình ảnh bạn đang chạy.

Tại sao lớp?

Các lớp có một vài lợi thế. Đầu tiên, họ là bất biến. Khi được tạo, lớp đó được xác định bởi hàm băm sha256 sẽ không bao giờ thay đổi. Sự bất biến đó cho phép hình ảnh xây dựng và tách rời nhau một cách an toàn. Nếu hai dockerfile có cùng một bộ dòng ban đầu và được xây dựng trên cùng một máy chủ, chúng sẽ chia sẻ cùng một bộ các lớp ban đầu, tiết kiệm không gian đĩa. Điều đó cũng có nghĩa là nếu bạn xây dựng lại một hình ảnh, chỉ với vài dòng cuối cùng của Dockerfile gặp phải thay đổi, chỉ những lớp đó cần được xây dựng lại và phần còn lại có thể được sử dụng lại từ bộ đệm của lớp. Điều này có thể làm cho việc xây dựng lại hình ảnh docker rất nhanh.

Trong một thùng chứa, bạn thấy hệ thống tệp hình ảnh, nhưng hệ thống tệp đó không được sao chép. Trên các lớp hình ảnh đó, thùng chứa gắn kết lớp hệ thống tệp đọc-ghi của chính nó. Mỗi lần đọc tệp đi qua các lớp cho đến khi nó chạm vào một lớp đã đánh dấu tệp để xóa, có một bản sao của tệp trong lớp đó hoặc đọc hết lớp để tìm kiếm. Mỗi ghi làm cho một sửa đổi trong lớp đọc-ghi cụ thể của container.

Giảm phồng lớp

Một nhược điểm của các lớp là xây dựng hình ảnh trùng lặp các tệp hoặc gửi các tệp bị xóa trong lớp sau. Giải pháp thường là hợp nhất nhiều lệnh thành một RUNlệnh duy nhất . Đặc biệt khi bạn sửa đổi các tệp hiện có hoặc xóa các tệp, bạn muốn các bước đó chạy trong cùng một lệnh nơi chúng được tạo lần đầu tiên. Một bản viết lại của Dockerfile ở trên sẽ trông như sau:

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

Và nếu bạn so sánh các hình ảnh kết quả:

  • bận rộn: ~ 1MB
  • hình ảnh đầu tiên: ~ 6MB
  • hình ảnh thứ hai: ~ 2MB

Chỉ bằng cách hợp nhất một số dòng trong ví dụ giả định, chúng tôi đã có cùng một nội dung kết quả trong hình ảnh của chúng tôi và thu nhỏ hình ảnh của chúng tôi từ 5MB xuống chỉ còn tệp 1 MB mà bạn nhìn thấy trong hình ảnh cuối cùng.


Di chuyển các lớp trong quá trình đọc tập tin đòi hỏi một số chi phí, phải không? Để tiết kiệm chi phí đó, việc kết hợp nhiều lệnh (cần phải được thực thi cùng nhau) trong một RUN có hợp lý không?
SergiyKolesnikov

@SergiyKolesnikov phụ thuộc vào thời gian bạn muốn dành tối ưu hóa sớm. Rủi ro là dành hàng giờ thời gian của nhà phát triển, hợp đồng thêm băng thông và lưu trữ, để tiết kiệm mili giây của thời gian chạy. Cũng như nhiều thứ liên quan đến hiệu suất, có những điều cực đoan, và cần phải đo lường vấn đề trước khi nỗ lực khắc phục nó.
BMitch

19

Kể từ Docker v1.10, với việc giới thiệu bộ lưu trữ địa chỉ nội dung, khái niệm 'lớp' trở nên khá khác biệt. Các lớp không có khái niệm về một hình ảnh hoặc thuộc về một hình ảnh, chúng chỉ trở thành các bộ sưu tập các tệp và thư mục có thể được chia sẻ trên các hình ảnh. Các lớp và hình ảnh trở nên tách biệt.

Ví dụ, trên một hình ảnh được xây dựng tại địa phương từ một hình ảnh cơ bản, chúng ta hãy nói, ubuntu:14.04thì docker historylệnh mang lại chuỗi hình ảnh, nhưng một số ID hình ảnh sẽ được hiển thị như 'mất tích' vì lịch sử xây dựng không còn được nạp. Và các lớp tạo ra những hình ảnh này có thể được tìm thấy thông qua

docker inspect <image_id> | jq -r '.[].RootFS'

Nội dung lớp được lưu trữ tại /var/lib/docker/aufs/diffnếu lựa chọn trình điều khiển lưu trữ là aufs. Nhưng các lớp được đặt tên với ID bộ đệm được tạo ngẫu nhiên, có vẻ như liên kết giữa một lớp và ID bộ đệm của nó chỉ được biết đến với Docker Engine vì lý do bảo mật. Tôi vẫn đang tìm cách để tìm hiểu

  1. Mối quan hệ tương ứng giữa một hình ảnh và (các) lớp sáng tác của nó
  2. Vị trí thực tế và kích thước của một lớp trên đĩa

Blog này cung cấp nhiều cái nhìn sâu sắc.


Trong mục SO này tôi đã đăng một cách khá ngây thơ để trả lời hai câu hỏi tôi đã đăng.
Ruifeng Ma

13

Thông số hình ảnh của mỗi Docker thông qua Dự án Moby :

Hình ảnh bao gồm các lớp. Mỗi lớp là một tập hợp các thay đổi hệ thống tập tin. Các lớp không có siêu dữ liệu cấu hình như biến môi trường hoặc đối số mặc định - đây là các thuộc tính của toàn bộ hình ảnh thay vì bất kỳ lớp cụ thể nào.

Vì vậy, về cơ bản, một lớp chỉ là một tập hợp các thay đổi được thực hiện cho hệ thống tập tin.


Tôi chỉ mất vài giờ để tìm thấy nó, nhưng với câu trả lời đơn giản thanh lịch này, cuối cùng tôi cũng hiểu một lớp là gì: "Each [Docker] layer is a set of filesystem changes."(Giả sử điều này là đúng.) Vì một số lý do tôi không hiểu được điểm cơ bản này khi đọc nhiều tài liệu khác / blog / Q + A's / etc, và tôi nghi ngờ giới hạn là của họ chứ không phải của tôi. Bất kể, bravo Aditya để đi vào trọng tâm của vấn đề.
Johnny Utahh

12

Tôi nghĩ rằng tài liệu chính thức đưa ra một lời giải thích khá chi tiết: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/ .


(nguồn: docker.com )

Một hình ảnh bao gồm nhiều lớp thường được tạo từ Dockerfile, mỗi dòng trong Dockerfile sẽ tạo ra một lớp mới và kết quả là một hình ảnh, được biểu thị bằng biểu mẫu repo:tag, như thế nào ubuntu:15.04.

Để biết thêm thông tin, xin vui lòng xem xét việc đọc các tài liệu chính thức ở trên.


2

Cảm ơn bạn @David Castillo vì thông tin hữu ích . Tôi nghĩ rằng lớp là một số thay đổi nhị phân hoặc hướng dẫn của một hình ảnh có thể được thực hiện hoặc hoàn tác dễ dàng. Chúng được thực hiện từng bước giống như một lớp trên một lớp, vì vậy chúng tôi gọi là "lớp".

Để biết thêm thông tin, bạn có thể xem "lịch sử docker" như thế này:

hình ảnh docker --tree
Cảnh báo: '--tree' không được dùng nữa, nó sẽ bị xóa sớm. Xem cách sử dụng.
└─511136ea3c5a Kích thước ảo: 0 B Thẻ: Scratch: mới nhất
  └─59e359cb35ef Kích thước ảo: 85,18 MB
    └─e8d37d9e3476 Kích thước ảo: 85,18 MB Thẻ: debian: wheezy
      └─c58b36b8f285 Kích thước ảo: 85,18 MB
        └─90ea6e05b074 Kích thước ảo: 118,6 MB
          └─5dc74cffc471 Kích thước ảo: 118,6 MB Thẻ: vim: mới nhất


5
đã tìm thấy thông tin mới về các lớp : Khi Docker gắn kết rootfs, nó bắt đầu chỉ đọc, như trong một khởi động Linux truyền thống, nhưng sau đó, thay vì thay đổi hệ thống tệp thành chế độ đọc-ghi, nó tận dụng lợi thế của mount mount để thêm một hệ thống tệp đọc-ghi trên hệ thống tệp chỉ đọc. Trong thực tế, có thể có nhiều hệ thống tệp chỉ đọc được xếp chồng lên nhau. Chúng tôi nghĩ rằng mỗi một trong những hệ thống tập tin này là một lớp .
hiproz 3/03/2016

1

Hiểu biết cá nhân của tôi là chúng ta có thể so sánh lớp docker với cam kết github. Đối với hình ảnh cơ sở của bạn (repo chính mới của bạn), bạn thực hiện một số cam kết, mọi cam kết đều thay đổi trạng thái chính của bạn, nó giống nhau trong docker, mỗi lớp đang thực hiện một số thao tác dựa trên lớp trung gian trước đó. Và sau đó, lớp này trở thành lớp trung gian mới cho lớp tiếp theo.


0

Tôi đã từng nghĩ rằng chúng giống như khác biệt trên các lớp trước. Sau khi đọc một số câu trả lời ở đây, tôi không chắc lắm; chúng được mô tả như là tập hợp các thay đổi đối với hệ thống tập tin . Tôi đã viết một số Dockerfiles để cho thấy chúng giống diff hơn, nghĩa là chúng thực sự phụ thuộc vào các lớp trước đó.

Cho hai Dockerfiles này

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one

người ta sẽ mong đợi một tập hợp các lớp giống nhau nếu chúng chỉ là về những thay đổi đối với hệ thống tập tin, nhưng đây không phải là trường hợp:

$ docker history img_1
IMAGE               CREATED             CREATED BY                                      SIZE
30daa166a9c5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
4467d16e79f5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
c299561fd031        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

$ docker history img_2
IMAGE               CREATED             CREATED BY                                      SIZE
f55c91305f8c        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
29b3b627c76f        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
18360be603aa        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

Bạn có thể thấy làm thế nào, ngay cả khi các thay đổi đối với hệ thống tập tin giống nhau trong cả hai trường hợp, thứ tự quan trọng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.