Oluşturma sırasında ana bilgisayar birimlerini Dockerfile'daki docker kaplarına bağlama


236

Orijinal soru: Dockerfile'da VOLUME talimatı nasıl kullanılır?

Çözmek istediğim asıl soru şu: ana bilgisayar birimlerini derleme sırasında Dockerfile'daki docker kaplarına nasıl bağlayacağımız, yani docker run -v /export:/exportyeteneği sırasında docker build.

Bunun arkasındaki neden, benim için, Docker'da bir şeyler inşa ederken, bu ( apt-get install) önbelleklerin tek bir liman işçisine kilitlenmesini istemiyorum , ancak onları paylaşma / yeniden kullanma. Bu soruyu sormamın ana nedeni bu.

Son Güncelleme:

Docker v18.09'dan önce, doğru cevap şu soru ile başlamalıdır:

Bir derleme sırasında bir birim monte etmenin bir yolu vardır, ancak Dockerfiles'ı içermez.

Ancak, bu kötü ifade edilmiş, organize ve desteklenmiş bir cevaptı. Docker içeriğimi yeniden yüklerken, aşağıdaki makaleye rastladım:

Uygun bir cacher-ng hizmetini dockerize
edin https://docs.docker.com/engine/examples/apt-cacher-ng/

Docker'in bu soruya çözümü doğrudan / dolaylı değil. Docker'ın yapmamızı önerdiği ortodoks bir yol. Ve burada sormaya çalıştığımdan daha iyi olduğunu itiraf ediyorum.

Başka bir yol, yeni kabul edilen cevap , örneğin v18.09'daki Buildkit.

Size uygun olanı seçin.


Oldu: Docker'dan olmayan bir çözüm - rocker vardı, ama şimdi rocker kesildi, cevabı tekrar "Mümkün değil" e geri döndürdüm .


Eski Güncelleme: Yani cevap "Mümkün değil". Sorunun https://github.com/docker/docker/issues/3156 adresinde yoğun bir şekilde tartışıldığını bildiğim için bunu bir cevap olarak kabul edebilirim . Taşınabilirliğin docker geliştiricisi için çok önemli bir sorun olduğunu anlayabilirim; ancak bir liman işçisi kullanıcı olarak, bu eksik özellik için çok hayal kırıklığına uğradığımı söylemeliyim. Tartışmamı yukarıda bahsi geçen tartışmadan bir alıntıyla kapatmama izin verin: " Gentoo'yu temel görüntü olarak kullanmak istiyorum, ancak görüntü oluşturulduktan sonra kesinlikle 1GB> Portage ağacı verilerinin katmanlardan herhangi birinde olmasını istemiyorum. yükleme sırasında devasa portage ağacının görünmemesi için kompakt bir konteynere sahip olabilir."Evet, ihtiyacım olanı indirmek için wget veya curl kullanabilirim, ancak sadece bir taşınabilirlik konusundaki düşüncenin beni her Gentoo temel imajı oluşturduğumda 1GB> Portage ağacını indirmeye zorlaması gerçeği ne verimli ne de kullanıcı dostu. Dahası, paket deposu HER ZAMAN / usr / portage altında OLACAK, bu nedenle DAİMA Gentoo altında TAŞINABİLİR Yine karara saygı duyuyorum, ama lütfen bu arada hayal kırıklığımı da ifade etmeme izin verin.


Ayrıntılarda orijinal soru :

itibaren

Dizinleri Ciltler Üzerinden Paylaşın
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

Veri hacimleri özelliğinin "Docker Remote API'sının 1. sürümünden beri kullanılabildiğini" söylüyor. Docker'ım 1.2.0 sürümü, ancak yukarıdaki makalede verilen örneği çalışmıyor:

# BUILD-USING:        docker build -t data .
# RUN-USING:          docker run -name DATA data
FROM          busybox
VOLUME        ["/var/volume1", "/var/volume2"]
CMD           ["/usr/bin/true"]

Dockerfile'da, VOLUME komutu ile ana bilgisayara monte edilen birimleri docker kaplarına monte etmenin doğru yolu nedir?

$ apt-cache policy lxc-docker
lxc-docker:
  Installed: 1.2.0
  Candidate: 1.2.0
  Version table:
 *** 1.2.0 0
        500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
        100 /var/lib/dpkg/status

$ cat Dockerfile 
FROM          debian:sid

VOLUME        ["/export"]
RUN ls -l /export
CMD ls -l /export

$ docker build -t data .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM          debian:sid
 ---> 77e97a48ce6a
Step 1 : VOLUME        ["/export"]
 ---> Using cache
 ---> 59b69b65a074
