Comment forcer Docker pour une construction propre d'une image

819

J'ai créé une image Docker à partir d'un fichier Docker à l'aide de la commande ci-dessous.

$ docker build -t u12_core -f u12_core .

Lorsque j'essaie de le reconstruire avec la même commande, il utilise le cache de génération comme:

Step 1 : FROM ubuntu:12.04
 ---> eb965dfb09d2
Step 2 : MAINTAINER Pavan Gupta <[email protected]>
 ---> Using cache
 ---> 4354ccf9dcd8
Step 3 : RUN apt-get update
 ---> Using cache
 ---> bcbca2fcf204
Step 4 : RUN apt-get install -y openjdk-7-jdk
 ---> Using cache
 ---> 103f1a261d44
Step 5 : RUN apt-get install -y openssh-server
 ---> Using cache
 ---> dde41f8d0904
Step 6 : RUN apt-get install -y git-core
 ---> Using cache
 ---> 9be002f08b6a
Step 7 : RUN apt-get install -y build-essential
 ---> Using cache
 ---> a752fd73a698
Step 8 : RUN apt-get install -y logrotate
 ---> Using cache
 ---> 93bca09b509d
Step 9 : RUN apt-get install -y lsb-release
 ---> Using cache
 ---> fd4d10cf18bc
Step 10 : RUN mkdir /var/run/sshd
 ---> Using cache
 ---> 63b4ecc39ff0
Step 11 : RUN echo 'root:root' | chpasswd
 ---> Using cache
 ---> 9532e31518a6
Step 12 : RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
 ---> Using cache
 ---> 47d1660bd544
Step 13 : RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
 ---> Using cache
 ---> d1f97f1c52f7
Step 14 : RUN wget -O aerospike.tgz 'http://aerospike.com/download/server/latest/artifact/ubuntu12'
 ---> Using cache
 ---> bd7dde7a98b9
Step 15 : RUN tar -xvf aerospike.tgz
 ---> Using cache
 ---> 54adaa09921f
