Moby: Dockerfile COPY dengan gumpalan file akan menyalin file dari subdirektori ke direktori tujuan

Dibuat pada 26 Agu 2015  Β·  54Komentar  Β·  Sumber: moby/moby

Deskripsi masalah:
Saat menggunakan COPY dalam Dockerfile dan menggunakan gumpalan untuk menyalin file & folder, buruh pelabuhan (kadang-kadang?) juga akan menyalin file dari subfolder ke folder tujuan.

$ docker version
Client:
 Version:      1.8.1
 API version:  1.20
 Go version:   go1.4.2
 Git commit:   d12ea79
 Built:        Thu Aug 13 19:47:52 UTC 2015
 OS/Arch:      darwin/amd64

Server:
 Version:      1.8.0
 API version:  1.20
 Go version:   go1.4.2
 Git commit:   0d03096
 Built:        Tue Aug 11 17:17:40 UTC 2015
 OS/Arch:      linux/amd64

$ docker info
Containers: 26
Images: 152
Storage Driver: aufs
 Root Dir: /mnt/sda1/var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 204
 Dirperm1 Supported: true
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 4.0.9-boot2docker
Operating System: Boot2Docker 1.8.0 (TCL 6.3); master : 7f12e95 - Tue Aug 11 17:55:16 UTC 2015
CPUs: 4
Total Memory: 3.858 GiB
Name: dev
ID: 7EON:IEHP:Z5QW:KG4Z:PG5J:DV4W:77S4:MJPX:2C5P:Z5UY:O22A:SYNK
Debug mode (server): true
File Descriptors: 42
Goroutines: 95
System Time: 2015-08-26T17:17:34.772268259Z
EventsListeners: 1
Init SHA1:
Init Path: /usr/local/bin/docker
Docker Root Dir: /mnt/sda1/var/lib/docker
Username: jfchevrette
Registry: https://index.docker.io/v1/
Labels:
 provider=vmwarefusion

$ uname -a
Darwin cerberus.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64

Detail lingkungan:
Pengaturan lokal di OSX /w boot2docker dibangun dengan mesin buruh pelabuhan

Cara Mereproduksi:

Konteks

$ tree
.
β”œβ”€β”€ Dockerfile
└── files
    β”œβ”€β”€ dir
    β”‚Β Β  β”œβ”€β”€ dirfile1
    β”‚Β Β  β”œβ”€β”€ dirfile2
    β”‚Β Β  └── dirfile3
    β”œβ”€β”€ file1
    β”œβ”€β”€ file2
    └── file3

file docker

FROM busybox