Step 2 : RUN ls -l /export
 ---> Running in df43c78d74be
total 0
 ---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
 ---> Running in 8e4916d3e390
 ---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551

$ docker run data
total 0

$ ls -l /export | wc 
     20     162    1131

$ docker -v
Docker version 1.2.0, build fa7b24f

Görünüşe göre daha güncel özellik isteği (uygulanmasını beklemek değil, ama sadece durumda): docker / docker # 14080
Jesse Glick

aslında inşa sırasında bir ana dizin ve konteyner dizini bağlamak için izin verilmemesi gerektiğini kapsamlı bir tartışma var yani VOLUME ~/host_dir ~/container_dir. Tartışma oldukça kapsamlı, bunun nedenini özetlemenin kısa bir yolu var mı?
Charlie Parker

Yanıtlar:


34

İlk olarak, "neden çalışmıyor VOLUME?" Bir tanımladığınızda VOLUMEDockerfile içinde, sadece hedefinin, hacim kaynak tanımlayabilirsiniz. İnşa sırasında, bundan sadece isimsiz bir hacim alacaksınız. Bu anonim birim her RUNkomuta monte edilir , görüntünün içeriği ile önceden doldurulur ve ardından RUNkomutun sonunda atılır . Sadece kaptaki değişiklikler kaydedilir, birimdeki değişiklikler kaydedilmez.


Bu soru sorulduğundan, yardımcı olabilecek birkaç özellik yayınlanmıştır. Birincisi, bir disk alanı verimsiz birinci aşama oluşturmanıza ve yalnızca gereken çıktıyı gönderdiğiniz son aşamaya kopyalamanıza izin veren çok aşamalı yapılardır. İkinci özellik, görüntülerin nasıl oluşturulduğunu ve yapıya yeni yetenekler eklenmesini önemli ölçüde değiştiren Buildkit.

Çok aşamalı bir yapı için, FROMher biri ayrı bir resim oluşturmaya başlayan birden fazla satırınız olur . Varsayılan olarak yalnızca son görüntü etiketlenir, ancak önceki aşamalardaki dosyaları kopyalayabilirsiniz. Standart kullanım, bir ikili veya başka bir uygulama yapay nesnesi oluşturmak için bir derleyici ortamına ve bu yapay nesnenin üzerine kopyalanan ikinci aşama olarak bir çalışma zamanı ortamına sahip olmaktır. Şunlara sahip olabilirsiniz:

FROM debian:sid as builder
COPY export /export
RUN compile command here >/result.bin

FROM debian:sid
COPY --from=builder /result.bin /result.bin
CMD ["/result.bin"]

Bu, tam / dışa aktarma dizinini değil, yalnızca elde edilen ikili dosyayı içeren bir derleme ile sonuçlanır.


Buildkit 18.09'da deneysel olarak çıkıyor. Ön uç ayrıştırıcısını değiştirme yeteneği de dahil olmak üzere oluşturma sürecinin tamamen yeniden tasarlanması. Bu ayrıştırıcı değişikliklerinden biri, RUN --mountçalıştırma komutlarınız için bir önbellek dizini bağlamanızı sağlayan seçeneği uyguladı . Örneğin, debian dizinlerinin bazılarını bağlayan bir dosya (debian görüntüsünün yeniden yapılandırılmasıyla, bu paketlerin yeniden yüklenmesini hızlandırabilir):

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/var/lib/apt/lists,type=cache \
    --mount=target=/var/cache/apt,type=cache \
    apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      git

Önbellek dizinini sahip olduğunuz uygulama önbelleği için ayarlayabilirsiniz; örneğin, maven için $ HOME / .m2 veya golang için /root/.cache.


TL; DR: Yanıt burada: Bu RUN --mountsözdizimiyle, mount-salt okunur dizinlerini derleme bağlamından da bağlayabilirsiniz. Klasörün derleme bağlamında bulunması gerekir ve ana bilgisayara veya derleme istemcisine eşlenmez:

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/export,type=bind,source=export \
    process export directory here...

Dizin bağlamdan bağlandığından, salt okunur olarak bağlandığını ve değişiklikleri ana bilgisayara veya istemciye geri gönderemeyeceğinizi unutmayın. Oluşturduğunuzda, 18.09 veya daha yeni bir kurulum ve buildkit ile etkinleştirmek istersiniz export DOCKER_BUILDKIT=1.

