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 dd
lệ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 diff
trê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ố A
là thêm tệp, C
dấu hiệu cho biết thay đổi đối với tệp hiện có và D
biể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 chmod
lệ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 history
lệ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 FROM
dò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ư CMD
dò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 RUN
lệ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.