Pour exécuter une application ASP.NET Core, j'ai généré un fichier docker qui construit l'application et copie le code source dans le conteneur, qui est récupéré par Git à l'aide de Jenkins. Donc, dans mon espace de travail, je fais ce qui suit dans le dockerfile:
WORKDIR /app
COPY src src
Alors que Jenkins met correctement à jour les fichiers sur mon hôte avec Git, Docker ne l'applique pas à mon image.
Mon script de base pour la construction:
#!/bin/bash
imageName=xx:my-image
containerName=my-container
docker build -t $imageName -f Dockerfile .
containerRunning=$(docker inspect --format="{{ .State.Running }}" $containerName 2> /dev/null)
if [ "$containerRunning" == "true" ]; then
docker stop $containerName
docker start $containerName
else
docker run -d -p 5000:5000 --name $containerName $imageName
fi
J'ai essayé différentes choses comme --rm
et --no-cache
paramètre pour docker run
et aussi arrêter / supprimer le conteneur avant la construction du nouveau. Je ne sais pas ce que je fais de mal ici. Il semble que docker met correctement à jour l'image, car l'appel de COPY src src
entraînerait un identifiant de couche et aucun appel de cache:
Step 6 : COPY src src
---> 382ef210d8fd
Quelle est la méthode recommandée pour mettre à jour un conteneur?
Mon scénario typique serait: l'application s'exécute sur le serveur dans un conteneur Docker. Désormais, certaines parties de l'application sont mises à jour, par exemple en modifiant un fichier. Maintenant, le conteneur doit exécuter la nouvelle version. Docker semble recommander de créer une nouvelle image au lieu de modifier un conteneur existant, donc je pense que la manière générale de reconstruire comme je le fais est correcte, mais certains détails de l'implémentation doivent être améliorés.
Réponses:
Après quelques recherches et tests, j'ai constaté que j'avais des malentendus sur la durée de vie des conteneurs Docker. Le simple fait de redémarrer un conteneur ne permet pas à Docker d'utiliser une nouvelle image, lorsque l'image a été reconstruite entre-temps. Au lieu de cela, Docker récupère l'image uniquement avant de créer le conteneur. Ainsi, l'état après l'exécution d'un conteneur est persistant.
Pourquoi la suppression est nécessaire
Par conséquent, la reconstruction et le redémarrage ne suffisent pas. Je pensais que les conteneurs fonctionnaient comme un service: arrêter le service, faire vos modifications, le redémarrer et ils s'appliqueraient. C'était ma plus grosse erreur.
Les conteneurs étant permanents, vous devez d'abord les supprimer
docker rm <ContainerName>
. Une fois qu'un conteneur est supprimé, vous ne pouvez pas simplement le démarrerdocker start
. Cela doit être fait en utilisantdocker run
, qui utilise elle-même la dernière image pour créer une nouvelle instance de conteneur.Les conteneurs doivent être aussi indépendants que possible
Avec cette connaissance, on comprend pourquoi le stockage de données dans des conteneurs est qualifié de mauvaise pratique et Docker recommande plutôt des volumes de données / le montage de répertoires hôtes : puisqu'un conteneur doit être détruit pour mettre à jour les applications, les données stockées à l'intérieur seraient également perdues. Cela entraîne un travail supplémentaire pour arrêter les services, sauvegarder les données, etc.
C'est donc une solution intelligente pour exclure complètement ces données du conteneur: nous n'avons pas à nous soucier de nos données, lorsqu'elles sont stockées en toute sécurité sur l'hôte et que le conteneur ne contient que l'application elle-même.
Pourquoi
-rf
ne peut pas vraiment vous aiderLa
docker run
commande a un commutateur de nettoyage appelé-rf
. Cela arrêtera le comportement de garder les conteneurs docker de manière permanente. En utilisant-rf
, Docker détruira le conteneur après sa sortie. Mais ce commutateur a deux problèmes:-d
commutateurBien que le
-rf
commutateur soit une bonne option pour économiser du travail pendant le développement pour des tests rapides, il est moins adapté en production. Surtout à cause de l'option manquante pour exécuter un conteneur en arrière-plan, ce qui serait principalement nécessaire.Comment retirer un conteneur
Nous pouvons contourner ces limitations en supprimant simplement le conteneur:
Le commutateur
--force
(ou-f
) qui utilise SIGKILL sur des conteneurs en cours d'exécution. Au lieu de cela, vous pouvez également arrêter le conteneur avant:Les deux sont égaux.
docker stop
utilise également SIGTERM . Mais l'utilisation de--force
switch raccourcira votre script, en particulier lors de l'utilisation de serveurs CI:docker stop
génère une erreur si le conteneur n'est pas en cours d'exécution. Cela amènerait Jenkins et de nombreux autres serveurs CI à considérer à tort la construction comme un échec. Pour résoudre ce problème, vous devez d'abord vérifier si le conteneur fonctionne comme je l'ai fait dans la question (voircontainerRunning
variable).Script complet pour la reconstruction d'un conteneur Docker
En fonction de ces nouvelles connaissances, j'ai corrigé mon script de la manière suivante:
Cela fonctionne parfaitement :)
la source
--force-recreate
option de composition de docker est-elle similaire à ce que vous décrivez ici? Et si oui, cela ne vaudrait pas la peine d'utiliser cette solution à la place (désolé si cette question est idiote mais je suis un docker noob ^^)docker-compose
c'est plus intelligent que lesdocker
commandes simples . Je travaille régulièrement avecdocker-compose
et la détection de changement fonctionne bien, donc je l'utilise--force-recreate
très rarement. C'estdocker-compose up --build
important lorsque vous créez une image personnalisée (build
directive dans le fichier de composition) au lieu d'utiliser une image provenant par exemple du hub Docker.Chaque fois que des modifications sont apportées à dockerfile ou à composer ou aux exigences, réexécutez-le en utilisant
docker-compose up --build
. Pour que les images soient reconstruites et rafraîchiesla source
/opt/mysql/data:/var/lib/mysql
?--build
dans des environnements de développement locaux. La vitesse à laquelle docker recopie les fichiers qu'il pourrait supposer ne pas avoir besoin d'être copiés ne prend que quelques millisecondes et enregistre un grand nombre de moments WTF.Vous pouvez exécuter
build
pour un service spécifique en exécutantdocker-compose up --build <service name>
où le nom du service doit correspondre à la façon dont vous l'avez appelé dans votre fichier docker-compose.Exemple Supposons que votre fichier docker-compose contient de nombreux services (application .net - base de données - chiffrons ... etc) et que vous souhaitez mettre à jour uniquement l'application .net nommée comme
application
dans le fichier docker-compose. Vous pouvez alors simplement exécuterdocker-compose up --build application
Paramètres supplémentaires Si vous souhaitez ajouter des paramètres supplémentaires à votre commande, par exemple
-d
pour une exécution en arrière-plan, le paramètre doit être avant le nom du service:docker-compose up --build -d application
la source