RUN mkdir /test
COPY files/* /test/

Hasil nyata

$ docker run -it copybug ls -1 /test/
dirfile1
dirfile2
dirfile3
file1
file2
file3

Hasil yang diharapkan
Gambar yang dihasilkan harus memiliki struktur direktori yang sama dari konteksnya

arebuilder

Komentar yang paling membantu

Buat CP perintah baru dan lakukan dengan benar kali ini.

Semua 54 komentar

Pesan asli yang diperbarui dengan keluaran dari docker info dan uname -a dan memformat ulang agar sesuai dengan template pelaporan masalah.

Saya sudah memiliki ini di 1.6.2 dan 1.8
https://Gist.github.com/jrabbit/e4f864ca1664ec0dd288 direktori tingkat kedua diperlakukan sebagai tingkat pertama karena suatu alasan?

untuk yang googling: jika Anda mengalami masalah dengan COPY * /src coba COPY / /src

@jfchevrette Saya pikir saya tahu mengapa ini terjadi.
Anda memiliki COPY files/* /test/ yang diperluas menjadi COPY files/dir files/file1 files/file2 files/file /test/ . Jika Anda membaginya menjadi perintah COPY individual (misalnya COPY files/dir /test/ ) Anda akan melihat bahwa (baik atau buruk) COPY akan menyalin konten setiap direktori arg ke direktori tujuan. Bukan dir arg itu sendiri, tetapi isinya. Jika Anda menambahkan dir tingkat ke-3, saya yakin itu akan bertahan.

Saya tidak senang dengan fakta bahwa COPY tidak mempertahankan direktori tingkat atas tetapi sudah seperti itu untuk sementara waktu sekarang.

Anda dapat mencoba membuat ini tidak terlalu menyakitkan dengan menyalin satu tingkat lebih tinggi di pohon src, jika memungkinkan.

Saya cukup yakin bahwa @duglin benar dan mengubah perilaku itu bisa sangat berisiko. banyak file docker dapat rusak atau hanya menyalin hal-hal yang tidak diinginkan.

Namun saya berpendapat bahwa untuk jangka panjang akan lebih baik jika COPY mengikuti cara alat seperti cp atau rsync menangani gumpalan & garis miring di folder. Jelas tidak diharapkan COPY untuk menyalin file dari subfolder yang cocok dengan dir/* ke IMO tujuan

@jfchevrette ya - kesempatan pertama yang kita dapatkan, kita harus "memperbaiki" ini.
Menutupnya untuk saat ini...

@duglin jadi, menutup berarti tidak akan diperbaiki?

@tugberkugurlu yup, setidaknya untuk saat ini. Ada pekerjaan yang sedang dilakukan untuk mengulang seluruh infrastruktur pembangunan dan ketika kami melakukannya, kami dapat membuat COPY (atau yang setara baru) bertindak sebagaimana mestinya.

@duglin terima kasih. Apakah mungkin untuk membiarkan masalah ini tetap terbuka dan memperbarui status di sini? Atau apakah ada masalah lain untuk ini yang bisa saya ikuti?

@tugberkugurlu Saya pikir kami memiliki masalah untuk "dukungan pembangun sisi klien" tetapi sepertinya saya tidak dapat menemukannya. Jadi yang mungkin kita miliki hanyalah apa yang dikatakan ROADMAP ( https://github.com/docker/docker/blob/master/ROADMAP.md#22-dockerfile-syntax ).

Untuk menjaga masalah tetap terbuka, saya tidak berpikir kita bisa melakukan itu. Aturan umum yang diikuti Docker adalah menutup masalah apa pun yang tidak dapat segera ditindaklanjuti. Masalah untuk pekerjaan masa depan biasanya ditutup dan kemudian dibuka kembali setelah keadaan berubah sehingga beberapa tindakan (PR) dapat diambil untuk masalah tersebut.

@duglin Ini adalah masalah yang sangat serius, Anda tidak boleh hanya menutupnya karena masalah tersebut diperkenalkan pada rilis 0.1. Akan lebih tepat untuk menargetkan ini untuk rilis 2.0 (tonggak sejarah juga ada di github).

Saya kira kebanyakan orang menggunakan:

COPY . /app

dan daftar hitam semua folder lain di .gitignore atau memiliki struktur direktori tingkat tunggal dan gunakan COPY yang sebenarnya memiliki mv semantik:

COPY src /myapp

Cukup sulit bagi saya untuk membayangkan bahwa seseorang akan benar-benar menggunakan COPY untuk meratakan struktur direktori. Solusi lain untuk ini adalah menggunakan tar -cf .. & ADD tarfile.tar.gz . Mengubah setidaknya ini akan sangat membantu. Hal lain adalah menghormati garis miring dalam nama direktori COPY src /src vs COPY src/ /src (yang saat ini sepenuhnya diabaikan).

duglin menutup ini pada 1 Sep 2015

@duglin Ini adalah masalah yang konyol dan menyebalkan dan tidak boleh ditutup. Perintah COPY berperilaku secara khusus tidak sesuai dengan penggunaan dan contoh yang didokumentasikan.

@tjwebb masih ada masalah terbuka https://github.com/docker/docker/issues/29211. Ini hanya dapat dilihat jika ada cara untuk memperbaikinya yang sepenuhnya kompatibel ke belakang. Kami terbuka untuk saran jika Anda memiliki proposal _bagaimana_ ini dapat diterapkan (jika Anda _melakukan_, jangan ragu untuk menulis ini, dan membuka proposal, menautkan ke masalah ini). Perhatikan bahwa sudah ada perbedaan antara (misalnya), OS X, dan Linux dalam cara menangani cp ;

mkdir -p repro-15858 \
  && cd repro-15858 \
  && mkdir -p source/dir1 source/dir2 \
  && touch source/file1 source/dir1/dir1-file1 \
  && mkdir -p target1 target2 target3 target4 target5 target6

cp -r source target1 \
&& cp -r source/ target2 \
&& cp -r source/ target3/ \
&& cp -r source/* target4/ \
&& cp -r source/dir* target5/ \
&& cp -r source/dir*/ target6/ \
&& tree

OSX:

.
β”œβ”€β”€ source
β”‚Β Β  β”œβ”€β”€ dir1
β”‚Β Β  β”‚Β Β  └── dir1-file1
β”‚Β Β  β”œβ”€β”€ dir2
β”‚Β Β  └── file1
β”œβ”€β”€ target1
β”‚Β Β  └── source
β”‚Β Β      β”œβ”€β”€ dir1
β”‚Β Β      β”‚Β Β  └── dir1-file1
β”‚Β Β      β”œβ”€β”€ dir2
β”‚Β Β      └── file1
β”œβ”€β”€ target2
β”‚Β Β  β”œβ”€β”€ dir1
β”‚Β Β  β”‚Β Β  └── dir1-file1
β”‚Β Β  β”œβ”€β”€ dir2
β”‚Β Β  └── file1
β”œβ”€β”€ target3
β”‚Β Β  β”œβ”€β”€ dir1
β”‚Β Β  β”‚Β Β  └── dir1-file1
β”‚Β Β  β”œβ”€β”€ dir2
β”‚Β Β  └── file1
β”œβ”€β”€ target4
β”‚Β Β  β”œβ”€β”€ dir1
β”‚Β Β  β”‚Β Β  └── dir1-file1
β”‚Β Β  β”œβ”€β”€ dir2
β”‚Β Β  └── file1
β”œβ”€β”€ target5
β”‚Β Β  β”œβ”€β”€ dir1
β”‚Β Β  β”‚Β Β  └── dir1-file1
β”‚Β Β  └── dir2
└── target6
    └── dir1-file1

20 directories, 12 files

Di Ubuntu (/bin/sh)

.
|-- source
|   |-- dir1
|   |   `-- dir1-file1
|   |-- dir2
|   `-- file1
|-- target1
|   `-- source
|       |-- dir1
|       |   `-- dir1-file1
|       |-- dir2
|       `-- file1
|-- target2
|   `-- source
|       |-- dir1
|       |   `-- dir1-file1
|       |-- dir2
|       `-- file1
|-- target3
|   `-- source
|       |-- dir1
|       |   `-- dir1-file1
|       |-- dir2
|       `-- file1
|-- target4
|   |-- dir1
|   |   `-- dir1-file1
|   |-- dir2
|   `-- file1
|-- target5
|   |-- dir1
|   |   `-- dir1-file1
|   `-- dir2
`-- target6
    |-- dir1
    |   `-- dir1-file1
    `-- dir2

24 directories, 12 files
diff --git a/macos.txt b/ubuntu.txt
index 188d2c3..d776f19 100644
--- a/macos.txt
+++ b/ubuntu.txt
@@ -11,15 +11,17 @@
 β”‚       β”œβ”€β”€ dir2
 β”‚       └── file1
 β”œβ”€β”€ target2
-β”‚   β”œβ”€β”€ dir1
-β”‚   β”‚   └── dir1-file1
-β”‚   β”œβ”€β”€ dir2
-β”‚   └── file1
+β”‚   └── source
+β”‚       β”œβ”€β”€ dir1
+β”‚       β”‚   └── dir1-file1
+β”‚       β”œβ”€β”€ dir2
+β”‚       └── file1
 β”œβ”€β”€ target3
-β”‚   β”œβ”€β”€ dir1
-β”‚   β”‚   └── dir1-file1
-β”‚   β”œβ”€β”€ dir2
-β”‚   └── file1
+β”‚   └── source
+β”‚       β”œβ”€β”€ dir1
+β”‚       β”‚   └── dir1-file1
+β”‚       β”œβ”€β”€ dir2
+β”‚       └── file1
 β”œβ”€β”€ target4
 β”‚   β”œβ”€β”€ dir1
 β”‚   β”‚   └── dir1-file1
@@ -30,6 +32,8 @@
 β”‚   β”‚   └── dir1-file1
 β”‚   └── dir2
 └── target6
-    └── dir1-file1
+    β”œβ”€β”€ dir1
+    β”‚   └── dir1-file1
+    └── dir2

-20 directories, 12 files
+24 directories, 12 files

Buat CP perintah baru dan lakukan dengan benar kali ini.

Saya akan menggemakan hal di atas, ini pasti telah membuang waktu pengembangan yang tak terhitung jumlahnya, ini sangat tidak intuitif.

+1 dari saya. Ini adalah perilaku yang benar-benar bodoh dan dapat dengan mudah diperbaiki hanya dengan menambahkan perintah CP yang melakukan bagaimana COPY seharusnya.

"Kompatibilitas mundur" adalah masalah

Versi TL;DR :

Jangan gunakan COPY * /app , itu tidak melakukan apa yang Anda harapkan.
Gunakan COPY . /app sebagai gantinya untuk mempertahankan pohon direktori.

COPY hanya dapat menyalin subfoldernya.

Hanya menghabiskan waktu berjam-jam untuk ini... Mengapa ini bekerja seperti ini?

Saya menggunakan Paket dan ingin menyalin yang berikut ini dalam struktur yang benar:

.
β”œβ”€β”€ .paket/
β”‚   β”œβ”€β”€ paket.exe
β”‚   β”œβ”€β”€ paket.bootstrapper.exe
β”œβ”€β”€ paket.dependencies
β”œβ”€β”€ paket.lock
β”œβ”€β”€ projectN/