Bağlama bayrağının desteklenmediğine dair bir hata alırsanız, bu, yukarıdaki değişkenle derleme kitini etkinleştirmediğinizi veya daha önce Dockerdosyasının üstündeki sözdizimi çizgisiyle deneysel sözdizimini etkinleştirmediğinizi gösterir. yorumlar da dahil olmak üzere diğer tüm satırlar. Buildkit'i değiştirmek için değişkenin yalnızca docker kurulumunuzda hem istemci hem de sunucuda 18.09 veya Docker sürümünden daha yeni bir sürüm gerektiren buildkit desteği varsa çalışacağını unutmayın.


2
Ne yazık ki, Windows Buildkit'te henüz 18.09 sürümünde desteklenmiyor
Wesley

1
Görünüşe göre "armhf" de "mount" desteklemiyor.
Mike

2
OSX'te "Daemonfile ayrıştırma hata satırı xx: Bilinmeyen bayrak: mount" hata yanıtı alıyorum
ChristoKiwi

1
Liman işçisi oluşturma desteği henüz mevcut değil, ancak görüntü oluşturmak için oluşturma işlemine ihtiyacınız yok. İzlenecek
sorun


116

VOLUMEDocker'a neyi monte edeceğini söylemek için talimatı kullanmak mümkün değildir . Bu, taşınabilirliği ciddi şekilde bozar. Bu talimat, docker'a bu dizinlerdeki içeriğin görüntülerde bulunmadığını ve --volumes-fromkomut satırı parametresi kullanılarak diğer kaplardan erişilebileceğini bildirir . -v /path/on/host:/path/in/containerAna bilgisayardan dizinlere erişmek için kapsayıcıyı çalıştırmanız gerekir .

İnşa sırasında ana bilgisayar hacimlerini monte etmek mümkün değildir. Ayrıcalıklı bir yapı yoktur ve ana bilgisayarın montajı da taşınabilirliği ciddi şekilde bozar. Yapım için ihtiyacınız olan her şeyi indirmek ve yerine koymak için wget veya curl kullanmayı deneyebilirsiniz.


2
Teşekkürler. Soru revize edildi. Çözmek istediğim asıl soru, ana bilgisayar birimlerinin derleme sırasında Dockerfile'daki docker kaplarına nasıl monte edileceğidir. Teşekkürler.
xpt

2
Mümkün değil. Gözden geçirilmiş cevaba bakınız.
Andreas Steffan

3
Taşınabilirliğin "potansiyel" kötü yan etkilerini takdir edebilirim, ancak bu seçeneğe sahip olmak için geçerli bir kullanım durumu da vardır. Benim durumumda, kullanıcılara "dizine taşıyın ve bazı kapsayıcı dizinine $ (PWD) monte edilmiş olan 'docker run' komutunu çalıştırmasını söyleyebilmek isterim. $ (PWD) taşınabilirliğin korunmasını sağlar. Bu ederken olabilecek bir köşe duruma ben kullanıcı tarafından sağlanan komut dosyaları için çalışma zamanı ortamları dağıtım ediyorum, nerede o derece bana yardımcı olacaktır.
ntwrkguru

64

GÜNCELLEME: Birisi hayır olarak cevap almayacak ve özellikle bu soruya çok sevdim.

İYİ HABER, Şimdi bir yol var -

Çözüm Rocker: https://github.com/grammarly/rocker

John Yani söyledi , "IMO, bu gelişme için uygun hale Dockerfile tüm zayıf noktalarını çözer."

rock'çı

https://github.com/grammarly/rocker

Rocker, yeni komutlar sunarak, düz Docker ile acı veren aşağıdaki kullanım durumlarını çözmeyi hedefliyor:

  1. Yeniden kullanılabilir birimleri derleme aşamasında bağlayın, böylece bağımlılık yönetimi araçları derlemeler arasında önbellek kullanabilir.
  2. Ssh tuşlarını derleme ile paylaşın (özel depoları çekmek için, vb.) Ve sonuçtaki görüntüde bırakmayın.
  3. Farklı görüntülerde uygulama oluşturun ve çalıştırın, bir yapay nesneyi bir görüntüden diğerine kolayca geçirin, ideal olarak bu mantığı tek bir Dockerfile'da bulun.
  4. Görüntüleri doğrudan Dockerfiles'dan etiketleyin / itin.
  5. Dockerfile ile değiştirilebilmeleri için değişkenleri shell build komutundan geçirin.

Ve dahası. Bunlar, Docker'ı Grammarly'de benimsememizi engelleyen en kritik konular.

Güncelleme: Github'daki resmi proje repo için Rocker'a ara verildi

