Docker'ın derleme bağlamının dışındaki dosyalar nasıl eklenir?


465

Docker dosyasındaki "EKLE" komutunu kullanarak Docker'ın yapı bağlamının dışındaki dosyaları nasıl ekleyebilirim?

Docker belgelerinden:

Yol, yapının bağlamı içinde olmalıdır; bir docker derlemesinin ilk adımı bağlam dizinini (ve alt dizinleri) docker arka plan programına göndermek olduğundan ../something/something ADD ekleyemezsiniz.

Tüm projemi Docker'ı bu konuya dahil etmek için yeniden yapılandırmak istemiyorum. Tüm Docker dosyalarımı aynı alt dizinde tutmak istiyorum.

Ayrıca, Docker henüz sembol bağlantılarını desteklemiyor (ve hiç desteklemiyor): Dockerfile ADD komutu ana bilgisayar # 1676'daki sembol bağlantılarını takip etmiyor.

Aklıma gelen tek şey, dosyaları Docker derleme bağlamına kopyalamak için bir ön derleme adımı eklemek (ve bu dosyaları yoksaymak için sürüm denetimimi yapılandırmak). Bundan daha iyi bir çözüm var mı?


96
Bu Docker ile ilgili en kötü şey olmalı. Benim bakış açımdan "Docker projesi" diye bir şey yok. Docker nakliye projeleri içindir. Bu sadece bir araç. Tüm projemi dock hesabına yeniden hesaplamak, .dockerignore vb. Eklemek zorunda kalmak istemiyorum. Günün sonunda, Docker'ın ne kadar süreceğini kim bilebilir? Kod (yani açısal proje) ile onu dağıtmak için ne anlama gelirse (yani liman işçisi) arasında bir ayrım yapmak harika olurdu. Sonuçta, diğer her şeyin yanında bir docker dosyasına sahip olmanın hiçbir yararı yoktur. Bir görüntü oluşturmak için sadece kablolama işleri :(
TigerBear

3
Evet, bu büyük bir düşüş. Aynı sorunla karşılaşıyorum ve her Docker yapı içeriğine kopyalamak istemiyorum daha büyük boyutlu bir ikili dosya (zaten sıkıştırılmış) var. Geçerli konumundan (Docker yapı bağlamı dışında) kaynak tercih ederim. Ve ben bir birim çalışma zamanında eşlemek istemiyorum, çünkü ben dosya oluşturmak ve dosyayı açmak ve bazı ikili görüntü görüntü pişmiş böylece ihtiyacım olanı yapmak için COPY / EKLE çalışıyorum. Bu şekilde kapları döndürmek hızlı olur.
jarse fasulyesi

İyi bir yapı buldum ve detayları açıklayarak stackoverflow.com/a/53298446/433814
Marcello de Sales

1
liman işçileri ile ilgili sorun "bağlam" ın oluşturulmuş konseptidir. Dockerfiles, bir stratejik dizinin altına (aka bağlam), yani "/" uç olarak yerleştirilmedikçe bir yapıyı tanımlamak için yeterli değildir, böylece herhangi bir yola erişebilirsiniz (bunun aklı başında bir projede yapılacak doğru şey olmadığını unutmayın) ya ..., artı, docker başlangıçta tüm içeriği taradığı için docker'ın çok yavaş olmasını sağlar). Gerekli tüm dosyalarla bir liman işçisi görüntüsü oluşturmayı ve oradan FROMdevam etmek için kullanmayı düşünebilirsiniz . Proje yapısını Docker'a (veya herhangi bir derleme aracına) uyacak şekilde değiştirmezdim.
Devis L.

Yanıtlar:


415

Bu soruna geçici bir çözüm bulmak için en iyi yolu, Dofdosyasını derleme bağlamından bağımsız olarak -f kullanarak belirtmektir.

Örneğin, bu komut ADD komutuna geçerli dizininizdeki herhangi bir şeye erişim sağlar.

