Docker katmanlarını anlama


27

Aşağıdaki bloğumuzda Dockerfile:

RUN yum -y update
RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel

Bana RUNyaratılan liman işçisi katmanlarını azaltmak için bu komutları birleştirmemiz gerektiği söylendi :

RUN yum -y update \
    && yum -y install epel-release \
    && yum -y groupinstall "Development Tools" \
    && yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel

Docker için çok yeniyim ve birden fazla RUN komutu tanımlamanın bu iki sürümü arasındaki farkları tamamen anladığımdan emin değilim. Bir kişi ne zaman RUNbir tek bir komutla birleşir ve ne zaman birden çok RUNkomutun olması mantıklı olur ?


Yanıtlar:


35

Liman görüntü, aslında dosya sistemi katmanlarının bağlantılı bir listesidir. Bir Docker dosyasındaki her komut , ilgili komutun uygulanmasından önce ve sonra dosya sistemindeki farklılıkları tanımlayan bir dosya sistemi katmanı oluşturur. Alt docker inspectkomut, dosya sistemi katmanlarının bağlantılı bir listesi olma niteliğini ortaya çıkarmak için bir liman görüntüsünde kullanılabilir.

Görüntüde kullanılan katman sayısı önemlidir

  • görüntüleri iterken veya çekerken, aynı anda gerçekleşen yükleme veya indirme sayısını etkiler.
  • bir kabı çalıştırırken, tabakalar kabın içinde kullanılan dosya sistemini üretmek için bir araya getirildiği için; katmanlar ne kadar fazla olursa, performans o kadar kötü olur, ancak farklı dosya sistemi arka uçları bundan farklı şekilde etkilenir.

Bunun görüntülerin nasıl oluşturulması gerektiğinin birkaç sonucu vardır. Verebileceğim ilk ve en önemli tavsiye:

Tavsiye # 1 Kaynak kodunuzun bulunduğu derleme adımlarının Dockerfile içinde mümkün olduğunca geç geldiğinden ve a &&veya a kullanarak önceki komutlara bağlı olmadığından emin olun ;.

Bunun nedeni, önceki adımların hepsinin önbelleğe alınması ve karşılık gelen katmanların tekrar tekrar indirilmesine gerek kalmamasıdır. Bu, daha hızlı kurulumlar ve daha hızlı sürümler anlamına gelir; bu muhtemelen istediğiniz şeydir. İlginçtir ki, liman işçisi önbelleğini en iyi şekilde kullanmak şaşırtıcı derecede zordur.

İkinci tavsiyem daha az önemli ama bakım açısından çok yararlı buluyorum:

Tavsiye # 2 Docker dosyasına karmaşık komutlar yazmayın , kopyalanacak ve uygulanacak komut dosyalarını kullanın.

Bu tavsiyeyi izleyen bir Dockerfile

COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
COPY install_pacakges.sh /root/
RUN sh -x /root/install_packages.sh

ve bunun gibi. Birkaç komutu bağlamanın tavsiyesi &&sadece sınırlı bir kapsamı vardır. Artıklıktan kaçınmak için veya dokümantasyon amacıyla fonksiyonlar vb. Kullanabileceğiniz komut dosyaları ile yazmak çok daha kolaydır.

İnsanlar ön-işlemci tarafından ilgi ve neden olduğu küçük yükü önlemek için istekli COPYbir-the-fly adımları ve aslında ürettiğini Dockerfile nerede

COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh

dizileri ile değiştirilir

RUN base64 --decode … | sh -x

buradaki base64 kodlu sürüm apt_setup.sh.

Üçüncü tavsiyem, daha uzun inşaatların olası maliyetiyle boyut ve katman sayısını sınırlamak isteyen insanlar içindir.

Tavsiye # 3with Orta katmanlarda bulunan ancak ortaya çıkan dosya sisteminde olmayan dosyaları önlemek için -idiom'u kullanın .

Bazı liman işçisi talimatı tarafından eklenen ve sonraki bazı talimatlarla kaldırılan bir dosya, sonuçta ortaya çıkan dosya sisteminde mevcut değildir, ancak yapım aşamasında docker görüntüsünü oluşturan liman katmanlarında iki kez belirtilir. Bir keresinde, katmanın içindeki ad ve tam içerik ile komutun eklenmesinden kaynaklanır ve katmanın içindeki bir silme uyarısı olarak çıkarılır.

Örneğin, geçici olarak bir C derleyicisine ve bazı görüntülere ihtiyacımız olduğunu varsayalım ve

# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc

(Daha gerçekçi bir örnek, sadece --versionbayrakla varlığını iddia etmek yerine, derleyiciyle birlikte bazı yazılımlar oluşturur .)

Dockerfile pasajı üç katman oluşturur, ilki tam gcc paketini içerir, böylece son dosya sisteminde mevcut olmasa bile karşılık gelen veriler yine de aynı şekilde görüntünün bir parçasıdır ve gerektiğinde indirilmesi, yüklenmesi ve açılması gerekir. son görüntü.

