Docker görüntü “katmanları” nedir?


165

Docker'da yeniyim ve bir Docker görüntüsünün tam olarak ne olduğunu anlamaya çalışıyorum . Docker görüntüsünün her bir tanımı "katman" terimini kullanır, ancak katman tarafından ne kastedildiğini tanımlamaz .

Resmi Docker belgelerinden :

Docker görüntülerinin Docker kapsayıcılarının başlatıldığı salt okunur şablonlar olduğunu zaten gördük. Her görüntü bir dizi katmandan oluşur. Docker, bu katmanları tek bir görüntüde birleştirmek için birleşim dosya sistemlerini kullanır. Birlik dosya sistemleri, dallar olarak bilinen ayrı dosya sistemlerinin dosyalarının ve dizinlerinin şeffaf bir şekilde üst üste binmesine izin vererek tek bir tutarlı dosya sistemi oluşturur.

Bu yüzden, bir katman (tam olarak) nedir diye soruyorum; birisi bunlardan birkaç somut örnek verebilir mi? Ve bu katmanlar bir görüntü oluşturmak için nasıl "birbirine yapışır"?

Yanıtlar:


133

Geç kalabilirim, ama işte 10 sentim (ashishjain'in cevabını tamamlıyor):

Temel olarak, bir katman veya görüntü katmanı görüntü veya ara görüntüdeki bir değişikliktir . Belirttiğiniz Her komut ( FROM, RUN,COPY senin Dockerfile içinde, vs.) böylece yeni bir katman oluşturarak, değişime önceki resmi neden olur. Git'i kullanırken bunu aşamalandırma değişiklikleri olarak düşünebilirsiniz: Bir dosya değişikliği, sonra başka bir değişiklik, sonra başka bir değişiklik ekleyin ...

Aşağıdaki Dockerfile dosyasını göz önünde bulundurun:

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

İlk olarak, bir başlangıç ​​resmi seçiyoruz: rails:onbuildsırayla birçok katmanı var . Biz ortam değişkeni, bizim başlangıç görüntünün üstünde bir katman eklemek RAILS_ENVile ENVkomuta. Ardından, docker'a bundle exec puma(raylar sunucusunu başlatan) çalışmasını söyleriz . Bu başka bir katman.

Katman kavramı, görüntü oluştururken işe yarar. Katmanlar ara görüntüler olduğundan, Dockerfile dosyasında bir değişiklik yaparsanız, docker yalnızca değiştirilen katmanı ve bundan sonraki katmanları oluşturur. Buna katman önbellekleme denir.

Burada daha fazla bilgi edinebilirsiniz .


13
Bir katmanı değiştirir veya eklerseniz Docker, değişiklikten etkilenebileceği için daha sonra gelen katmanları da oluşturur.
Adam

Diğer cevaplardan eksik olan katmanlar kavramının ardındaki nedeni açıkladığınız için teşekkür ederiz.
Seeta Somagani

@David, yukarıdaki örnekte kaç katman eklenecek? 2? veya 1?
Gourav Singla

1
@GouravSingla 2 olmalıdır. Değişim ENV aynı zamanda bir değişikliktir. Katmanın git taahhüdü olduğu anlaşılıyor.
PokerFace

Son web bağlantısı ( https://labs.ctl.io/caching-docker-images/) bozuk. Değiştirilmesi için önerileriniz var mı?
Johnny Utahh

72

Bir docker kapsayıcısı görüntüsü, bir dockerfile kullanılarak oluşturulur . Bir dockerfile dosyasındaki her satır bir katman oluşturur. Aşağıdaki kukla örneği ele alalım:

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 

Bu, toplam katman sayısının X + 3 olacağı bir son görüntü oluşturur


32
Ben yoksaydım, tahminim bu katmanların nasıl oluşturulacağını açıklar , ancak hiçbir şekilde bir katmanın ne olduğu sorusunu cevaplamaz .
Lasse V. Karlsen

2
@ LasseV.Karlsen, ashishjain ile aynı fikirdeyim. Seni küçümsemedim ve aslında bana yardım etmeye çalıştığın için (yani +1) - ama sana yeşil onay verebilmem için, bir katmanın gerçekte ne olduğunu anlamam gerekiyor! Tekrar teşekkürler, devam et!
smeeb

3
en iyi cevap imo. "liman işçisini kullanarak" hareket eden birçoğumuz için, bize katmanların nasıl çalıştığının özünü veriyor.
dtc

6
"Bir dockerfile her satır bir katman oluşturacak" - bu benim için çok yararlı oldu
akirekadu

2
@akirekadu Hikayenin tamamı bu değil. Çoğu satır bir katman oluşturur, ancak yalnızca ADD, COPY veya RUN talimatları sonuçta elde edilen kap görüntüsünün boyutunu artıran katmanlar oluşturur. Çoğu satýr dedim çünkü komutlarý birbirine zincirleþtirirseniz veya ters eğik çizgi ile yeni satýrlardan kaçarsanýz, zincirleme komutlar / kaçýlan yeni satırlarýn tek bir komut oluþturmasýný saðlar.
Scott Simontis

41

Bir örnekle bana en mantıklı ...

Docker diff ile kendi yapınızın katmanlarını inceleme

Dockerfile için örnek bir örnek alalım:

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

Bu ddkomutların her biri diske 1M dosyası verir. Geçici kapsayıcıları kaydetmek için görüntüyü fazladan bir bayrakla oluşturalım:

docker image build --rm=false .

Çıktıda, çalışan komutların her birinin şimdi otomatik olarak silmek yerine tuttuğumuz geçici bir kapta gerçekleştiğini göreceksiniz:

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

docker diffBu kapsayıcı kimliklerinin her birinde a çalıştırırsanız , bu kapsayıcılarda hangi dosyaların oluşturulduğunu görürsünüz:

$ 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

Ön ekine sahip her satır Adosyayı ekler, var olan bir dosyada yapılan Cdeğişikliği ve Dbir silme işlemini belirtir.

İşte TL; DR kısmı

Bu kapsayıcı dosya sistemi farklarının her biri, görüntüyü kapsayıcı olarak çalıştırdığınızda birleştirilen bir "katmana" gider. Bir ekleme veya değiştirme olduğunda tüm dosya her katmandadır, bu nedenle bu chmodkomutların her biri, bir izin bitini değiştirmesine rağmen, tüm dosyanın bir sonraki katmana kopyalanmasına neden olur. Silinen / veri / bir dosya, önceki katmanlarda, aslında 3 kez ve görüntüyü çektiğinizde ağ üzerinden kopyalanacak ve diskte saklanacaktır.

Mevcut görüntüleri inceleme

Komutla mevcut bir görüntünün katmanlarını oluşturmaya giden komutları görebilirsiniz docker history. Ayrıca docker image inspectbir görüntü üzerinde a çalıştırabilir ve RootFS bölümünün altındaki katmanların listesini görebilirsiniz.

Yukarıdaki resim için tarih:

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

En yeni katmanlar üstte listelenir. Dikkat çeken, altta oldukça eski olan iki katman var. Meşgul kutusu görüntüsünün kendisinden geliyorlar. Bir görüntü oluşturduğunuzda, FROMsatırda belirttiğiniz görüntünün tüm katmanlarını devralırsınız . Görüntü meta verilerindeki, CMDçizgi gibi değişiklikler için eklenen katmanlar da vardır . Çok az yer kaplarlar ve çalıştırdığınız görüntü için hangi ayarların geçerli olduğunu kaydetmek için daha fazladır.

Neden katmanlar?

Katmanların birkaç avantajı vardır. İlk olarak değişmezler. Bir kez oluşturulduktan sonra, sha256 karmasıyla tanımlanan katman asla değişmez. Bu değişmezlik, görüntülerin birbirinden güvenli bir şekilde oluşturulmasını ve çatallanmasını sağlar. İki docker dosyası aynı ilk satır kümesine sahipse ve aynı sunucu üzerinde oluşturulmuşsa, disk alanından tasarruf ederek aynı başlangıç ​​katmanları kümesini paylaşırlar. Bu, Dockerfile'ın yalnızca son birkaç satırında değişikliklerle birlikte bir görüntüyü yeniden oluşturduğunuzda, yalnızca bu katmanların yeniden oluşturulması ve geri kalanı katman önbelleğinden yeniden kullanılabileceği anlamına gelir. Bu, docker görüntülerinin yeniden oluşturulmasını çok hızlı hale getirebilir.

Bir kabın içinde görüntü dosya sistemini görürsünüz, ancak bu dosya sistemi kopyalanmaz. Bu görüntü katmanlarının üstünde, kap kendi okuma-yazma dosya sistemi katmanını bağlar. Bir dosyanın her okunması, dosyayı silinmek üzere işaretlenmiş bir katmana çarpana kadar, o katmanda dosyanın bir kopyasına sahip olana veya okunacak arama katmanları bitene kadar katmanlar arasında ilerler. Her yazma, konteynere özgü okuma-yazma katmanında bir değişiklik yapar.

Katman şişkinliğini azaltma

Katmanların bir dezavantajı, dosyaları çoğaltan veya daha sonraki bir katmanda silinen dosyaları gönderen görüntüler oluşturmaktır. Çözüm genellikle birden çok komutu tek bir RUNkomutta birleştirmektir . Özellikle mevcut dosyaları değiştirirken veya dosyaları silerken, bu adımların ilk oluşturuldukları komutla çalışmasını istersiniz. Yukarıdaki Dockerfile'ın yeniden yazılması şöyle görünür:

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

Ve ortaya çıkan görüntüleri karşılaştırırsanız:

  • meşgul kutusu: ~ 1MB
  • ilk resim: ~ 6MB
  • ikinci resim: ~ 2MB

Anlaşılan örnekte bazı satırları birleştirerek, görüntümüzde elde edilen aynı içeriği aldık ve görüntümüzü 5MB'den son görüntüde gördüğünüz 1MB dosyasına küçülttük.


Dosya okumaları sırasında katmanların arasında gezinmek biraz ek yük gerektirir, değil mi? Bu yükü kaydetmek için, birden fazla komutu (yine de birlikte yürütülmesi gerekir) tek bir RUN'da birleştirmek mantıklı mıdır?
SergiyKolesnikov

@SergiyKolesnikov, zamanından önce optimize etmek için ne kadar zaman harcamak istediğinize bağlıdır. Risk, milisaniyelik çalışma süresinden tasarruf etmek için geliştirici saatini, ek bant genişliği ve depolama alanlarını harcamaktır. Performansla ilgili birçok şeyde olduğu gibi, aşırı uçlar vardır ve sorunu düzeltmek için çaba sarf etmeden önce sorunu ölçmeye ihtiyaç vardır.
BMitch

19

Docker v1.10'dan beri, adreslenebilir depolamanın içeriğiyle, 'katman' kavramı oldukça farklı hale geldi. Katmanların bir görüntü veya görüntüye ait bir fikri yoktur, yalnızca resimler arasında paylaşılabilecek dosya ve dizin koleksiyonları haline gelirler. Katmanlar ve görüntüler ayrıldı.

Örneğin, bir baz görüntüden bir yerel inşa görüntü üzerinde, diyelim ki, ubuntu:14.04, docker historykomut görüntü zincirini verir, ancak görüntü kimlikleri bazı yapı geçmişi artık yüklü olduğu için 'kayıp' olarak gösterilecektir. Ve bu görüntüleri oluşturan katmanlar şu şekilde bulunabilir:

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

/var/lib/docker/aufs/diffDepolama sürücüsü seçimi ise katman içeriği adresinde saklanır aufs. Ancak katmanlar rastgele oluşturulmuş bir önbellek kimliğiyle adlandırılır, bir katman ile önbellek kimliği arasındaki bağlantı sadece güvenlik nedenleriyle Docker Engine tarafından bilinir. Hala öğrenmenin bir yolunu arıyorum

  1. Bir görüntü ile oluşturma katman (lar) ı arasındaki karşılık gelen ilişki
  2. Diskteki bir katmanın gerçek konumu ve boyutu

Bu blog çok fikir verdi.


Bu SO girişinde, gönderdiğim iki soruyu cevaplamanın oldukça naif bir yolunu yayınladım.
Ruifeng Ma

13

Docker en Başına görüntü spec aracılığıyla Moby Projesi :

Görüntüler katmanlardan oluşur. Her katman bir dosya sistemi değişiklikleri kümesidir. Katmanlar, ortam değişkenleri veya varsayılan bağımsız değişkenler gibi yapılandırma meta verilerine sahip değildir - bunlar görüntünün belirli bir katmandan ziyade bir bütün olarak özellikleridir.

Yani, esasen, bir katman sadece dosya sisteminde yapılan bir değişiklik kümesidir.


Onu bulmam sadece birkaç saatimi aldı, ancak bu zarif ve basit cevapla nihayet bir katmanın ne olduğunu anlıyorum: "Each [Docker] layer is a set of filesystem changes."(Bunun doğru olduğunu varsayarak.) Nedense çok sayıda diğer dokümanı okurken bu temel noktayı anlamadım / bloglar / Q + A / vb. Ne olursa olsun, bravo Aditya meselenin kalbine ulaştığı için.
Johnny Utahh


2

Yararlı bilgiler için @David Castillo'a teşekkür ederiz . Bence katman, ikili bir değişiklik veya kolayca yapılabilen veya geri alınabilen bir görüntünün talimatıdır. Bir katmandaki katmanla aynı olan adım adım yapılırlar, bu yüzden "katman" adını verdik.

Daha fazla bilgi için "docker geçmişi" ni şöyle görebilirsiniz:

docker görüntüleri - ağaç
Uyarı: '--tree' kullanımdan kaldırıldı, yakında kaldırılacak. Kullanım bölümüne bakınız.
Size511136ea3c5a Sanal Boyut: 0 B Etiketler: kazı kazan: en son
  Virtual59e359cb35ef Sanal Boyut: 85.18 MB
    8e8d37d9e3476 Sanal Boyut: 85.18 MB Etiketler: debian: wheezy
      58c58b36b8f285 Sanal Boyut: 85.18 MB
        Size90ea6e05b074 Sanal Boyut: 118.6 MB
          └─5dc74cffc471 Sanal Boyut: 118.6 MB Etiketler: vim: en son


5
katmanlar hakkında yeni bir bilgi buldu : Docker kökleri bağladığında, geleneksel bir Linux önyüklemesinde olduğu gibi salt okunur olarak başlar, ancak daha sonra dosya sistemini okuma-yazma moduna değiştirmek yerine, birleşim birleşiminin avantajlarından yararlanır salt okunur dosya sistemi üzerinden bir okuma-yazma dosya sistemi. Aslında, birbirinin üzerine yığılmış birden çok salt okunur dosya sistemi olabilir. Bu dosya sistemlerinin her birini bir katman olarak düşünüyoruz .
hiproz

1

Kişisel anlayışım, docker katmanını github commit ile karşılaştırabilmemiz. Temel görüntünüz için (yeni master repo'nuz), birkaç taahhütte bulunursunuz, her taahhüt ana durumunuzu değiştirir, docker'da aynıdır, her katman önceki ara katmana göre bazı işlemler yapar. Ve sonra, bu katman bir sonraki katmana yeni bir ara katman haline gelir.


0

Önceki katmanlardaki farklar gibi olduklarını düşünürdüm . Bazı cevapları okuduktan sonra o kadar emin değildim; bunlar dosya sisteminde yapılan değişiklikler kümesi olarak tanımlanır . Bazı Dockerfiles yazdım, daha farklı diffs gibi, yani gerçekten önceki katmanlara bağlılar.

Verilen bu iki Docker dosyası

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

ve

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

dosya sistemindeki değişikliklerle ilgili olsaydı aynı katman kümesini beklerlerdi, ancak durum böyle değildir:

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

ve

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

Dosya sistemindeki değişiklikler her iki durumda da aynı olsa bile , siparişin nasıl önemli olduğunu görebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.