docker build -f docker-files/Dockerfile .

Güncelleme : Docker artık Dockerfile'ın yapı bağlamının dışında olmasına izin veriyor (18.03.0-ce, https://github.com/docker/cli/pull/886 ile düzeltildi ). Böylece şöyle bir şey yapabilirsiniz

docker build -f ../Dockerfile .

8
@Ro. Bu dockerfile:özelliği docs.docker.com/compose/compose-file/#/compose-file-reference adresindekibuild: Oluştur dosyasındaki bölümde kullanırsınız
Emerson Farrugia

3
"Dockerfile yapı bağlamında olmalıdır" - gerçekten geçerli yapı bağlamının altında ikamet bir Dockerfile olmasını istiyorum. Örneğinizde, elbette çalışan geçerli derleme bağlamında / altında Dockerfile var.
Alexander Mills

3
Evet, hepsi "yapı bağlamları" olan birden fazla alt dizine karşılık gelen paylaşılan bir Dockerfile istiyorum
Alexander Mills

51
Bu OP'nin ADDbağlam dizini dışında bir dosya isteme sorununu çözüyor mu ? Yapmaya çalıştığım şey bu ama -fharici dosyaları eklenebilir kılmıyorum.
Sridhar Sarnobat

18
Benim de .. Bu yeterli upvote Can not Ben docker-compose.yml: build: context: .., dockerfile: dir/Dockerfile. Şimdi yapı bağlamım üst dizin!
Mike Gleason jr Couturier

51

Sık sık kendimi --build-argbu amaç için kullanıyorum . Örneğin Dockerfile dosyasına koyduktan sonra:

ARG SSH_KEY
RUN echo "$SSH_KEY" > /root/.ssh/id_rsa

Sadece şunları yapabilirsiniz:

docker build -t some-app --build-arg SSH_KEY="$(cat ~/file/outside/build/context/id_rsa)" .

Ancak Docker belgelerinde aşağıdaki uyarıyı dikkate alın :

Uyarı: Github anahtarları, kullanıcı kimlik bilgileri vb. Gibi sırları iletmek için oluşturma zamanı değişkenlerinin kullanılması önerilmez. Oluşturma zamanı değişken değerleri, docker geçmişi komutuyla görüntünün herhangi bir kullanıcısı tarafından görülebilir.


6
Bu büyük bir uyarı olmadan kötü bir tavsiye. Docker belgelerinden: "Uyarı: Github anahtarları, kullanıcı kimlik bilgileri vb. Gibi sırları iletmek için oluşturma zamanı değişkenlerinin kullanılması önerilmez. Oluşturma zamanı değişken değerleri, docker geçmişi komutuyla görüntünün herhangi bir kullanıcısı tarafından görülebilir." [1] Başka bir deyişle, bu örnekte verilen örnek, liman işçiliği görüntüsünde özel SSH anahtarını açıklar. Bazı bağlamlarda bu iyi olabilir. docs.docker.com/engine/reference/builder/#arg
sheldonh

3
Son olarak, bu güvenlik sorununun üstesinden gelmek için, ezme veya çok aşamalı yapılar gibi teknikleri kullanabilirsiniz: vsupalov.com/build-docker-image-clone-private-repo-ssh-key
Jojo

46

Linux'ta başka dizinleri işaretlemek yerine bağlayabilirsiniz

mount --bind olddir newdir

Daha fazla ayrıntı için bkz. Https://superuser.com/questions/842642 .

Diğer işletim sistemleri için benzer bir şey olup olmadığını bilmiyorum. Ayrıca bir klasörü paylaşmak ve de çalışan Docker bağlamına yeniden monte etmek için Samba'yı kullanmayı denedim.


2
Sadece kök dizinleri bağlayabilir
jjcf89 15

28