Dan dengan melakukan COPY *paket* ./ itu menghasilkan ini di dalam wadah:

.
β”œβ”€β”€ paket.dependencies
β”œβ”€β”€ paket.lock

Bagaimana kalau menambahkan flag --glob atau --recursive untuk COPY dan ADD ?

SALIN. /destination mempertahankan sub-folder.

Tiga tahun dan ini masih menjadi masalah :-/

Bisakah kita mendapatkan ETA, kapan ini akan diperbaiki?

bukan masalah...
dari atas...
SALIN.

Benar, tidak ada lagi masalah setelah Anda mengasapi selama setengah hari dan berakhir di sini. Tentu :)
Mari membangun,

image

Kami benar-benar membutuhkan perintah _CP_ baru atau flag --recursive ke _COPY_ sehingga kompatibilitas mundur dipertahankan.

Poin teratas jika kami juga menampilkan peringatan pada pembuatan gambar, seperti:
Directory structure not preserved with COPY *, use CP or COPY . More here <link>. jika kami mendeteksi kemungkinan penyalahgunaan.

Saya mencari ini untuk menyalin di seluruh file lerna package.json bersarang di subdirektori untuk lebih memanfaatkan cache npm install untuk hanya memicu ketika dependensi berubah. Saat ini semua file berubah menyebabkan dependensi untuk menginstal lagi.

Sesuatu seperti ini akan bagus:

COPY ["package.json", "packages/*/package.json", "/app/"]

Cek #29211 guys. Yang ini telah ditutup dan tidak ada yang peduli.

@zentby Percakapan ada di sini, masalah dilacak di sana (karena yang ini ditutup)... Ini membingungkan.

solusinya adalah dengan COPY file dan perintah RUN cp -R

COPY files /tmp/
RUN cp -R /tmp/etc/* /etc/ && rm -rf /tmp/etc

Itu tidak akan berfungsi @instabledesign karena perintah COPY menghancurkan cache ketika file berbeda yang seharusnya tidak membatalkan cache (misalnya saya hanya ingin menyalin file yang berkaitan dengan instalasi ketergantungan npm karena itu tidak sering berubah)

Saya juga perlu menyalin hanya satu set file (dalam kasus saya, file *.sln dan *.csproj untuk inti dotnet) ke cache yang salah. Salah satu solusinya adalah membuat bola tar hanya dari file yang Anda inginkan dan kemudian TAMBAHKAN tarball di file Docker. Ya, sekarang Anda harus memiliki skrip shell selain file Docker ...

build.sh

#!/bin/bash

# unfortunately there's no easy way to copy just the *.sln and *.csproj (see https://github.com/moby/moby/issues/15858)
# so we generate a tar file containing the required files for the layer

find .. -name '*.csproj' -o -name 'Finomial.InternalServicesCore.sln' -o -name 'nuget.config' | sort | tar cf dotnet-restore.tar -T - 2> /dev/null

docker build -t finomial/iscore-build -f Dockerfile ..

berkas buruh pelabuhan

FROM microsoft/aspnetcore-build:2.0
WORKDIR /src

# set up a layer for dotnet restore 

ADD docker/dotnet-restore.tar ./

RUN dotnet restore

# now copy all the source and do the dotnet buld
COPY . ./

RUN dotnet publish --no-restore -c Release -o bin Finomial.InternalServicesCore.sln

Anda dapat menggunakan beberapa perintah COPY untuk melakukan ini, tetapi itu memiliki kelemahan dalam membuat beberapa lapisan gambar dan membengkakkan ukuran gambar akhir Anda.

Seperti yang disebutkan kayjtea di atas, Anda juga dapat membungkus perintah docker build dalam skrip build pembantu untuk membuat tarball yang mempertahankan struktur direktori, dan ADD mereka, tetapi itu menambah kerumitan dan merusak hal-hal seperti docker-compose build dan build otomatis Docker Hub.

Sungguh, COPY harus berfungsi seperti perintah /bin/cp -r yang sesuai dengan POSIX, tetapi sepertinya itu tidak akan terjadi untuk 'kompatibilitas mundur,' meskipun perilaku saat ini sama sekali tidak intuitif bagi siapa pun yang berpengalaman dalam sistem *nix.


Kompromi terbaik yang saya temukan adalah menggunakan build multi-tahap sebagai peretasan:

FROM scratch as project_root
# Use COPY to move individual directories
# and WORKDIR to change directory
WORKDIR /
COPY ./file1 .
COPY ./dir1/ ./dir1/
COPY ./dir2/ .
WORKDIR /newDir
COPY ./file2 .

# The actual final build you end up using/pushing
# Node.js app as example
FROM node
WORKDIR /opt/app

COPY package.json .
RUN npm install

COPY --from=project_root / .
CMD ["npm", "start"]

Ini mandiri dalam satu Dockerfile, dan hanya membuat satu lapisan di gambar akhir, seperti cara kerja ADD project.tar .

Memiliki perintah COPY yang lengkap akan sangat membantu ketika mencoba untuk mempertahankan cache build buruh pelabuhan. Komunitas ROS berkembang menggunakan ruang kerja paket bersarang, dengan masing-masing mendeklarasikan dependensi dalam file package.xml -nya sendiri. File-file ini digunakan oleh manajer ketergantungan untuk menginstal pustaka upstream apa pun. File package.xml ini relatif jarang berubah menjadi kode dalam paket itu sendiri setelah dasar ditetapkan. Jika struktur pohon direktori dipertahankan selama penyalinan, kita cukup menyalin ruang kerja kita selama pembangunan buruh pelabuhan dalam dua tahap untuk memaksimalkan caching misalnya:

# copy project dependency metadata
COPY ./**/package.xml /opt/ws/

