Apa itu "lapisan" gambar Docker?

165

Saya baru mengenal Docker dan berusaha memahami apa sebenarnya gambar Docker . Setiap definisi tunggal dari gambar Docker menggunakan istilah "layer", tetapi tampaknya tidak mendefinisikan apa yang dimaksud dengan layer .

Dari dokumen Docker resmi :

Kita telah melihat bahwa gambar Docker adalah templat hanya-baca dari mana wadah Docker diluncurkan. Setiap gambar terdiri dari serangkaian lapisan. Docker menggunakan sistem file gabungan untuk menggabungkan lapisan-lapisan ini menjadi satu gambar. Sistem file Union memungkinkan file dan direktori sistem file terpisah, yang dikenal sebagai cabang, untuk ditindih secara transparan, membentuk sistem file koheren tunggal.

Jadi saya bertanya, apa itu layer (tepatnya); dapatkah seseorang memberikan beberapa contoh nyata tentang hal itu? Dan bagaimana lapisan-lapisan ini "bersatu" untuk membentuk suatu gambar?

smeeb
sumber

Jawaban:

133

Saya mungkin terlambat, tapi inilah 10 sen saya (melengkapi jawaban ashishjain):

Pada dasarnya, layer, atau layer gambar adalah perubahan pada gambar, atau gambar perantara . Setiap perintah yang Anda tentukan ( FROM, RUN, COPY, dll) di Dockerfile Anda menyebabkan gambar sebelumnya perubahan, sehingga menciptakan layer baru. Anda dapat menganggapnya sebagai pementasan perubahan saat Anda menggunakan git: Anda menambahkan perubahan file, lalu yang lain, lalu yang lain ...

Pertimbangkan Dockerfile berikut:

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

Pertama, kami memilih gambar awal:, rails:onbuildyang pada gilirannya memiliki banyak lapisan . Kami menambahkan layer lain di atas gambar awal kami, mengatur variabel lingkungan RAILS_ENVdengan ENVperintah. Kemudian, kami meminta buruh pelabuhan untuk menjalankan bundle exec puma(yang menjalankan server rails). Itu lapisan lain.

Konsep lapisan sangat berguna pada saat membangun gambar. Karena layer adalah gambar perantara, jika Anda melakukan perubahan pada Dockerfile Anda, docker hanya akan membuat layer yang diubah dan yang setelahnya. Ini disebut layer caching.

Anda dapat membaca lebih lanjut di sini .