2018'in başından itibaren konteyner ekosistemi, bu projenin başlatıldığı üç yıl öncesine göre çok daha olgun. Şimdi, rocker'ın kritik ve olağanüstü özelliklerinden bazıları docker yapısı veya diğer iyi desteklenen araçlar tarafından kolayca kapsanabilir, ancak bazı özellikler rocker'a özgü kalır. Daha fazla bilgi için https://github.com/grammarly/rocker/issues/199 adresine bakın.


1 numaralı sorunu çözmek için Rocker kullanmaya çalışıyorum, ancak mount komutu çalışmaz ve oluşturulan görüntü ana bilgisayar klasörünü içermez. Dockerfile bağlama komutum şöyle görünüyor - MOUNT ~/code/docker-app-dev/new-editor/:/src/ve Rocker oluşturma komutum bu - rocker build -f Dockerfile .. Neyi yanlış yapıyorum?
Yaron Idan

Belki gerçek bir ana bilgisayar yolu kullanmayı deneyin? ~Bourne kabuğu metakarakteridir.
Jesse Glick

Rocker buildizin vermez docker runkomut satırı seçenekleri, bu nedenle şu anda gibi şeyler izin vermez --privileged.
Monty Wild

Merhaba @xpt, rocker artık üretilmediği için başka bir güncelleme alabilir miyiz
Shardj

Şimdi rocker kesildi, cevabı tekrar "Mümkün değil" e çevirdim. OP ve seçilen cevaba bakınız.
xpt

14

Bir derleme sırasında bir birim monte etmenin bir yolu vardır, ancak Dockerfiles'ı içermez.

Teknik, kullanmak istediğiniz herhangi bir tabandan bir kap oluşturmak (hacimlerinizi -vseçenekle kap içine monte etmek ), görüntü oluşturma işinizi yapmak için bir kabuk komut dosyası çalıştırmak, sonra kapsayıcıyı bir görüntü olarak işlemek .

Bu sadece istemediğiniz fazla dosyaları dışarıda bırakmakla kalmaz (SSH dosyaları gibi güvenli dosyalar için de iyidir), aynı zamanda tek bir görüntü oluşturur. Bunun dezavantajları vardır: commit komutu tüm Dockerfile talimatlarını desteklemez ve derleme komut dosyanızı düzenlemeniz gerektiğinde kaldığınız zaman almanıza izin vermez.

GÜNCELLEME:

Örneğin,

CONTAINER_ID=$(docker run -dit ubuntu:16.04)
docker cp build.sh $CONTAINER_ID:/build.sh
docker exec -t $CONTAINER_ID /bin/sh -c '/bin/sh /build.sh'
docker commit $CONTAINER_ID $REPO:$TAG
docker stop $CONTAINER_ID

6
+1 2. paragraftaki talimatlar hakkında biraz daha bilgi verebilir misiniz? Örneğin, temel debian:wheezyve kabuk komut dosyası ise build.sh, hangi belirli yönergeler kullanılır?
Drux

6

Kapsayıcıyı çalıştırdıkça, ana makinenizde bir dizin oluşturulur ve kaba konur. Bunun hangi dizinde olduğunu öğrenebilirsiniz

$ docker inspect --format "{{ .Volumes }}" <ID>
map[/export:/var/lib/docker/vfs/dir/<VOLUME ID...>]

Ana makinenizden kapsayıcınızın içindeki bir dizini takmak istiyorsanız, -vparametreyi kullanmanız ve dizini belirtmeniz gerekir. Sizin durumunuzda:

docker run -v /export:/export data

Bu yüzden konteynerinizin içindeki hosts klasörünü kullanırsınız.


1
Teşekkürler. Soru revize edildi. Çözmek istediğim asıl soru, ana bilgisayar birimlerinin derleme sırasında Dockerfile'daki docker kaplarına nasıl monte edileceğidir. Teşekkürler.
xpt

Lütfen sorularınızı bu kadar sert bir şekilde gözden geçirmeyin . Bu, düzenlemelerimden önce tamamen geçerli olmasına rağmen sorumu geçersiz kılıyor. Bunun yerine yeni bir soru sormayı düşünün.
Behe

11
Orijinal soru : Dockerfile'da VOLUME talimatı nasıl kullanılır? Bugün bile hala sorunun başında geliyor. Cevabınız çalışma süresi içindi ve sorum her zaman derleme süresiyle ilgili , Dockerfile bunun içindi.
xpt

4

Yapımın kendisi bir docker konteyner içinde çalıştırılan bir docker komutu ile çalıştırarak ne yapmak istediğinizi düşünüyorum. Bkz. Docker artık Docker'da çalışabilir | Docker Blogu . Mesela mümkün olan en küçük Docker konteynerinin nasıl yaratıldığını keşfederken bunun gibi, ancak harici docker'a bir konteynırdan erişen bir teknik kullanıldı. Xebia Blogu .

