Reconstruire le conteneur Docker sur les changements de fichier
pour exécuter un ASP.NET Core application, j'ai généré un fichier dockerfile qui construit l'application et copys le code source dans le conteneur, qui est récupéré par Git en utilisant Jenkins. Ainsi, dans mon espace de travail, je fais ce qui suit dans le fichier dockerfile:
WORKDIR /app
COPY src src
tandis que Jenkins met à jour les fichiers sur mon hôte correctement 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 docker run
et aussi arrêter/enlever le container avant le nouveau est build. Je ne suis pas sûr de ce que je fais de mal ici. Il semble que docker mette à jour l'image correctement, comme l'appel de COPY src src
résulterait en un ID de calque 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 tourne sur le serveur dans un conteneur Docker. Maintenant parties de l'application sont mis à jour, par exemple en modifiant un fichier. Maintenant le conteneur devrait exécuter la nouvelle version. Docker semble recommander de construire une nouvelle image au lieu de modifier un conteneur existant, donc je pense que la façon générale de reconstruire comme je le fais est juste, mais certains détails dans la mise en œuvre doit être améliorée.
1 réponses
après des recherches et des tests, j'ai découvert que j'avais des malentendus au sujet de la durée de vie des conteneurs Docker. Simplement redémarrer un conteneur ne fait pas Docker utiliser une nouvelle image, lorsque l'image a été reconstruite dans l'intervalle. Au lieu de cela, Docker ne récupère que l'image avant fonctionnement du conteneur. Donc l'état après avoir couru un conteneur est persistant.
pourquoi supprimer est nécessaire
par conséquent, la reconstruction et le redémarrage ne suffisent pas. Je pensez conteneurs fonctionne comme un service: arrêter le service, faire vos changements, redémarrer et ils s'appliqueraient. C'était ma plus grosse erreur.
parce que les conteneurs sont permanents, vous devez les enlever en utilisant docker rm <ContainerName>
en premier. Après qu'un conteneur est enlevé, vous ne pouvez pas simplement le démarrer par docker start
. Ceci doit être fait en utilisant docker run
, qui lui-même utilise la dernière image pour créer une nouvelle instance de conteneur.
les Conteneurs doivent être aussi indépendants que possible
avec cette connaissance, il est compréhensible pourquoi stocker des données dans des conteneurs est qualifié de mauvaise pratique et Docker recommande volumes de données/montage d'accueil répertoires au lieu de cela: Puisqu'un conteneur doit être détruit pour mettre à jour les applications, les données stockées à l'intérieur seraient également perdues. Cela cause du travail supplémentaire pour les services d'arrêt, sauvegarde des données et ainsi de suite.
C'est donc une solution intelligente d'exclure complètement ces données de la conteneur: nous n'avons pas à nous soucier de nos données, lorsque son stocké en toute sécurité sur l'hôte et le conteneur ne contient que l'application elle-même.
Pourquoi -rf
ne peut pas vraiment vous aider
docker run
commande, a un Nettoyage switch -rf
. Il va arrêter le comportement de garder les conteneurs docker de façon permanente. En utilisant -rf
, Docker détruira le conteneur une fois qu'il sera sorti. Mais ce commutateur a deux problèmes:
- Docker supprime aussi les volumes sans nom associé au conteneur, ce qui peut tuer vos données
- en utilisant cette option, il n'est pas possible de lancer des conteneurs en arrière-plan en utilisant
-d
switch
-rf
switch est une bonne option pour économiser du travail pendant le développement pour des tests rapides, il est moins adapté à la production. En particulier en raison de l'option manquante de lancer un conteneur dans l'arrière-plan, qui serait requis.
Comment enlever un contenant
On peut contourner ces limitations en enlevant simplement le conteneur:
docker rm --force <ContainerName>
--force
(ou -f
) commutateur qui utilise SIGKILL sur le fonctionnement des conteneurs. Au lieu de cela, vous pouvez également arrêter le conteneur avant:
docker stop <ContainerName>
docker rm <ContainerName>
les Deux sont égaux. docker stop
utilise aussi SIGTERM. Mais à l'aide de --force
switch raccourcira votre script, surtout si vous utilisez des serveurs CI:docker stop
jette une erreur si le conteneur ne tourne pas. Cela pourrait amener Jenkins et de nombreux autres serveurs de CI à considérer la construction à tort comme ayant échoué. Pour corriger cela, vous devez d'abord vérifier si le conteneur fonctionne comme je l'ai fait dans la question (voir containerRunning
variable).
script complet pour reconstruire un conteneur Docker
selon ces nouvelles connaissances, j'ai corrigé mon script de la façon suivante:
#!/bin/bash
imageName=xx:my-image
containerName=my-container
docker build -t $imageName -f Dockerfile .
echo Delete old container...
docker rm -f $containerName
echo Run new container...
docker run -d -p 5000:5000 --name $containerName $imageName
Cela fonctionne parfaitement :)