David Castillo
sumber
13
Jika Anda mengubah atau menambahkan lapisan, Docker juga akan membuat lapisan apa pun yang datang sesudahnya karena mereka mungkin akan terpengaruh oleh perubahan tersebut.
Adam
Terima kasih telah menjelaskan alasan di balik konsep lapisan yang hilang dari jawaban lain.
Seeta Somagani
@ David, dalam contoh di atas, berapa banyak layer yang akan ditambahkan? 2? atau 1?
Gourav Singla
1
@GouravSingla Seharusnya 2. Ubah ENV juga merupakan perubahan. Sepertinya layer adalah komit dari git.
PokerFace
Tautan web terakhir ( https://labs.ctl.io/caching-docker-images/) rusak. Adakah yang punya saran untuk pengganti?
Johnny Utahh
72

Gambar container docker dibuat menggunakan dockerfile . Setiap baris di dockerfile akan membuat layer. Pertimbangkan contoh boneka berikut:

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 

Ini akan membuat gambar akhir di mana jumlah total layer akan menjadi X + 3

ashishjain
sumber
32
Meskipun saya tidak melakukan downvote, dugaan saya adalah ini menjelaskan cara membuat layer, tetapi tidak menjawab pertanyaan tentang apa itu layer.
Lasse V. Karlsen
2
Saya setuju dengan @ LasseV.Karlsen, ashishjain. Saya tidak menurunkan Anda dan saya malah membuat Anda tidak setuju karena mencoba membantu saya (jadi +1) - tetapi agar saya dapat memberi Anda cek hijau, saya perlu memahami apa sebenarnya lapisan itu! Sekali lagi terima kasih, teruskan!
smeeb
3
jawaban terbaik imo. bagi banyak dari kita yang pindah ke "memanfaatkan buruh pelabuhan", itu memberi kita inti bagaimana lapisan bekerja.
dtc
6
"Setiap baris di dockerfile akan membuat layer" - ini sangat membantu saya untuk mengetahui
akirekadu
2
@akirekadu Itu bukan cerita lengkapnya. Sebagian besar garis akan membuat layer, tetapi hanya instruksi ADD, COPY atau RUN yang akan membuat layer yang meningkatkan ukuran gambar kontainer yang dihasilkan. Saya mengatakan sebagian besar baris karena jika Anda rantai bersama perintah, atau melarikan diri baris baru dengan garis miring terbalik, urutan perintah dirantai / lolos baris baru akan membentuk satu perintah.
Scott Simontis
41

Mereka paling masuk akal bagi saya dengan contoh ...

Memeriksa lapisan bangunan Anda sendiri dengan docker diff

Mari kita ambil contoh buatan 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

Masing-masing ddperintah menghasilkan file 1M ke disk. Mari kita membangun gambar dengan bendera tambahan untuk menyimpan wadah sementara:

docker image build --rm=false .

Dalam output, Anda akan melihat masing-masing perintah yang berjalan terjadi dalam wadah sementara yang sekarang kami simpan alih-alih dihapus secara otomatis:

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

Jika Anda menjalankan docker diffmasing-masing id wadah itu, Anda akan melihat file apa yang dibuat dalam wadah itu:

$ 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

Setiap baris diawali dengan Amenambahkan file, Cmenunjukkan perubahan ke file yang ada, dan Dmenunjukkan penghapusan.

Inilah bagian TL; DR

Masing-masing dari sistem berkas wadah di atas masuk ke dalam satu "lapisan" yang akan dirakit ketika Anda menjalankan gambar sebagai wadah. Seluruh file ada di setiap lapisan saat ada penambahan atau perubahan, sehingga setiap chmodperintah itu, meskipun hanya mengubah sedikit izin, menghasilkan seluruh file yang disalin ke lapisan berikutnya. File yang dihapus / data / satu masih di lapisan sebelumnya, sebenarnya 3 kali, dan akan disalin melalui jaringan dan disimpan dalam disk ketika Anda menarik gambar.

Meneliti gambar yang ada

Anda dapat melihat perintah yang digunakan untuk membuat lapisan gambar yang ada dengan docker historyperintah. Anda juga dapat menjalankan a docker image inspectpada gambar dan melihat daftar lapisan di bawah bagian RootFS.

Inilah sejarah untuk gambar di atas:

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

Lapisan terbaru tercantum di atas. Yang perlu diperhatikan, ada dua lapisan di bagian bawah yang cukup tua. Mereka berasal dari gambar busybox itu sendiri. Saat Anda membangun satu gambar, Anda mewarisi semua lapisan gambar yang Anda tentukan di FROMbaris. Ada juga lapisan yang ditambahkan untuk perubahan pada meta-data gambar, seperti CMDgaris. Mereka hampir tidak mengambil ruang apa pun dan lebih untuk menyimpan pengaturan apa yang berlaku untuk gambar yang Anda jalankan.

Mengapa lapisan?

Lapisan memiliki beberapa keunggulan. Pertama, mereka tidak berubah. Setelah dibuat, lapisan yang diidentifikasi oleh hasa sha256 tidak akan pernah berubah. Kekekalan itu memungkinkan gambar saling membangun dan memotong dengan aman. Jika dua dockerfiles memiliki himpunan garis awal yang sama, dan dibangun pada server yang sama, mereka akan berbagi himpunan lapisan awal yang sama, menghemat ruang disk. Itu juga berarti jika Anda membangun kembali gambar, dengan hanya beberapa baris terakhir Dockerfile mengalami perubahan, hanya lapisan-lapisan yang perlu dibangun kembali dan sisanya dapat digunakan kembali dari cache lapisan. Ini dapat membuat pembangunan kembali gambar buruh pelabuhan sangat cepat.

Di dalam sebuah wadah, Anda melihat sistem file gambar, tetapi sistem file itu tidak disalin. Di atas semua layer gambar itu, container me-mount sendiri layer sistem file read-write. Setiap pembacaan file turun melalui lapisan sampai menyentuh lapisan yang telah menandai file untuk dihapus, memiliki salinan file di lapisan itu, atau membaca kehabisan lapisan untuk mencari. Setiap tulisan membuat modifikasi dalam lapisan baca-tulis khusus wadah.

Mengurangi lapisan kembung

Salah satu kelemahan lapisan adalah membangun gambar yang menduplikasi file atau mengirim file yang dihapus di lapisan selanjutnya. Solusinya adalah sering menggabungkan beberapa perintah menjadi satu RUNperintah. Khususnya ketika Anda memodifikasi file yang sudah ada atau menghapus file, Anda ingin langkah-langkah tersebut berjalan di perintah yang sama di mana mereka pertama kali dibuat. Menulis ulang Dockerfile di atas akan terlihat seperti:

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

Dan jika Anda membandingkan gambar yang dihasilkan:

  • busybox: ~ 1MB
  • gambar pertama: ~ 6MB
  • gambar kedua: ~ 2MB

Hanya dengan menggabungkan beberapa baris dalam contoh yang dibuat, kami mendapatkan konten yang dihasilkan sama di gambar kami, dan menyusut gambar kami dari 5MB menjadi hanya 1MB file yang Anda lihat di gambar akhir.

BMitch
sumber
Melintasi lapisan selama membaca file memerlukan beberapa overhead, bukan? Untuk menyimpan overhead itu, apakah masuk akal untuk menggabungkan beberapa perintah (yang perlu dieksekusi bersama-sama) dalam satu RUN?
SergiyKolesnikov
@SergiyKolesnikov tergantung pada berapa banyak waktu yang Anda ingin optimalkan secara prematur. Risikonya adalah menghabiskan berjam-jam waktu pengembang, pertunjukan bandwidth dan penyimpanan tambahan, untuk menghemat runtime milidetik. Seperti banyak hal terkait kinerja, ada yang ekstrem, dan ada kebutuhan untuk mengukur masalah sebelum berupaya memperbaikinya.
BMitch
19

Sejak Docker v1.10, dengan pengenalan penyimpanan yang dapat dialamatkan konten, gagasan 'lapisan' menjadi sangat berbeda. Lapisan tidak memiliki gagasan tentang suatu gambar atau milik suatu gambar, mereka hanya menjadi kumpulan file dan direktori yang dapat dibagikan di seluruh gambar. Lapisan dan gambar menjadi terpisah.

Sebagai contoh, pada gambar lokal dibangun dari gambar dasar, katakanlah, ubuntu:14.04, yang docker historyperintah menghasilkan rantai gambar, tetapi beberapa ID gambar akan ditampilkan sebagai 'hilang' karena sejarah membangun tidak lagi dimuat. Dan lapisan-lapisan yang menyusun gambar-gambar ini dapat ditemukan melalui

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

Konten lapisan disimpan di /var/lib/docker/aufs/diffjika pemilihan driver penyimpanan aufs. Tetapi layer-layer tersebut dinamai dengan ID cache yang dibuat secara acak, tampaknya tautan antara layer dan ID cache-nya hanya diketahui oleh Docker Engine karena alasan keamanan. Saya masih mencari cara untuk mencari tahu

  1. Hubungan yang sesuai antara gambar dan lapisan penyusunnya
  2. Lokasi aktual dan ukuran lapisan pada disk

Blog ini memberikan banyak wawasan.

Ruifeng Ma
sumber
Dalam entri SO ini saya memposting cara yang agak naif untuk menjawab dua pertanyaan yang saya posting.
Ruifeng Ma
13

Per spesifikasi gambar Docker melalui The Moby Project :

Gambar terdiri dari beberapa lapisan. Setiap lapisan adalah sekumpulan perubahan sistem file. Lapisan tidak memiliki metadata konfigurasi seperti variabel lingkungan atau argumen default - ini adalah properti gambar secara keseluruhan daripada lapisan tertentu.

Jadi, pada dasarnya, layer hanyalah sekumpulan perubahan yang dibuat pada sistem file.

Aditya Patawari
sumber
Saya hanya butuh beberapa jam untuk menemukannya, tetapi dengan jawaban yang sederhana dan elegan ini, saya akhirnya mengerti apa itu layer: "Each [Docker] layer is a set of filesystem changes."(Dengan asumsi ini benar.) Untuk beberapa alasan saya tidak mengerti poin mendasar ini ketika membaca banyak dokumen lain / blog / Q + A's / etc, dan saya curiga keterbatasannya adalah milik mereka dan bukan milik saya. Apapun, bravo Aditya untuk sampai ke inti permasalahan.
Johnny Utahh
12

Saya pikir dokumen resmi memberikan penjelasan yang cukup rinci: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/ .


(sumber: docker.com )

Gambar terdiri dari banyak lapisan yang biasanya dihasilkan dari Dockerfile, setiap baris di Dockerfile akan membuat layer baru, dan hasilnya adalah gambar, yang dilambangkan dengan bentuk repo:tag, seperti ubuntu:15.04.

Untuk informasi lebih lanjut, silakan baca dokumen resmi di atas.

cizixs
sumber
2

Terima kasih @ David Castillo untuk informasi yang bermanfaat . Saya pikir layer adalah beberapa perubahan biner atau instruksi dari suatu gambar yang dapat dilakukan atau dibatalkan dengan mudah. Mereka dilakukan langkah demi langkah yang sama dengan layer pada layer, jadi kami menyebutnya "layer".

Untuk informasi lebih lanjut, Anda dapat melihat "riwayat buruh pelabuhan" seperti ini:

gambar buruh pelabuhan - pohon
Peringatan: '--tree' sudah usang, ini akan segera dihapus. Lihat penggunaan.
└─511136ea3c5a Ukuran Virtual: 0 B Tag: awal: terbaru
  └─59e359cb35ef Ukuran Virtual: 85.18 MB
    └─e8d37d9e3476 Ukuran Virtual: 85.18 MB Tag: debian: wheezy
      └─c58b36b8f285 Ukuran Virtual: 85.18 MB
        └─90ea6e05b074 Ukuran Virtual: 118,6 MB
          └─5dc74cffc471 Ukuran Virtual: 118,6 MB Tag: vim: terbaru

hiproz
sumber
5
menemukan informasi baru tentang lapisan : Ketika Docker me-mount rootfs, ia mulai read-only, seperti pada boot Linux tradisional, tetapi kemudian, alih-alih mengubah sistem file ke mode baca-tulis, ia mengambil keuntungan dari mount union untuk menambahkan sistem file baca-tulis di atas sistem file read-only. Bahkan mungkin ada beberapa sistem file read-only yang ditumpuk satu sama lain. Kami menganggap masing-masing sistem file ini sebagai layer .
hiproz
1

Pemahaman pribadi saya adalah bahwa kita dapat membandingkan layer docker dengan github commit. Untuk gambar dasar Anda (repo master baru Anda), Anda membuat beberapa komit, setiap komit mengubah status master Anda, itu sama di buruh pelabuhan, setiap lapisan melakukan beberapa operasi berdasarkan pada lapisan menengah sebelumnya. Dan kemudian, lapisan ini menjadi lapisan menengah baru ke lapisan berikutnya.

KevinZhou
sumber
0

Saya dulu berpikir mereka seperti diff pada lapisan sebelumnya. Setelah membaca beberapa jawaban di sini saya tidak begitu yakin; mereka digambarkan sebagai set perubahan ke sistem file . Saya telah menulis beberapa Dockerfiles untuk menunjukkan mereka lebih seperti diff, yaitu, mereka benar-benar bergantung pada layer sebelumnya.

Diberi dua Dockerfiles ini

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

dan

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

orang akan mengharapkan lapisan yang sama jika mereka hanya tentang perubahan pada sistem file, tetapi ini tidak terjadi:

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

dan

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

Anda dapat melihat caranya, meskipun perubahan pada sistem file sama dalam kedua kasus, urutannya penting.

olepinto
sumber