with-İdiom izolatı kaynak sahipliği ve kaynak kullanmadan mantıktan bırakmadan fonksiyonel programlamada yaygın bir şeklidir. Bu deyimi kabuk kodlamaya dönüştürmek kolaydır ve önceki komutları Tavsiye 2'deCOPY & RUN olduğu gibi kullanılmak üzere önceki komutları aşağıdaki komut dosyası olarak değiştirebiliriz .

# with_c_compiler SIMPLE-COMMAND
#  Execute SIMPLE-COMMAND in a sub-shell with gcc being available.

with_c_compiler()
(
    set -e
    apt-get install -y gcc
    "$@"
    trap 'apt-get --purge autoremove -y gcc' EXIT
)

with_c_compiler\
    gcc --version

Karmaşık komutlar fonksiyona dönüştürülebilir, böylece beslenebilsinler with_c_compiler. Ayrıca, çeşitli with_whateverişlevlerin çağrılarını zincirlemek de mümkündür , ancak çok arzu edilmez. (Kabuğun daha ezoterik özelliklerini kullanarak, with_c_compilerkarmaşık komutları kabul etmek kesinlikle mümkündür , ancak bu karmaşık komutları fonksiyonlara sarmak her yönüyle tercih edilir.)

Tavsiye # 2'yi yoksaymak istiyorsak, ortaya çıkan Dockerfile snippet'i

RUN apt-get install -y gcc\
 && gcc --version\
 && apt-get --purge autoremove -y gcc

ki bu şaşkınlık nedeniyle okunması ve bakımı o kadar kolay değildir. Shell-script değişkeninin , gürültünün ortasındaki bölümü gömdüğü gcc --versionsırada, önemli olana nasıl vurgu yaptığını görün &&.


1
Bir komut dosyası kullanarak ve çoklu komutları tek bir RUN ifadesinde kullandıktan sonra kutu boyutunun sonucunu dahil edebilir misiniz?
030

1
Görüntü tabanının (yani işletim sistemi öğeleri) yapılandırmasını ve hatta yazdığınız kaynağın kurulumuyla birlikte libleri karıştırmam kötü bir fikir gibi görünüyor. "Kaynak kodunuzun bulunduğu derleme adımlarının mümkün olduğunca geç geldiğinden emin olun" diyorsunuz. Bu kısmı tamamen bağımsız bir eser haline getirmede herhangi bir sorun var mı?
JimmyJames

1
@ 030 “Kutu” boyutu ile ne demek istiyorsunuz? Hangi kutudan bahsettiğin hakkında hiçbir fikrim yok.
Michael Le Barbier Grünewald

1
Liman görüntü boyutunu kastediyordum
030

1
@JimmyJames Büyük ölçüde dağıtım senaryonuza bağlıdır. Derlenmiş bir program kabul edersek, “yapılacak doğru şey” onu paketlemek ve bu paket bağımlılıklarını ve paketin kendisini son noktaya yakın iki adım olarak kurmak olacaktır. Liman işçisi önbelleğinin kullanışlılığını en üst düzeye çıkarmak ve aynı dosyalarla katmanların üstüne ve üstüne yüklenmesini önlemek için. Docker görüntüleri oluşturmak için görüntü oluşturma uzunluğundaki bağımlılık zincirlerini oluşturmaktan ziyade yapı reçetelerini paylaşmayı daha kolay buluyorum çünkü ikincisi yeniden yapılanmayı zorlaştırıyor.
Michael Le Barbier Grünewald

13

Dockerfile dosyanızda oluşturduğunuz her talimat, yeni bir resim katmanının oluşturulmasına neden olur. Her katman, elde edilen görüntünün parçası olmayan her zaman ek veriler getirir. Örneğin, bir katmana bir dosya eklerseniz, ancak daha sonra başka bir katmanda kaldırırsanız, son görüntünün boyutu, kaldırmanıza rağmen özel bir "whiteout" dosyası biçiminde eklenmiş dosya boyutunu içerecektir.

Diyelim ki aşağıdaki Dockerfile'unuz var:

FROM centos:6

RUN yum -y update 
RUN yum -y install epel-release

Elde edilen görüntü boyutu

bigimage     latest        3c5cbfbb4116        2 minutes ago    407MB

Karşılık olarak, "benzer" Dockerfile ile:

FROM centos:6

RUN yum -y update  && yum -y install epel-release

Elde edilen görüntü boyutu

smallimage     latest        7edeafc01ffe        3 minutes ago    384MB

Yum önbelleğini tek bir RUN ifadesinde temizlerseniz daha da küçük boyut alırsınız.

Bu nedenle okunabilirlik / bakım kolaylığı ile katman sayısı / görüntü boyutu arasındaki dengeyi korumak istiyorsunuz.


4

RUNİfadeleri her biri bir katman oluşturmaktadır. Bir paketin indirildiğini, yüklendiğini ve kaldırmak istediğini hayal edin. Biri üç RUNifade kullanıyorsa , ayrı katmanlar olduğu için görüntü boyutu daralmaz. Biri tüm komutları bir RUNifade kullanarak çalıştırırsa , disk görüntüsü boyutu azaltılabilir.

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.