İyi bir model ve bu özellik desteğiyle neler olup bittiğini daha iyi açıklamaya çalışmak için iyi zaman geçirdim. Bunu açıklamanın en iyi yolunun aşağıdaki gibi olduğunu fark ettim ...

  • Dockerfile: Yalnızca kendi göreli yolu altındaki dosyaları görür
  • Bağlam: "boşlukta" paylaşmak istediğiniz dosyaların ve Dockerfile dosyanızın kopyalanacağı yer

Bununla birlikte, işte Dockerfile adlı bir dosyayı yeniden kullanması gereken bir örnek start.sh

Dockerfile

Bu ALWAYSşekilde kendisinin geçerli dir sahip göreceli yolundan yükleyecektir localbelirttiğiniz yollara başvurmak.

COPY start.sh /runtime/start.sh

Dosyalar

Bu fikir göz önüne alındığında, Dockerfiles'in belirli şeyler inşa etmesi için birden fazla kopya almayı düşünebiliriz, ancak hepsinin start.sh.

./all-services/
   /start.sh
   /service-X/Dockerfile
   /service-Y/Dockerfile
   /service-Z/Dockerfile
./docker-compose.yaml

Bu yapı ve yukarıdaki dosyalar göz önüne alındığında, burada bir docker-compose.yml

liman işçisi-compose.yaml

  • Bu örnekte, sharedbağlam dir runtimedir.
    • Burada aynı zihinsel model, bu direktifin altındaki tüm dosyaların sözde dosyaya taşındığını düşünün context.
    • Benzer şekilde, sadece aynı dizine kopyalamak istediğiniz Docker dosyasını belirtin. Bunu kullanarak belirleyebilirsiniz dockerfile.
  • ana içeriğinizin bulunduğu dizin, ayarlanacak gerçek bağlamdır.

Aşağıdaki docker-compose.ymlgibidir

version: "3.3"
services:

  service-A
    build:
      context: ./all-service
      dockerfile: ./service-A/Dockerfile

  service-B
    build:
      context: ./all-service
      dockerfile: ./service-B/Dockerfile

  service-C
    build:
      context: ./all-service
      dockerfile: ./service-C/Dockerfile
  • all-servicebağlam olarak ayarlanırsa, paylaşılan dosya start.shorada her biri tarafından belirtilen Dockerfile da kopyalanır dockerfile.
  • Her biri kendi yolunu oluşturarak başlangıç ​​dosyasını paylaşıyor!

Şerefe!


1
Dockerfile üzerinde nokta bir klasör hiyerarşisinde ise kabul cevap ile sivri gibi, tamamen doğru değildir a/b/c, o zaman evet çalışan docker build .içinde cerişmenize izin vermez ../file-in-b. Ancak, bu (veya en azından benim) genel yanlış anlama, bağlamın Dockerfile'ın konumu tarafından değil, build komutunun ilk argümanı tarafından belirtilen konumla tanımlandığıdır. Kabul edilen cevapta belirtildiği gibi: from a: docker build -f a/b/c/Dockerfile . Dockerfile'da .şu an klasör anlamına gelira
βε.εηοιτ.βε

1
Dockerfile belgelerinden alıntı: dosya ve dizinlerin yolları derlemenin içeriğinin kaynağına göre yorumlanacaktır.
Nishant George Agrwal

18

Sayı 2745'teki tartışmayı okursanız, yalnızca docker sembolik bağlantıları asla destekleyemez, bağlamınızın dışında dosya eklemeyi asla desteklemeyebilir. Docker yapısına giren dosyaların açıkça bağlamının bir parçası olması veya yapının iyi bilinen URL'lerle veya dosyalarla birlikte gönderilen dosyalarla tekrarlanabilmesi için muhtemelen sabit bir sürümle konuşlandırıldığı bir URL'den olması gereken bir tasarım felsefesi gibi görünüyor. liman konteyner.