# install step that fetches unsatisfied dependency
RUN dependency_manager install --workspace /opt/ws/

# copy the rest of the project's code
COPY ./ /opt/ws/

# compile code with cached dependencies
RUN build_tool build --workspace /opt/ws/

Dengan demikian, cache untuk lapisan pemasangan dependensi di atas hanya akan rusak jika pengembang kebetulan mengubah dependensi yang dideklarasikan, sementara perubahan dalam kode paket hanya akan merusak lapisan kompilasi.

Saat ini, semua file package.xml yang cocok sedang disalin di atas satu sama lain ke root direktori tujuan, dengan file globe terakhir menjadi satu-satunya package.xml yang bertahan dalam gambar. Yang benar-benar sangat tidak intuitif bagi pengguna! Mengapa file yang disalin ditimpa di atas satu sama lain, ditambah perilaku tidak terdefinisi yang akhirnya tetap ada dalam gambar.

Ini sangat merepotkan pada dasarnya setiap tumpukan yang memiliki manajemen paket, sehingga mempengaruhi banyak dari kita. Bisakah itu diperbaiki? Sheesh. Sudah menjadi masalah sejak 2015! Saran untuk menggunakan perintah baru CP adalah saran yang bagus.

Bisakah kita membuka kembali ini? Ini perilaku yang sangat membosankan bahwa perintah COPY menggunakan fungsi internal golang untuk pencocokan jalur, daripada standar yang diadopsi secara luas, seperti glob

Bagi mereka yang ingin menyalin melalui globing menggunakan solusi dengan sintaks buildkit eksperimental, bahkan jika caching tidak setepat atau kuat dapat melihat komentar di sini: https://github.com/moby/moby/issues /39530#issuecomment -530606189

Saya masih ingin melihat masalah ini dibuka kembali sehingga kami dapat menyimpan salinan gaya glob selektif.

Saya menyadari solusi yang relatif sederhana untuk contoh saya di https://github.com/moby/moby/issues/15858#issuecomment -462017830 melalui multi-tahap build , dan berpikir banyak dari Anda di sini dengan kebutuhan serupa mungkin menghargai caching sewenang-wenang pada salinan artefak dari konteks bangunan. Menggunakan build multi-tahap, dimungkinkan untuk memfilter/memproses direktori ke cache:

# Add prior stage to cache/copy from
FROM ubuntu AS package_cache

# Copy from build context
WORKDIR /tmp
COPY ./ ./src

# Filter or glob files to cache upon
RUN mkdir ./cache && cd ./src && \
    find ./ -name "package.xml" | \
      xargs cp --parents -t ../cache

# Continue with primary stage
FROM ubuntu

# copy project dependency metadata
COPY --from=package_cache /tmp/cache /opt/ws/

# install step that fetches unsatisfied dependency
RUN dependency_manager install --workspace /opt/ws/

# copy the rest of the project's code
COPY ./ /opt/ws/

# compile code with cached dependencies
RUN build_tool build --workspace /opt/ws/

Untuk contoh kerja dunia nyata, Anda juga dapat melihat di sini: https://github.com/ros-planning/navigation2/pull/1122

Saya mencari ini untuk menyalin di seluruh file lerna package.json bersarang di subdirektori untuk lebih memanfaatkan cache npm install untuk hanya memicu ketika dependensi berubah. Saat ini semua file berubah menyebabkan dependensi untuk menginstal lagi.

Sesuatu seperti ini akan bagus:

COPY ["package.json", "packages/*/package.json", "/app/"]

saya memiliki kasus penggunaan yang sama persis.

