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.

26
demandé sur Lion 2016-12-25 18:54:05

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:

  1. Docker supprime aussi les volumes sans nom associé au conteneur, ce qui peut tuer vos données
  2. 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 :)

60
répondu Lion 2017-10-24 11:00:10