Moby: Dockerfile COPY avec les globs de fichiers copiera les fichiers des sous-répertoires vers le répertoire de destination

CrĂ©Ă© le 26 aoĂ»t 2015  Â·  54Commentaires  Â·  Source: moby/moby

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

arebuilder

Commentaire le plus utile

Faites une nouvelle commande CP et faites-le bien cette fois s'il vous plaĂźt.

Tous les 54 commentaires

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,

image

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
Cette page vous a été utile?
0 / 5 - 0 notes