Saya mencari ini untuk menyalin di seluruh file lerna package.json bersarang di subdirektori untuk lebih memanfaatkan cache npm install untuk hanya memicu ketika dependensi berubah. Saat ini semua file berubah menyebabkan dependensi untuk menginstal lagi.

Sesuatu seperti ini akan bagus:

COPY ["package.json", "packages/*/package.json", "/app/"]

Kasus ini tetapi untuk ruang kerja Benang.

Ini tahun 2020 dan ini masih belum diperbaiki.

Jika ada yang berjuang dengan ini dalam pengaturan dotnet, saya telah menyelesaikannya untuk kami dengan menulis alat global inti dotnet yang mengembalikan struktur direktori untuk file *.csproj, memungkinkan pemulihan untuk mengikuti. Lihat dokumentasi tentang cara melakukannya di sini .

FYI, secara teoritis pendekatan serupa dapat digunakan dalam pengaturan lain, tetapi pada dasarnya alat ini merekayasa balik struktur folder, jadi saya tidak yakin seberapa mudah atau bahkan mungkin untuk mengatakan pengaturan ruang kerja lerna atau benang. Senang menyelidikinya jika ada minat. Bahkan dapat dimungkinkan di alat yang sama jika orang senang menginstal runtime inti dotnet agar berfungsi, jika tidak, pendekatan yang sama yang saya lakukan perlu dibangun dalam bahasa yang tidak memerlukan ketergantungan baru, seperti node Saya kira.

Sungguh menakjubkan bahwa mengimplementasikan perintah salin dulunya merupakan tugas bagi seorang siswa di tahun pertama, dan sekarang terlalu rumit untuk pemrogram terampil dengan pengalaman bertahun-tahun...

Ini mungkin bukan bug yang paling memalukan yang pernah ada, tetapi dengan mempertimbangkan bahwa itu diikuti oleh diskusi bertahun-tahun tanpa hasil apa pun, itu pasti mencapai puncak.

@benmccallum
FYI, secara teoritis pendekatan serupa dapat digunakan di pengaturan lain, tetapi pada dasarnya alat ini merekayasa balik struktur folder,

Bukankah lebih mudah bagi sebagian besar kesempatan untuk melakukan apa yang disarankan https://github.com/moby/moby/issues/15858#issuecomment -532016362 dan menggunakan build multi-tahap untuk melakukan prefilter?

Juga untuk kasus dotnet restore ini adalah pola yang relatif mudah:

# Prefiltering stage using find -exec and cp --parents to copy out
# the project files in their proper directory structure.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS dotnet-prep
COPY . ./src/
RUN mkdir ./proj && cd ./src && \
  find . -type f -a \( -iname "*.sln" -o -iname "*.csproj" \) \
    -exec cp --parents "{}" ../proj/ \;

# New build stage, independent cache
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS dotnet-build

# Copy only the project files with correct directory structure
# then restore packages
COPY --from=dotnet-prep ./proj ./src/
RUN dotnet restore

# Copy everything else
COPY --from=dotnet-prep ./src ./src/
# etc.

Masih tidak menjadi alasan yang tepat bagi Docker untuk tidak pernah mengimplementasikan varian yang layak pada perintah COPY yang hanya mengikuti semantik sinkronisasi yang normal dan waras.
Maksudku; Ayo!

@rjgotten , saya menyukainya! Tentu saja jauh lebih mudah daripada yang saya lakukan dan saya tidak dapat melihat mengapa ini tidak sesuai dengan kebutuhan saya. Saya akan mencobanya besok dan jika ini berhasil, saya akan mengubah dokumen saya untuk merekomendasikan ini sebagai pendekatan yang lebih baik.

Saya pikir masalah awal saya adalah saya menggunakan Windows jadi mungkin mengabaikan saran itu. Saya tidak lagi, tetapi apakah Anda memiliki versi Windows yang setara untuk kelengkapan? Saya ingin tahu apakah PowerShell sudah diinstal sebelumnya di gambar inti dotnet ...

Apakah benar-benar ada kebutuhan untuk FROM tambahan/berulang? Setiap kali Anda melakukan RUN, itu membuat layer baru untuk caching, bukan? Mungkin saya melewatkan sesuatu, sudah lama sejak saya harus memikirkan hal ini!

Saya ingin tahu apakah PowerShell sudah diinstal sebelumnya di gambar inti dotnet ...

Saya pikir itu sebenarnya. Yang akan membuatnya sedikit lebih mudah untuk melakukan ini dengan cara lintas platform.

Apakah benar-benar ada kebutuhan untuk FROM tambahan/berulang?