Step 16 : RUN dpkg -i aerospike-server-community-*/*.deb
 ---> Using cache
 ---> 11aba013eea5
Step 17 : EXPOSE 22 3000 3001 3002 3003
 ---> Using cache
 ---> e33aaa78a931
Step 18 : CMD /usr/sbin/sshd -D
 ---> Using cache
 ---> 25f5fe70fa84
Successfully built 25f5fe70fa84

Le cache montre que l'aérospike est installé. Cependant, je ne le trouve pas à l'intérieur des conteneurs générés à partir de cette image, donc je veux reconstruire cette image sans utiliser le cache. Comment puis-je forcer Docker à reconstruire une image propre sans le cache?

Pavan Gupta
la source
10
En passant, vous devriez généralement essayer de minimiser le nombre de RUNdirectives.
tripleee
4
@tripleee Pouvez-vous expliquer pourquoi?
Ouais.
9
@Ya. Auparavant, Docker créait toujours une couche distincte pour chaque RUNdirective, donc une Dockerfileavec de nombreuses RUNdirectives consommerait des quantités gigantesques d'espace disque; mais cela a apparemment été quelque peu amélioré dans les versions récentes.
tripleee
Quand j'essaye docker-compose up -d, où puis-je l'utiliser --no-cache?
Oo
1
@Oo ce n'est pas possible. Vous devez d'abord faire docker-compose build --no-cacheet ensuitedocker-compose up -d
Martin Melka

Réponses:

1446

Il y a une --no-cacheoption:

docker build --no-cache -t u12_core -f u12_core .

Dans les anciennes versions de Docker, vous deviez réussir --no-cache=true, mais ce n'est plus le cas.

Assaf Lavie
la source
89
Notez également que cela --no-cachefonctionne avec docker-compose build.
Blackus
42
Vous pourriez également vouloir utiliser --pull. Cela indiquera à docker d'obtenir la dernière version de l'image de base. Ceci est nécessaire en plus --no-cachesi vous avez déjà l'image de base (ex:) ubuntu/latestet que l'image de base a été mise à jour depuis votre dernière extraction. Voir les documents ici .
Collin Krawll
2
@CollinKrawll: L' --pulloption a fait l'affaire pour moi. Juste --no-cache, la construction s'est encore cassée. Mettez --pullaussi, la construction a fonctionné! Je vous remercie!
Erdős-Bacon
1
Si quelqu'un appelle la construction de docker, ne suppose-t-on pas qu'il veut reconstruire sans le cache? Dans quel cas d'utilisation quelqu'un voudrait-il construire une image et utiliser une image précédemment construite? <rant> Je viens de perdre une journée car une version antérieure a échoué en silence mais s'est terminée "avec succès" et j'utilisais l'image cassée sans comprendre pourquoi les mises à jour du script de construction ne fonctionnaient pas </rant>
Jeff
3
@Jeff Lorsque vous développez une image Docker, la construction Docker ne refait que les couches / étapes qui ont été modifiées. Si j'ai cinq étapes et que j'ajoute une nouvelle étape à l'index 3, les couches associées aux étapes 1 et 2 peuvent être réutilisées. Cela accélère considérablement le processus de développement
s'écaille
130

Dans certains cas extrêmes, votre seul moyen de contourner les échecs de génération récurrents est d'exécuter:

docker system prune

La commande vous demandera votre confirmation:

WARNING! This will remove:
    - all stopped containers
    - all volumes not used by at least one container
    - all networks not used by at least one container
    - all images without at least one container associated to them
Are you sure you want to continue? [y/N]

Ce n'est bien sûr pas une réponse directe à la question, mais cela pourrait sauver des vies ... Cela a sauvé la mienne.

Wallace Sidhrée
la source
8
l'ajout de -a -f le rend meilleur
Ravi
1
@IulianOnofrei Works for me,Docker version 17.09.0-ce, build afdb6d4
Per Lundberg
1
@PerLundberg, j'ai mis dockerà jour la même version et ça marche, merci.
Iulian Onofrei
1
C'est beaucoup trop pour ce scénario et pas une réponse utilisable si vous ne voulez pas tout supprimer.
M_dk
1
Cela supprimera même les images des conteneurs arrêtés, probablement quelque chose que vous ne voulez pas. Les versions récentes de docker ont la commande docker builder prunepour effacer les couches de construction mises en cache. Je viens de tomber dans le piège après avoir copié aveuglément les commandes du débordement de pile.
Evil Azrael
59

La commande a docker build --no-cache .résolu notre problème similaire.

Notre Dockerfile était:

RUN apt-get update
RUN apt-get -y install php5-fpm

Mais aurait dû être:

RUN apt-get update && apt-get -y install php5-fpm

Pour empêcher la mise en cache de la mise à jour et installer séparément.

Voir: Meilleures pratiques pour écrire des Dockerfiles

Youniteus
la source
10
Le «aurait dû être» est trompeur. Si Docker voit qu'il a une copie en cache de RUN apt-get update && apt-get -y install php5-fpmvous, il verra toujours qu'il est réutilisé avec l'ancien contenu.
tripleee
10
En fait, il est toujours logique de les rejoindre, car sinon, si vous modifiez la ligne d'installation, il utilisera toujours l'ancien cache de package, qui aura souvent des problèmes si le cache est obsolète (généralement, les fichiers seront 404.)
John Chadwick
19

Pour vous assurer que votre build est complètement reconstruit, y compris la vérification de l'image de base pour les mises à jour, utilisez les options suivantes lors de la construction:

--no-cache - Cela forcera la reconstruction des couches déjà disponibles

--pull - Cela déclenchera une extraction de l'image de base référencée à l'aide de FROM pour vous assurer que vous avez la dernière version.

La commande complète ressemblera donc à ceci:

docker build --pull --no-cache --tag myimage:version .

Les mêmes options sont disponibles pour docker-compose:

docker-compose build --no-cache --pull
M_dk
la source
13

Je ne recommanderais pas d'utiliser --no-cachedans votre cas.

Vous exécutez quelques installations de l'étape 3 à 9 (en passant, je préférerais utiliser une seule ligne) et si vous ne voulez pas la surcharge de réexécuter ces étapes chaque fois que vous construisez votre image, vous pouvez modifier votre Dockerfileavec une étape temporaire avant votre wgetinstruction.

J'utilise pour faire quelque chose comme RUN ls .et le changer en RUN ls ./puis RUN ls ./.et ainsi de suite pour chaque modification effectuée sur l'archive récupérée parwget

Vous pouvez bien sûr faire quelque chose comme RUN echo 'test1' > test && rm testaugmenter le nombre 'test1pour chaque itération.

Cela a l'air sale, mais pour autant que je sache, c'est le moyen le plus efficace de continuer à bénéficier du système de cache de Docker, ce qui fait gagner du temps lorsque vous avez plusieurs couches ...

Olivier
la source
3
La possibilité de ne pas pouvoir utiliser le cache après un certain point est une fonctionnalité demandée par beaucoup (voir github.com/moby/moby/issues/1996 pour des alternatives pour le contournement du cache)
leszek.hanusz
13

Avec docker-compose try docker-compose up -d --build --force-recreate

Yash
la source
6

La plupart des informations fournies ici sont correctes.
Voici une compilation d'entre eux et ma façon de les utiliser.

L'idée est de s'en tenir à l'approche recommandée (spécifique à la construction et sans impact sur les autres objets docker stockés) et d'essayer l'approche la plus radicale (non spécifique à la construction et ayant un impact sur les autres objets docker stockés) lorsqu'elle ne suffit pas.

Approche recommandée:

1) Forcer l'exécution de chaque étape / instruction dans le Dockerfile:

docker build --no-cache 

ou avec docker-compose build:

docker-compose build --no-cache

Nous pourrions également combiner cela à la upsous-commande qui recrée tous les conteneurs:

docker-compose build --no-cache &&
docker-compose up -d --force-recreate 

De cette façon, n'utilisez pas le cache, mais pour le générateur de docker et l'image de base référencée avec l' FROMinstruction.

2) Essuyez le cache du générateur de docker (si nous utilisons Buildkit, nous en avons très probablement besoin):

docker builder prune -af

3) Si nous ne voulons pas utiliser le cache des images parentes, nous pouvons essayer de les supprimer telles que:

docker image rm -f fooParentImage

Dans la plupart des cas, ces 3 choses sont parfaitement suffisantes pour permettre une construction propre de notre image.
Nous devons donc essayer de nous en tenir à cela.

Approche plus radicale:

Dans les cas d'angle où il semble que certains objets dans le cache du docker sont toujours utilisés pendant la génération et que cela semble reproductible, nous devrions essayer de comprendre la cause pour pouvoir effacer la partie manquante de manière très spécifique. Si nous ne trouvons vraiment pas de moyen de reconstruire à partir de zéro, il existe d'autres moyens, mais il est important de se rappeler que ceux-ci suppriment généralement beaucoup plus que ce qui est nécessaire. Nous devons donc les utiliser avec prudence dans l'ensemble lorsque nous ne sommes pas dans un environnement local / dev.

1) Supprimez toutes les images sans au moins un conteneur qui leur est associé:

docker image prune -a

2) Retirez bien d'autres choses:

docker system prune -a

Ça dit :

ATTENTION! Cela supprimera:
  - tous les conteneurs arrêtés
  - tous les réseaux non utilisés par au moins un conteneur
  - toutes les images sans au moins un conteneur qui leur est associé
  - tout le cache de construction

L'utilisation de cette commande de super suppression peut ne pas être suffisante car elle dépend fortement de l'état des conteneurs (en cours d'exécution ou non). Lorsque cette commande ne suffit pas, j'essaie de réfléchir soigneusement aux conteneurs Docker qui pourraient provoquer des effets secondaires sur notre build Docker et de permettre à ces conteneurs d'être fermés afin de permettre leur suppression avec la commande.

davidxxx
la source
3

Vous pouvez gérer le cache du générateur avec docker builder

Pour nettoyer tout le cache sans invite: docker builder prune -af

Shawn
la source