Description du problĂšme:
Lorsque vous utilisez COPY
dans un Dockerfile
et que vous utilisez des globs pour copier des fichiers et des dossiers, docker copiera (parfois ?) également les fichiers des sous-dossiers vers le dossier de destination.
$ 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
Détails de l'environnement :
Configuration locale sur OSX /w boot2docker construit avec docker-machine
Comment reproduire :
Le contexte
$ tree
.
âââ Dockerfile
âââ files
âââ dir
â  âââ dirfile1
â  âââ dirfile2
â  âââ dirfile3
âââ file1
âââ file2
âââ file3
Fichier Docker
FROM busybox
RUN mkdir /test
COPY files/* /test/
RĂ©sultats actuels
$ docker run -it copybug ls -1 /test/
dirfile1
dirfile2
dirfile3
file1
file2
file3
RĂ©sultats attendus
L'image rĂ©sultante doit avoir la mĂȘme structure de rĂ©pertoires Ă partir du contexte
Message d'origine mis Ă jour avec la sortie de docker info
et uname -a
et reformaté selon le modÚle de rapport de problÚme.
J'ai eu ça sur 1.6.2 et 1.8
https://gist.github.com/jrabbit/e4f864ca1664ec0dd288 les rĂ©pertoires de deuxiĂšme niveau sont traitĂ©s comme ceux de premier niveau devraient l'ĂȘtre pour une raison quelconque ?
pour ceux qui recherchent sur Google : si vous rencontrez des problÚmes avec COPY * /src, essayez COPY / /src
@jfchevrette Je pense savoir pourquoi cela se produit.
Vous avez COPY files/* /test/
qui se transforme en COPY files/dir files/file1 files/file2 files/file /test/
. Si vous le divisez en commandes COPY individuelles (par exemple COPY files/dir /test/
), vous verrez que (pour le meilleur ou pour le pire) COPY copiera le contenu de chaque rĂ©pertoire arg dans le rĂ©pertoire de destination. Pas le rĂ©pertoire arg lui-mĂȘme, mais le contenu. Si vous avez ajoutĂ© un 3e niveau de rĂ©pertoires, je parie que ceux-ci resteront.
Je ne suis pas ravi du fait que COPY ne conserve pas le répertoire de niveau supérieur, mais c'est ainsi depuis un moment maintenant.
Vous pouvez essayer de rendre cela moins pénible en copiant un niveau supérieur dans l'arborescence src, si possible.
Je suis assez confiant que @duglin a raison et il pourrait ĂȘtre trĂšs risquĂ© de changer ce comportement. de nombreux dockerfiles peuvent casser ou simplement copier des Ă©lĂ©ments involontaires.
Cependant, je dirais qu'à long terme, il serait préférable que COPY suive la maniÚre dont des outils tels que cp ou rsync gÚrent les globs et les barres obliques de fin sur les dossiers. Il n'est certainement pas prévu que COPY copie des fichiers d'un sous-dossier correspondant à dir/* dans l'IMO de destination
@jfchevrette yep - la premiÚre chance que nous ayons, nous devrions "réparer" cela.
Je le ferme pour l'instant...
@duglin donc, la fermeture signifie que ça ne sera pas réparé ?
@tugberkugurlu oui , du moins pour le moment. Des travaux sont en cours pour refaire toute l'infrastructure de construction et lorsque nous le ferons, nous pourrons faire en sorte que COPY (ou son nouvel Ă©quivalent) agisse comme il se doit.
@duglin merci. Est-il possible de garder ce problÚme ouvert et de mettre à jour le statut ici ? Ou y a-t-il un autre problÚme auquel je peux souscrire ?
@tugberkugurlu Je pensais que nous avions un problÚme pour "le support du constructeur cÎté client" mais je n'arrive pas à le trouver. Donc, tout ce que nous pouvons avoir, c'est ce que dit la ROADMAP ( https://github.com/docker/docker/blob/master/ROADMAP.md#22-dockerfile-syntax ).
Quant Ă garder la question ouverte, je ne pense pas que nous puissions le faire. La rĂšgle gĂ©nĂ©rale suivie par Docker est de fermer immĂ©diatement tout problĂšme qui ne peut pas ĂȘtre traitĂ©. Les problĂšmes pour les travaux futurs sont gĂ©nĂ©ralement fermĂ©s puis rouverts une fois que l'Ă©tat des choses change, de sorte qu'une action (RP) peut ĂȘtre prise pour le problĂšme.
@duglin C'est un problÚme trÚs sérieux, vous ne devriez pas simplement le fermer car le problÚme a été introduit dans la version 0.1. Il serait plus approprié de cibler cela pour la version 2.0 (les jalons sont également sur github).
Je suppose que la plupart des gens utilisent :
COPY . /app
et mettre sur liste noire tous les autres dossiers dans .gitignore
ou avoir une structure de répertoires à un seul niveau et utiliser COPY
qui a en fait une sémantique mv
 :
COPY src /myapp
Il est assez difficile pour moi d'imaginer que quelqu'un utiliserait réellement COPY
pour aplatir la structure des répertoires. L'autre solution consiste à utiliser tar -cf .. & ADD tarfile.tar.gz
. Changer au moins cela serait vraiment utile. L'autre chose est de respecter les barres obliques dans les noms de répertoire COPY src /src
vs COPY src/ /src
(qui sont actuellement complÚtement ignorés).
duglin a fermé ceci le 1 sept. 2015
@duglin C'est un problĂšme ridicule et exaspĂ©rant et ne devrait pas ĂȘtre fermĂ©. La commande COPY
se comporte spécifiquement en désaccord avec l'utilisation documentée et les exemples.
@tjwebb il y a toujours un problĂšme ouvert https://github.com/docker/docker/issues/29211. Cela ne peut ĂȘtre examinĂ© que s'il existe un moyen de rĂ©soudre ce problĂšme qui est entiĂšrement rĂ©trocompatible. Nous sommes ouverts aux suggestions si vous avez une proposition _comment_ cela pourrait ĂȘtre mis en Ćuvre (si vous _faites_, n'hĂ©sitez pas Ă l'Ă©crire et Ă ouvrir une proposition, avec un lien vers ce problĂšme). Notez qu'il existe dĂ©jĂ une diffĂ©rence entre (par exemple), OS X et Linux dans la maniĂšre dont cp
est géré ;
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
OSÂ XÂ :
.
âââ 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
Sur 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
Faites une nouvelle commande CP et faites-le bien cette fois s'il vous plaĂźt.
Je ferais Ă©cho Ă ce qui prĂ©cĂšde, cela a dĂ» gaspiller d'innombrables heures de dĂ©veloppement, c'est extrĂȘmement peu intuitif.
+1 de ma part. C'est un comportement vraiment stupide et pourrait facilement ĂȘtre corrigĂ© en ajoutant simplement une commande CP qui fonctionne comme COPY devrait l'ĂȘtre.
La "rétrocompatibilité" est un flic
La version TL; DRÂ :
N'utilisez pas COPY * /app
, il ne fait pas ce que vous attendez de lui.
Utilisez plutĂŽt COPY . /app
pour conserver l'arborescence des répertoires.
COPY ne peut copier que son sous-dossier.
Je viens de passer d'innombrables heures dessus... Pourquoi cela fonctionne-t-il de cette façon ?
J'utilise Paket et je souhaite copier ce qui suit dans la bonne structure :
.
âââ .paket/
â âââ paket.exe
â âââ paket.bootstrapper.exe
âââ paket.dependencies
âââ paket.lock
âââ projectN/
Et en faisant COPY *paket* ./
il en résulte ceci à l'intérieur du conteneur :
.
âââ paket.dependencies
âââ paket.lock
Que diriez-vous d'ajouter un drapeau --glob
ou --recursive
pour COPY
et ADD
 ?
COPIE . /destination conserve les sous-dossiers.
Trois ans et c'est toujours un problĂšme :-/
Pouvons-nous obtenir une ETA, quand cela sera corrigé
pas une solution...
d'en haut...
COPIE .
Certes, ce n'est plus un problÚme aprÚs avoir fumé pendant une demi-journée et fini ici. Sûr :)
Soyons constructifs,
Nous avons vraiment besoin d'une nouvelle commande _CP_ ou d'un indicateur --recursive
pour _COPY_ afin que la rétrocompatibilité soit préservée.
Principaux points si nous affichons également un avertissement sur la création d'image, comme :
Directory structure not preserved with COPY *, use CP or COPY . More here <link>.
si nous détectons un éventuel abus.
Je recherche cela pour copier des fichiers lerna package.json imbriqués dans des sous-répertoires afin de mieux utiliser le cache npm install
pour ne se déclencher que lorsque les dépendances changent. Actuellement, tous les fichiers modifiés entraßnent la réinstallation des dépendances.
Quelque chose comme ça serait génial :
COPY ["package.json", "packages/*/package.json", "/app/"]
Allez vérifier # 29211 les gars. Celui-ci a été fermé et personne ne s'en soucie.
@zentby La conversation est ici, le problÚme y est suivi (puisque celui-ci est fermé) ... C'est déroutant.
une solution consiste Ă utiliser les fichiers COPY
et la commande RUN
cp -R
COPY files /tmp/
RUN cp -R /tmp/etc/* /etc/ && rm -rf /tmp/etc
Cela ne fonctionnera pas @instabledesign car la commande COPY détruit le cache lorsqu'un fichier est différent, ce qui ne devrait pas invalider le cache (par exemple, je veux uniquement copier les fichiers relatifs à l'installation de la dépendance npm car cela ne change pas souvent)
J'avais également besoin de copier uniquement un ensemble de fichiers (dans mon cas, les fichiers *.sln et *.csproj pour le noyau dotnet) dans le cache pervers. Une solution consiste à créer une boule tar contenant uniquement les fichiers de votre choix, puis à AJOUTER la boule tar dans le fichier Docker. Ouais, maintenant vous devez avoir un script shell en plus du fichier 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 ..
Fichier Docker
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
Vous pouvez utiliser plusieurs commandes COPY
pour ce faire, mais cela a l'inconvénient de créer plusieurs calques d'image et de gonfler la taille de votre image finale.
Comme kayjtea mentionné ci-dessus, vous pouvez également envelopper la commande docker build
dans un script de construction d'assistance pour créer des archives tar qui préservent la structure des répertoires et ADD
, mais cela ajoute de la complexité et casse des choses comme docker-compose build
et versions automatisées de Docker Hub.
Vraiment, COPY
devrait fonctionner comme une commande /bin/cp -r
conforme Ă POSIX, mais il semble que cela ne se produira pas pour la "compatibilitĂ© descendante", mĂȘme si le comportement actuel n'est pas du tout intuitif pour quiconque a de l'expĂ©rience dans les systĂšmes *nix.
Le meilleur compromis que j'ai trouvé est d'utiliser une construction en plusieurs étapes comme un hack :
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"]
Ceci est autonome dans un Dockerfile et ne crée qu'un seul calque dans l'image finale, tout comme le ferait un ADD project.tar
.
Avoir une commande complĂšte COPY
serait vraiment utile pour tenter de préserver le cache de construction du menu fixe. La communauté ROS se développe en utilisant un espace de travail imbriqué de packages, chacun déclarant des dépendances dans son propre fichier package.xml
. Ces fichiers sont utilisés par un gestionnaire de dépendances pour installer toutes les bibliothÚques en amont. Ces fichiers package.xml
changent relativement rarement par rapport au code dans les packages eux-mĂȘmes une fois que le travail de base est dĂ©fini. Si l'arborescence des rĂ©pertoires Ă©tait conservĂ©e lors d'une copie, nous pourrions simplement copier notre espace de travail lors de la construction du docker en deux Ă©tapes pour maximiser la mise en cache, par exemple :
# 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/
Ainsi, le cache de la couche d'installation des dépendances ci-dessus ne s'effondrerait que si le développeur modifiait une dépendance déclarée, tandis qu'un changement dans le code du package ne ferait que s'effondrer dans la couche de compilation.
Actuellement, tous les fichiers package.xml
correspondants sont copiés les uns sur les autres à la racine du répertoire de destination, le dernier fichier globe étant le seul package.xml
qui persiste dans l'image. Ce qui n'est vraiment pas intuitif pour les utilisateurs ! Pourquoi les fichiers copiés sont-ils écrasés les uns sur les autres, et dont le comportement indéfini persiste finalement dans l'image.
C'est une telle douleur dans pratiquement toutes les piles qui ont une gestion de paquets, donc cela affecte beaucoup d'entre nous. Peut-il ĂȘtre rĂ©parĂ©? Chut. C'est un problĂšme depuis 2015 ! La suggestion d'utiliser une nouvelle commande de CP
est bonne.
Pouvons-nous rouvrir cela ? C'est un comportement trÚs fastidieux que la commande COPY utilise une fonction interne golang pour la correspondance de chemin, plutÎt qu'une véritable norme largement adoptée, comme glob
Pour ceux qui souhaitent copier via globing en utilisant une solution de contournement avec une syntaxe de kit de construction expĂ©rimentale, mĂȘme si la mise en cache n'est pas aussi prĂ©cise ou robuste, vous pouvez consulter les commentaires ici : https://github.com/moby/moby/issues /39530#issuecomment -530606189
J'aimerais toujours que ce problÚme soit rouvert afin que nous puissions mettre en cache des copies sélectives de style glob.
J'ai réalisé une solution de contournement relativement simple pour mon exemple dans https://github.com/moby/moby/issues/15858#issuecomment -462017830 via des versions en plusieurs étapes , et j'ai pensé que beaucoup d'entre vous ici avec des besoins similaires pourraient apprécier la mise en cache arbitraire sur copié artefacts du contexte de génération. En utilisant des builds en plusieurs étapes, il est possible de filtrer/prétraiter le répertoire à mettre en 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/
Pour un exemple de travail dans le monde rĂ©el, vous pouvez Ă©galement jeter un Ćil ici : https://github.com/ros-planning/navigation2/pull/1122
Je recherche cela pour copier des fichiers lerna package.json imbriqués dans des sous-répertoires afin de mieux utiliser le cache
npm install
pour ne se déclencher que lorsque les dépendances changent. Actuellement, tous les fichiers modifiés entraßnent la réinstallation des dépendances.Quelque chose comme ça serait génial :
COPY ["package.json", "packages/*/package.json", "/app/"]
j'ai exactement le mĂȘme cas d'utilisation.
Je recherche cela pour copier des fichiers lerna package.json imbriqués dans des sous-répertoires afin de mieux utiliser le cache
npm install
pour ne se déclencher que lorsque les dépendances changent. Actuellement, tous les fichiers modifiés entraßnent la réinstallation des dépendances.Quelque chose comme ça serait génial :
COPY ["package.json", "packages/*/package.json", "/app/"]
Ce cas, mais pour les espaces de travail Yarn.
Nous sommes en 2020 et ce n'est toujours pas réglé.
Si quelqu'un a du mal avec cela dans un environnement dotnet, je l'ai résolu pour nous en écrivant un outil global dotnet core qui restaure la structure de répertoires pour les fichiers *.csproj, permettant une restauration à suivre. Voir la documentation sur la façon de le faire ici .
Pour votre information, thĂ©oriquement, une approche similaire pourrait ĂȘtre utilisĂ©e dans d'autres contextes, mais essentiellement l'outil procĂšde Ă une ingĂ©nierie inverse de la structure des dossiers, donc je ne sais pas Ă quel point cela serait facile ou mĂȘme possible, par exemple, une configuration d'espaces de travail lerna ou yarn. Heureux d'enquĂȘter s'il y a un intĂ©rĂȘt. Cela pourrait mĂȘme ĂȘtre possible dans le mĂȘme outil si les gens Ă©taient heureux d'installer le runtime dotnet core pour qu'il fonctionne, sinon la mĂȘme approche que j'ai faite devrait ĂȘtre construite dans un langage qui ne nĂ©cessite pas de nouvelle dĂ©pendance, comme node Je suppose.
Il est étonnant que l'implémentation d'une commande de copie ait été une tùche pour un étudiant la premiÚre année, et maintenant c'est trop complexe pour des programmeurs expérimentés avec de nombreuses années d'expérience...
Ce n'est probablement pas le bogue le plus embarrassant de tous les temps, mais compte tenu qu'il est suivi de nombreuses années de discussion sans aucune sortie, il se rattrape certainement au sommet.
@benmccallum
Pour votre information, thĂ©oriquement, une approche similaire pourrait ĂȘtre utilisĂ©e dans d'autres contextes, mais essentiellement, l'outil procĂšde Ă la rĂ©tro-ingĂ©nierie de la structure des dossiers,
N'est-il pas plus facile pour la plupart des occasions de faire ce que https://github.com/moby/moby/issues/15858#issuecomment -532016362 a suggéré et d'utiliser une construction en plusieurs étapes pour préfiltrer ?
De plus, pour le cas dotnet restore
, c'est un modÚle relativement simple :
# 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.
Cela ne constitue toujours pas une excuse appropriée pour que Docker n'ait jamais implémenté une variante décente sur la commande COPY
qui suit simplement la sémantique de synchronisation normale et saine.
Je veux dire; allez!
@rjgotten , j'aime ça ! Certainement beaucoup plus facile que ce que j'ai fait et je ne vois pas pourquoi cela ne fonctionnerait pas pour mes besoins. Je vais essayer demain et si cela fonctionne, je changerai mon doc pour le recommander comme une meilleure approche.
Je pense que mon problĂšme initial Ă©tait que j'Ă©tais sous Windows, donc j'ai probablement rejetĂ© cette suggestion. Je ne le suis plus, mais avez-vous une version Ă©quivalente de Windows pour ĂȘtre complet ? Je me demande si PowerShell est prĂ©-installĂ© dans les images principales de dotnet...
Y a-t-il vraiment un besoin pour le FROM supplĂ©mentaire / rĂ©pĂ©tĂ© ... cependant? Chaque fois que vous faites un RUN, cela crĂ©e une nouvelle couche pour la mise en cache, n'est-ce pas ? Peut-ĂȘtre qu'il me manque quelque chose, cela fait un moment que je n'ai pas eu Ă y penser !
Je me demande si PowerShell est pré-installé dans les images principales de dotnet...
Je pense que c'est en fait. Ce qui rendrait un peu plus facile de le faire de maniĂšre multiplateforme.
Y a-t-il vraiment un besoin pour le FROM supplémentaire / répété ... cependant?
Les étapes de construction isolées obtiennent une mise en cache de couche indépendante.
La premiÚre étape fait le travail de préparation. Puisqu'il doit initialement tout copier, il invalide toujours le cache de sa premiÚre couche, et donc les couches qui suivent, lorsque _n'importe quel_ fichier change. Mais cela ne vaut que pour les couches _dans cette étape de construction_.
La deuxiĂšme Ă©tape commence par _seulement_ copier dans les fichiers liĂ©s au projet et tant que ces fichiers sont les mĂȘmes - c'est-Ă -dire les mĂȘmes noms de fichiers ; mĂȘme contenu ; etc. - Ă travers les builds que la couche _n'invalidera pas_. Ce qui signifie que la couche dotnet restore
_également_ ne sera pas invalidée à moins que ces fichiers de projet ne soient réellement modifiés.
J'ai eu le temps de m'asseoir avec ça et je comprends maintenant! Docker est amusant car Ă moins que vous ne passiez toujours du temps avec lui, vous oubliez le fonctionnement de toutes les commandes. Surtout, j'avais oubliĂ© que la cmd RUN ne peut fonctionner que sur le systĂšme de fichiers de l'image Docker, pas sur les fichiers de contexte de construction. Vous ĂȘtes donc obligĂ© de tout COPIER avant de pouvoir effectuer une cmd RUN complexe qui prĂ©serve les rĂ©pertoires. Et c'est pourquoi nous avons dĂ©sespĂ©rĂ©ment besoin d'un COPY globbing dĂ©cent !
Cette approche
La commande COPY initiale consiste, comme vous l'avez mentionné, à copier _tout_, puis à extraire les fichiers .sln et .csproj dans un dossier /proj séparé. Tout changement de code invalidera ces étapes. Fondamentalement, la limitation que cela contourne est que l'impressionnant RUN
linux cmd ne peut fonctionner que sur des fichiers _sur l'image docker déjà _, apportés par le COPY gourmand avant.
Ensuite, une nouvelle Ă©tape est lancĂ©e et copie le contenu du dossier /proj sur lequel peut ensuite ĂȘtre utilisĂ© pour dotnet restore
. Ătant donnĂ© que la "clĂ©" du cache est essentiellement le fichier de hachage, cela cassera rarement cette couche de cache, ni la suivante dotnet restore
, vous évitant ainsi la restauration coûteuse. Agréable!
Mon approche
Utilise une seule étape de construction pour cela au prix de quelques commandes COPY supplémentaires pour transférer les fichiers qui affectent une restauration dotnet. J'aplatis spécifiquement tous les fichiers .csproj dans un répertoire, puis j'utilise mon outil global pour reconstruire la bonne structure de répertoires à partir du fichier d'entrée .sln. Ce n'est qu'aprÚs cela que je COPIE sur tous les fichiers src, afin que je puisse effectivement mettre en cache les couches jusqu'ici réguliÚrement, plutÎt que de devoir toujours COPIER sur tous les fichiers src à l'avance.
Plats Ă emporter
Je pense que cela dépendra de la base de code des gens quant à l'efficacité de chaque approche. Pour nous, dans un référentiel mono, nous avons BEAUCOUP de code partagé qui est copié dans la COPIE "all src over". .dockerignore aide ici, mais est difficile à maintenir, nous sommes donc assez "gourmands" dans cette COPIE ; donc c'est assez lent. Ainsi, mon approche, bien que légÚrement plus compliquée, serait probablement plus rapide pour nous que cette alternative.
Merci pour l'explication. Je n'arrive toujours pas Ă croire que nous devons mĂȘme avoir cette conversation haha. J'ai encore besoin d'enquĂȘter sur les nouveaux Ă©lĂ©ments de BuildKit pour voir si c'est plus facile maintenant. Est-ce que quelqu'un d'autre a fait ça?
EnquĂȘte BuildKit
RUN --mount=type=bind
- On dirait que cela nous permettrait de faire la cmd linux sophistiquée par rapport au contexte de construction (plutÎt que RUN
étant simplement limité au systÚme de fichiers de l'image). En effet, il utilise apparemment par défaut le contexte de construction.
RUN --mount=type=cache
- ressemble Ă une sorte de rĂ©pertoire de cache rĂ©utilisable (entre les versions de docker ?) Qui est prĂ©servĂ©Â ? Donc, en substance, nous n'aurions mĂȘme pas besoin de trop nous soucier d'une couche de cache pour les restaurations de packages, car avec un cache rĂ©utilisĂ© de packages prĂ©cĂ©demment restaurĂ©s, ce serait dĂ©jĂ beaucoup plus rapide ! ?
Je pense que le problÚme n'est pas encore résolu car il est "fermé" et les gens sont habitués aux solutions de contournement.
Lorsque vous ne comprenez pas pourquoi les gens ont tendance à se déplacer vers un autre type de conteneur.
Existe-t-il un autre type de conteneur que je peux utiliser. Vous ne pouvez pas croire que cela n'est pas pris en charge aprÚs tant d'années ? Docker est-il un projet open source, est-ce que quelqu'un peut le faire réparer ?
Nous avons une option COPY --dir
dans Earthly pour que la copie se comporte plus comme cp -r
. Peut-ĂȘtre que cela pourrait aussi ĂȘtre portĂ© sur Dockerfile ?
Pour accélérer la création d'images pour les applications principales .net, nous devons créer un conteneur intermédiaire qui contiendra tous les packages de nuget restaurés. Pour une solution multi-projets, j'ai utilisé cette solution de contournement. Je viens de copier tous les fichiers de projet dans un dossier unique et d'exécuter la restauration dotnet pour chacun d'eux. Il y a quelques avertissements concernant les projets manqués car nous ne pouvons pas conserver la hiérarchie des dossiers, mais c'est toujours une solution de travail.
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
Il y a quelques avertissements concernant les projets manqués car nous ne pouvons pas conserver la hiérarchie des dossiers, mais c'est toujours une solution de travail.
Non; ça ne marche pas. Et voici pourquoi :
.NET Core stocke les méta-informations de package dans le sous-répertoire ./obj
associĂ© Ă chaque projet. Sans ces informations, le package ne sera pas considĂ©rĂ© comme installĂ© et prĂȘt Ă l'emploi. (Ne me croyez pas? Ensuite, jetez votre dossier ./obj
, puis ouvrez par exemple le projet dans VSCode et regardez-le vous demander de relancer la restauration du paquet. Allez-y, essayez-le.)
Si les fichiers de projet sur lesquels vous exécutez la restauration du package se trouvent dans une structure de répertoires différente de celle des dotnet build
ou dotnet publish
, ces commandes ne verront pas le package comme restauré.
La raison pour laquelle votre solution n'échoue pas carrément est que dotnet publish
et dotnet build
impliquent tous deux dotnet restore
. Ils recherchent activement les packages non restaurés et les restaurent à la volée. Pour éviter qu'ils ne le fassent, vous devez activement passer le drapeau --no-restore
, ce que vous ne faites pas.
Donc, vraiment, votre solution restaure les packages _TWICE_. La premiĂšre fois est essentiellement une grande perte de temps et d'espace, car elle ne va pas dans la bonne structure de rĂ©pertoires pour ĂȘtre rĂ©utilisĂ©e. La deuxiĂšme fois, implicite dans le cadre de la commande publish
, fonctionne ; mais comme il fait partie de la mĂȘme couche que l'opĂ©ration de construction et de publication, vos packages ne sont pas du tout mis en cache sĂ©parĂ©ment de vos modifications de code.
@rjgotten ,
Merci pour votre réponse et vos éclaircissements.
En fait, tous les packages de nuget sont mis en cache dans le dossier global-packages
du conteneur docker 'build'. Dans mon cas, il s'agit du dossier /root/.nuget/packages/
, et le dossier obj
ne contient que de petits fichiers avec des références à ce stockage global, il n'y a donc pas de gaspillage de stockage (comme vous le mentionnez).
DeuxiĂšme restauration pendant la publication au moins x10 fois plus rapide (dans mon cas) car tous les nugets sont mis en cache dans le conteneur.
@zatuliveter @rjgotten merci pour l'info à la fin ici. Je rencontrais des problÚmes similaires et j'ai proposé le fichier dockerfile suivant pour améliorer les exemples que vous avez donnés. Bash n'est certainement pas mon fort alors allez-y doucement avec moi ! Notre structure est Project/Project.csproj
pour tous nos projets. Cela copie tous les fichiers proj, les déplace au bon endroit, puis restaure / copie tout / publie.
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
Commentaire le plus utile
Faites une nouvelle commande CP et faites-le bien cette fois s'il vous plaĂźt.