Sürüm kontrollü bir kaynaktan (yani docker build -t stuff http://my.git.org/repo) inşa etmeyi tercih ederim - aksi takdirde rastgele dosyalar içeren rastgele bir yerden inşa ediyorum.

temelde, hayır .... - SvenDowideit, Docker Inc

Sadece benim fikrim ama bence kodu ve liman işçilerinin depolarını ayırmak için yeniden yapılandırmalısınız. Bu şekilde kaplar genel olabilir ve kod oluşturma süresinden ziyade çalışma zamanında kodun herhangi bir sürümünü alabilir.

Alternatif olarak, docker'ı temel kod dağıtımı yapay nesneniz olarak kullanın ve dockerfile'ı kod havuzunun köküne koyun. bu rotaya giderseniz, daha genel sistem seviyesi ayrıntıları için bir üst docker konteynerine ve kodunuza özel kurulum için bir alt konteynere sahip olmak muhtemelen mantıklıdır.


Neden docker kullanıyorsunuz?
lscoughlin

11

Daha basit bir çözümün 'bağlam'ı' değiştirmek olacağını düşünüyorum.

Örneğin, vermek yerine:

docker build -t hello-demo-app .

geçerli dizini bağlam olarak ayarlar, diyelim ki üst dizini içerik olarak kullanmak istiyorsunuz, sadece şunu kullanın:

docker build -t hello-demo-app ..

6
Bence bu kopuyor .dockerignore: - \
NullVoxPopuli

Ben .dockerignore vazgeçti ve bunun yerine sadece yapı bağlamı için gerekli dosyaları içeren Makefile yönetilen docker klasörü yaptım ... Sadece çağırmak gerekir make buildve güncellenmiş eğer gerekli tüm dosyaları çeker ve sonra uygun docker yapı çağırır ... Ekstra iş yapmam gerekiyor, ama kusursuz bir şekilde çalıştığım için kusursuz bir şekilde çalışıyorum.
Sahsahae


3

Docker-compose kullanarak bunu, ihtiyacım olan birimleri bağlayan bir hizmet oluşturarak ve kabın görüntüsünü işleyerek başardım. Daha sonra, sonraki hizmette, bağlı konumlarda depolanan tüm verilerin bulunduğu daha önce kaydedilmiş görüntüye güveniyorum. Daha sonra, ana bilgisayara bağlı dizinler bir docker commitkomut çalıştırıldığında işlenmediği için bu dosyaları nihai hedeflerine kopyalamanız gerekecektir.

Bunu yapmak için docker-compose kullanmak zorunda değilsiniz, ancak hayatı biraz daha kolaylaştırır

# docker-compose.yml

version: '3'
  services:
    stage:
      image: alpine
      volumes:
        - /host/machine/path:/tmp/container/path
      command: bash -c "cp -r /tmp/container/path /final/container/path"
    setup:
      image: stage
# setup.sh

# Start "stage" service
docker-compose up stage

# Commit changes to an image named "stage"
docker commit $(docker-compose ps -q stage) stage

# Start setup service off of stage image
docker-compose up setup

1

HIPPA nedenlerinden ötürü repo bağlamında hareket edemediğim bir proje ve bazı veri dosyalarıyla aynı sorunu yaşadım. 2 Dockerfiles kullanarak sona erdi. Biri ana uygulamayı, konteynerin dışında ihtiyacım olan şeyler olmadan oluşturuyor ve bunu iç repoya yayınlıyor. Daha sonra ikinci bir dockerfile bu görüntüyü çeker ve verileri ekler ve daha sonra dağıtılan ve hiçbir yerde saklanmayan yeni bir görüntü oluşturur. İdeal değil, ama hassas bilgileri repo dışında tutmak için çalıştı.


1

Kolay bir çözüm, birimi çalıştırdığınızda (-v veya --mount bayrağını kullanarak) kapsayıcıya bağlamanız ve dosyalara bu şekilde erişmeniz olabilir.

misal:

docker run -v /path/to/file/on/host:/desired/path/to/file/in/container/ image_name

daha fazla bilgi için: https://docs.docker.com/storage/volumes/


Bunun yalnızca birimin çalışma zamanı bağımlılığı olması durumunda işe yaradığını unutmayın. İnşa süresi bağımlılıkları docker runiçin çok geç.
user3735633

1

Bu GitHub sayısında açıklandığı gibi, yapı aslında gerçekleşir /tmp/docker-12345, dolayısıyla göreli bir yol ../relative-add/some-filegörecelidir /tmp/docker-12345. Böylece,/tmp/relative-add/some-file hata mesajında ​​da gösterilen . *

Derleme dizininin dışından dosyalar eklenmesine izin verilmez, bu nedenle "Yasak yol" iletisiyle sonuçlanır.


0

Hızlı ve kirli bir yol, yapı bağlamını ihtiyacınız olduğu kadar çok seviyeye ayarlamaktır - ancak bunun sonuçları olabilir. Şuna benzeyen bir mikro hizmet mimarisinde çalışıyorsanız:

./Code/Repo1
./Code/Repo2
...

Yapı içeriğini üst öğeye ayarlayabilirsiniz Code dizine ve sonra her şeye erişebilirsiniz, ancak çok sayıda havuzla bu, yapının uzun zaman almasına neden olabilir.

Örnek bir durum, başka bir ekibin bir veritabanı şeması tutması Repo1ve ekibinizin kodununRepo2 bağlı olması olabilir. Şema değişiklikleri hakkında endişelenmeden veya diğer ekibin deposunu kirletmeden bu bağımlılığı kendi tohum verilerinizden biriyle sabitlemek istiyorsunuz (değişikliklerin ne olduğuna bağlı olarak, tabii ki tohum veri komut dosyalarınızı değiştirmek zorunda kalabilirsiniz) İkinci yaklaşım hacky ama uzun yapılar sorununu çözer:

./Code/Repo2İhtiyacınız olan dosyaları kopyalamak için sh (veya ps1) komut dosyası oluşturun ve istediğiniz docker komutlarını çağırın, örneğin:

#!/bin/bash
rm -r ./db/schema
mkdir ./db/schema

cp  -r ../Repo1/db/schema ./db/schema

docker-compose -f docker-compose.yml down
docker container prune -f
docker-compose -f docker-compose.yml up --build

Docker-compose dosyasında, içeriği Repo2kök olarak ayarlayın ./db/schemave yol hakkında endişelenmeden dockerfile dosyanızdaki dizinin içeriğini kullanın . Bu dizini yanlışlıkla kaynak denetimine alma riskini taşıyacağınızı unutmayın, ancak komut dosyası temizleme eylemleri yeterince kolay olmalıdır.


0

Benim durumumda, Dockerfile'ım yapılandırma dosyamı kullanarak gerçek değerle değiştirdiğim yer tutucuları içeren bir şablon gibi yazılıyor.

Bu yüzden bu dosyayı doğrudan belirleyemedim ama docker yapısına bu şekilde aktarın:

sed "s/%email_address%/$EMAIL_ADDRESS/;" ./Dockerfile | docker build -t katzda/bookings:latest . -f -;

Ancak boru yüzünden, COPYkomut işe yaramadı. Ancak yukarıdaki yol bunu -f -(dosya açıkça belirtilmediğini söyleyerek) çözer . Sadece bayrak -olmadan yapmak -f, bir uyarı olan bağlam VE Dockerfile sağlanmaz.


0

Hile, Docker yolunu belirtirseniz, üst komuttaki dosyaları dahil etmek için build komutundaki bağlamı belirtebileceğinizi tanımaktır, Dockerfile'ımı şöyle görünecek şekilde değiştirirdim:

...
COPY ./ /dest/
...

Sonra benim inşa komutu şöyle görünebilir:

docker built -t TAG -f DOCKER_FILE_PATH CONTEXT

Proje dizininden

docker built -t username/project[:tag] -f ./docker/Dockerfile .

Proje / liman işçisinden

docker built -t username/project[:tag] -f ./docker/Dockerfile ..
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.