İlgili başka bir makale Docker Görüntülerini Optimize Etme | Bir derleme sırasında bir şeyler indirirseniz, indirmeyi tek bir RUN adımında indirerek, oluşturarak ve silerek son görüntüde alanın boşa gitmesini önleyebileceğinizi açıklayan CenturyLink Labs .


3

Çirkin, ama bunun gibi bir benzerlik elde ettim:

Dockerfile:

FROM foo
COPY ./m2/ /root/.m2
RUN stuff

imageBuild.sh:

docker build . -t barImage
container="$(docker run -d barImage)"
rm -rf ./m2
docker cp "$container:/root/.m2" ./m2
docker rm -f "$container"

Evreni /root/.m2'ye indiren ve her seferinde bunu yapan bir java derlemem var . imageBuild.shderlemeden sonra o klasörün içeriğini ana bilgisayara Dockerfilekopyalar ve bir sonraki derleme için tekrar görüntüye kopyalar.

Bu, bir hacmin nasıl çalışacağı gibi bir şeydir (yani, yapılar arasında devam eder).


Bu, Docker tabanlı sürekli entegrasyon, yani CI için uygun bir çözümdür. Kitaplıkları ve derleyicileri ayarlayın ve Dockerfile komutları ile make komutunu çalıştırın, sadece bir kap oluşturmak için görüntüyü önemsiz bir şekilde başlatın ve son olarak .deb gibi istenen eseri kopyalayın. Çalışıyor gibi görünüyor, bunu gönderdiğin için teşekkürler.
chrisinmtown

Bu çözüm size ihtiyacınız olan ve ihtiyacınız olmayan ./m2/ TÜM dosyaları olan bir görüntü bırakır ve bu da BÜYÜK üretim görüntülerine yol açabilir, bu da istenmez! Harici bağımlılıklar dizinine bağlandığında, yalnızca gerekli dosyalar görüntüye kopyalanır.
Marko Krajnc

Görüntüyü yayınlamak istiyorsanız, muhtemelen beklemek ve her seferinde kendi bağımlılıklarını yeniden indirmesine izin vermek en iyisidir. Bu saldırı, yalnızca bir görüntüyü test etmek üzere hazırlıyorsanız anlamlıdır - son kullanıcıların asla temas etmeyeceği bir görüntü.
MatrixManAtYrService

1

Burada, kabuk komut dosyaları olmadan derleme ve kaydetme özelliğini kullanan 2 adımlı yaklaşımın basitleştirilmiş bir sürümü bulunmaktadır. İçerir:

  1. Görüntüyü, hacimler olmadan kısmen oluşturma
  2. Bir kap Koşu hacimleri ile daha sonra, sonuç işlemekten orijinal resim adını değiştirerek, bir değişiklik yapmadan,.

Nispeten küçük değişikliklerle ek adım, yapım süresine yalnızca birkaç saniye ekler.

Temelde:

docker build -t image-name . # your normal docker build

# Now run a command in a throwaway container that uses volumes and makes changes:
docker run -v /some:/volume --name temp-container image-name /some/post-configure/command

# Replace the original image with the result:
# (reverting CMD to whatever it was, otherwise it will be set to /some/post-configure/command)   
docker commit --change="CMD bash" temp-container image-name 

# Delete the temporary container:
docker rm temp-container

Benim kullanım durumunda bir maven toolchains.xml dosyasını önceden oluşturmak istiyorum, ancak birçok JDK kurulumum çalışma zamanına kadar mevcut olmayan bir birimde. Bazı resimlerim tüm JDKS ile uyumlu değil, bu yüzden derleme zamanında uyumluluk test etmek ve toolchains.xml koşullu doldurmak gerekir. Görüntünün taşınabilir olması gerekmediğini unutmayın, Docker Hub'da yayınlamıyorum.


1

Birçoğunun daha önce yanıtladığı gibi, derleme sırasında ana bilgisayar birimlerini monte etmek mümkün değildir. Sadece docker-composeyol eklemek istiyorum , bence çoğunlukla geliştirme / test kullanımı için olması güzel olacak

Dockerfile

FROM node:10
WORKDIR /app
COPY . .
RUN npm ci
CMD sleep 999999999

liman işçisi-compose.yml

version: '3'
services:
  test-service:
    image: test/image
    build:
      context: .
      dockerfile: Dockerfile
    container_name: test
    volumes:
      - ./export:/app/export
      - ./build:/app/build

Ve konteynırınızı docker-compose up -d --build

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.