Tahap pembuatan yang terisolasi mendapatkan cache lapisan independen.
Tahap pertama melakukan pekerjaan persiapan. Karena awalnya harus menyalin semua yang ada di dalamnya, cache lapisan pertama selalu tidak valid, dan dengan demikian lapisan setelahnya, ketika file _any_ berubah. Tapi itu hanya berlaku untuk lapisan _dalam tahap pembangunan itu_.

Tahap kedua dimulai dengan _only_ menyalin file terkait proyek dan selama file tersebut sama - yaitu nama file yang sama; konten yang sama; dll. - di seluruh lapisan itu _tidak akan_ batal. Yang berarti lapisan dotnet restore _also_ tidak akan dibatalkan kecuali file proyek tersebut benar-benar diubah.

Punya waktu untuk duduk dengan ini dan saya mengerti sekarang! Docker menyenangkan karena kecuali Anda selalu menghabiskan waktu dengannya, Anda lupa bagaimana semua perintah bekerja. Yang terpenting, saya lupa bahwa RUN cmd hanya dapat beroperasi pada sistem file gambar buruh pelabuhan, bukan file konteks build. Jadi Anda dipaksa untuk MENYALIN semuanya sebelum Anda dapat melakukan RUN cmd kompleks yang mempertahankan direktori. Dan itulah mengapa kami sangat membutuhkan globbing COPY yang layak!

Pendekatan itu
COPY cmd awal adalah, seperti yang Anda sebutkan, menyalin _semuanya_ dan kemudian mengeluarkan file .sln dan .csproj ke dalam folder /proj terpisah. Setiap perubahan kode akan membatalkan langkah-langkah ini. Yang terpenting, batasan yang diatasi adalah bahwa cmd linux RUN yang mengagumkan hanya dapat beroperasi pada file _pada gambar buruh pelabuhan yang sudah_, dibawa oleh COPY serakah sebelumnya.

Kemudian tahap baru dimulai, dan menyalin isi folder /proj yang kemudian dapat digunakan untuk dotnet restore . Karena "kunci" cache pada dasarnya adalah hash file, ini jarang akan merusak lapisan cache ini, atau dotnet restore berikutnya, jadi Anda menghindari pemulihan yang mahal. Bagus!

Pendekatan saya
Hanya menggunakan satu tahap pembuatan untuk ini dengan biaya beberapa perintah SALIN lagi untuk membawa file yang memengaruhi pemulihan dotnet. Saya secara khusus meratakan semua file .csproj menjadi satu direktori, dan kemudian menggunakan alat global saya untuk membangun kembali struktur direktori yang benar dari entri file .sln. Hanya setelah ini saya MENYALIN semua file src, jadi saya dapat secara efektif men-cache lapisan sampai ke sini secara teratur, daripada selalu harus MENYALIN semua file src di depan.

Bawa pulang
Saya pikir itu akan tergantung pada basis kode orang tentang seberapa efektif setiap pendekatan. Bagi kami, dalam repo mono, kami memiliki BANYAK kode bersama yang disalin di "all src over" COPY. .dockerignore membantu di sini, tetapi sulit untuk dipertahankan, jadi kami cukup "rakus" dalam COPY itu; jadi cukup lambat. Dengan demikian, pendekatan saya, meskipun sedikit lebih rumit, mungkin akan lebih cepat bagi kita daripada alternatif ini.

Terima kasih atas penjelasannya. Masih tidak percaya kita bahkan harus melakukan percakapan ini haha. Saya masih perlu menyelidiki hal-hal BuildKit yang lebih baru untuk melihat apakah ini lebih mudah sekarang. Apakah ada orang lain yang melakukan itu?

Investigasi BuildKit
RUN --mount=type=bind - Kedengarannya seperti ini akankah ini memungkinkan kita untuk melakukan cmd linux yang mewah terhadap konteks build (daripada RUN hanya dibatasi pada sistem file gambar). Memang itu tampaknya default ke konteks build.

RUN --mount=type=cache - terdengar seperti semacam direktori cache yang dapat digunakan kembali (antara build buruh pelabuhan?) yang dipertahankan? Jadi intinya, kita bahkan tidak perlu terlalu khawatir tentang lapisan cache untuk pemulihan paket, karena dengan cache yang digunakan kembali dari paket yang sebelumnya dipulihkan, itu akan menjadi jauh lebih cepat!?

Saya pikir masalahnya belum diperbaiki karena "tertutup" dan orang-orang sudah terbiasa dengan solusinya.

Ketika Anda tidak mengerti mengapa orang cenderung pindah ke jenis wadah lain.

Apakah ada jenis wadah lain yang bisa saya gunakan. Tidak percaya ini tidak didukung setelah bertahun-tahun? Apakah buruh pelabuhan merupakan proyek sumber terbuka, adakah yang bisa memperbaikinya?

