it-swarm.com.de

Erstellen Sie den Docker-Container bei Dateiänderungen neu

Zum Ausführen einer ASP.NET Core-Anwendung habe ich eine Docker-Datei generiert, die die Anwendung erstellt und den Quellcode in den Container kopiert, der von Git mit Jenkins abgerufen wird. In meinem Arbeitsbereich mache ich in der Docker-Datei Folgendes:

WORKDIR /app
COPY src src

Während Jenkins die Dateien auf meinem Host mit Git korrekt aktualisiert, wendet Docker dies nicht auf mein Image an.

Mein grundlegendes Skript zum Erstellen:

#!/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

Ich habe verschiedene Dinge ausprobiert wie --rm und --no-cache Parameter für docker run und auch den Container anhalten/entfernen vorher der neue wird gebaut. Ich bin nicht sicher, was ich hier falsch mache. Es scheint, dass Docker das Bild korrekt aktualisiert, wie der Aufruf von COPY src src würde zu einer Layer-ID und keinem Cache-Aufruf führen:

Step 6 : COPY src src
 ---> 382ef210d8fd

Was ist die empfohlene Methode zum Aktualisieren eines Containers?

Mein typisches Szenario wäre: Die Anwendung wird auf dem Server in einem Docker-Container ausgeführt. Jetzt werden Teile der App aktualisiert, z. durch Ändern einer Datei. Jetzt sollte der Container die neue Version ausführen. Docker scheint zu empfehlen, ein neues Image zu erstellen, anstatt einen vorhandenen Container zu ändern. Daher halte ich die allgemeine Art der Neuerstellung für richtig, aber einige Details in der Implementierung müssen verbessert werden.

51
Lion

Nach einigen Recherchen und Tests stellte ich fest, dass ich einige Missverständnisse über die Lebensdauer von Docker-Containern hatte. Wenn Sie einen Container einfach neu starten, verwendet Docker kein neues Image, wenn das Image in der Zwischenzeit neu erstellt wurde. Stattdessen ruft Docker nur das Image ab , bevor der Container ausgeführt wird . Der Zustand nach dem Ausführen eines Containers bleibt also bestehen.

Warum ist das Entfernen erforderlich?

Daher reicht ein Neuaufbau und Neustart nicht aus. Ich dachte, Container funktionieren wie ein Dienst: Beenden Sie den Dienst, nehmen Sie Ihre Änderungen vor, starten Sie ihn neu, und sie werden angewendet. Das war mein größter Fehler.

Da Container permanent sind, müssen Sie sie zuerst mit docker rm <ContainerName> Entfernen. Nachdem ein Container entfernt wurde, kann er nicht einfach mit docker start Gestartet werden. Dies muss mit docker run Geschehen, das selbst das neueste Image verwendet, um eine neue Container-Instanz zu erstellen.

Die Container sollten so unabhängig wie möglich sein

Mit diesem Wissen ist es verständlich, warum das Speichern von Daten in Containern als schlechte Praxis qualifiziert und Docker empfiehlt Datenvolumen/Bereitstellen von Host-Verzeichnissen stattdessen: Da ein Container zum Aktualisieren zerstört werden muss Anwendungen würden die darin gespeicherten Daten ebenfalls verloren gehen. Dies verursacht zusätzlichen Aufwand beim Herunterfahren von Diensten, beim Sichern von Daten usw.

Daher ist es eine clevere Lösung, diese Daten vollständig aus dem Container auszuschließen: Wir müssen uns keine Gedanken über unsere Daten machen, wenn sie sicher auf dem Host gespeichert sind und der Container nur die Anwendung selbst enthält.

Warum -rf Ihnen vielleicht nicht wirklich hilft

Der Befehl docker run Verfügt über einen Schalter Clean up mit dem Namen -rf. Das Verhalten, Docker-Container dauerhaft zu behalten, wird gestoppt. Mit -rf Zerstört Docker den Container nach dem Verlassen. Dieser Schalter hat jedoch zwei Probleme:

  1. Docker entfernt auch die Volumes ohne einen dem Container zugeordneten Namen, wodurch Ihre Daten möglicherweise zerstört werden
  2. Mit dieser Option ist es nicht möglich, Container mit der Option -d Im Hintergrund auszuführen

Während der Schalter -rf Eine gute Option ist, um während der Entwicklung Arbeit für schnelle Tests zu sparen, ist er für die Produktion weniger geeignet. Vor allem wegen der fehlenden Option, einen Container im Hintergrund laufen zu lassen, was meistens erforderlich wäre.

So entfernen Sie einen Container

Wir können diese Einschränkungen umgehen, indem wir einfach den Container entfernen:

docker rm --force <ContainerName>

Der Schalter --force (Oder -f), Der SIGKILL für das Ausführen von Containern verwendet. Stattdessen können Sie den Container auch stoppen, bevor Sie:

docker stop <ContainerName>
docker rm <ContainerName>

Beide sind gleich. docker stop Verwendet auch SIGTERM . Die Verwendung des Schalters --force Verkürzt jedoch Ihr Skript, insbesondere bei Verwendung von CI-Servern: docker stop Löst einen Fehler aus, wenn der Container nicht ausgeführt wird. Dies würde dazu führen, dass Jenkins und viele andere CI-Server den Build fälschlicherweise als fehlgeschlagen betrachten. Um dies zu beheben, müssen Sie zuerst überprüfen, ob der Container wie in der Frage ausgeführt wird (siehe containerRunning Variable).

Vollständiges Skript zum Neuerstellen eines Docker-Containers

Aufgrund dieser neuen Erkenntnisse habe ich mein Skript folgendermaßen repariert:

#!/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

Das funktioniert perfekt :)

96
Lion

Wann immer Änderungen in Dockerfile oder Compose oder Anforderungen vorgenommen werden, führen Sie es erneut mit docker-compose up --build Aus. Damit die Bilder neu erstellt und aktualisiert werden

16
yunus