Kami memiliki opsi COPY --dir di Earthly untuk membuat salinan berperilaku lebih seperti cp -r . Mungkin ini bisa di-porting ke Dockerfile juga?

Untuk mempercepat pembuatan gambar untuk aplikasi inti .net, kita harus membuat beberapa wadah perantara yang akan berisi semua paket nuget yang dipulihkan. Untuk solusi multi-proyek saya menggunakan solusi ini. Saya baru saja menyalin semua file proyek ke satu folder dan menjalankan pemulihan dotnet untuk masing-masingnya. Ada beberapa peringatan tentang proyek yang terlewat karena kami tidak dapat mempertahankan hierarki folder, tetapi ini masih merupakan solusi yang berfungsi.

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build

# Nugets restore
WORKDIR /src/allprojects          # just temporary storage for .csproj files
COPY */*.csproj ./
RUN for file in $(ls *.csproj); do dotnet restore ${file}; done

# Build/Publish
WORKDIR /src/solution             # actual folder with source code and full hierarchy 
COPY . .
RUN dotnet publish "MyProject/MyProject.csproj" -c Release -o /bublish/myproject

# Run Application
FROM mcr.microsoft.com/dotnet/core/runtime:3.1 AS base
WORKDIR /app
COPY --from=build /bublish/myproject .
ENTRYPOINT ["dotnet", "MyProject.dll"]

@zatuliveter
Ada beberapa peringatan tentang proyek yang terlewat karena kami tidak dapat mempertahankan hierarki folder, tetapi ini masih merupakan solusi yang berfungsi.

Tidak; itu tidak bekerja. Dan inilah alasannya:

.NET Core menyimpan informasi meta paket di subdirektori ./obj yang terkait dengan setiap proyek. Tanpa informasi tersebut, paket tidak akan dianggap terinstal dan siap digunakan. (Tidak percaya? Kemudian buang folder ./obj Anda dan misalnya, buka proyek di VSCode dan lihat ia meminta Anda untuk menjalankan kembali pemulihan paket. Silakan; cobalah.)

Jika file proyek tempat Anda menjalankan pemulihan paket berada dalam struktur direktori yang berbeda dari dotnet build atau dotnet publish berikut, maka perintah tersebut tidak akan melihat paket telah dipulihkan.

Alasan solusi Anda tidak langsung gagal, adalah karena dotnet publish dan dotnet build keduanya menyiratkan dotnet restore . Mereka secara aktif memeriksa paket yang tidak dipulihkan dan memulihkannya dengan cepat. Untuk menghindari mereka melakukan ini, Anda secara aktif harus melewati flag --no-restore , yang tidak Anda lakukan.

Jadi sungguh, solusi Anda adalah memulihkan paket _TWICE_. Pertama kali pada dasarnya membuang-buang waktu dan ruang, karena tidak masuk ke struktur direktori yang benar untuk digunakan kembali. Kedua kalinya, implisit sebagai bagian dari perintah publish , bekerja; tetapi karena ini adalah bagian dari lapisan yang sama dengan operasi build&publish, paket Anda sebenarnya tidak di-cache terpisah dari perubahan kode Anda sama sekali.

@rjgotten ,
Terima kasih atas jawaban dan klarifikasi Anda.
Sebenarnya semua paket nuget di-cache di folder global-packages di 'build' docker container. Dalam kasus saya ini adalah folder /root/.nuget/packages/ , dan folder obj hanya berisi file kecil dengan referensi ke penyimpanan global ini, jadi tidak ada pemborosan penyimpanan (seperti yang Anda sebutkan).
Pemulihan kedua selama publikasi setidaknya x10 kali lebih cepat (dalam kasus saya) karena semua nuget di-cache dalam wadah.

@zatuliveter @rjgotten terima kasih atas infonya di akhir sini. Saya mengalami masalah serupa dan muncul dengan sedikit dockerfile berikut untuk memperbaiki contoh yang Anda berikan. Bash jelas bukan setelan kuatku, jadi santai saja! Struktur kami adalah Project/Project.csproj untuk semua proyek kami. Ini menyalin semua file proj, memindahkannya ke tempat yang benar, dan kemudian melakukan pemulihan / salin semua / publikasikan.

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ./*/*.csproj ./proj/
RUN for file in $(ls ./proj); do mkdir /src/${file%.*} && mv ./proj/${file} /src/${file%.*}/${file}; done
RUN dotnet restore "MyProject/MyProject.csproj"
COPY . .
WORKDIR "/src/MyProject"
RUN dotnet publish "MyProject.csproj" -c Release -o /app --no-restore
Apakah halaman ini membantu?
0 / 5 - 0 peringkat