Aby uruchomić aplikację ASP.NET Core, wygenerowałem plik dockerfile, który buduje aplikację i kopiuje kod źródłowy w kontenerze, który jest pobierany przez Git przy użyciu Jenkinsa. Dlatego w moim obszarze roboczym wykonuję następujące czynności w pliku docker:
WORKDIR /app
COPY src src
Chociaż Jenkins poprawnie aktualizuje pliki na moim hoście za pomocą Git, Docker nie stosuje tego do mojego obrazu.
Mój podstawowy skrypt do budowania:
#!/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
Próbowałem różnych rzeczy, takich jak --rm
i --no-cache
parametrów, docker run
a także zatrzymywanie / usuwanie kontenera przed zbudowaniem nowego. Nie jestem pewien, co tu robię źle. Wygląda na to, że docker poprawnie aktualizuje obraz, ponieważ wywołanie COPY src src
spowodowałoby identyfikator warstwy i brak wywołania pamięci podręcznej:
Step 6 : COPY src src
---> 382ef210d8fd
Jaki jest zalecany sposób aktualizacji kontenera?
Mój typowy scenariusz byłby następujący: aplikacja działa na serwerze w kontenerze Docker. Teraz części aplikacji są aktualizowane, np. Poprzez modyfikację pliku. Teraz kontener powinien działać w nowej wersji. Wydaje się, że Docker zaleca budowanie nowego obrazu zamiast modyfikowania istniejącego kontenera, więc myślę, że ogólny sposób przebudowy, tak jak ja, jest właściwy, ale niektóre szczegóły implementacji muszą zostać poprawione.
Odpowiedzi:
Po kilku badaniach i testach odkryłem, że miałem pewne nieporozumienia dotyczące żywotności kontenerów Docker. Po prostu ponowne uruchomienie kontenera nie powoduje, że Docker używa nowego obrazu, gdy obraz został w międzyczasie odbudowany. Zamiast tego Docker pobiera obraz tylko przed utworzeniem kontenera. Zatem stan po uruchomieniu kontenera jest trwały.
Dlaczego usuwanie jest wymagane
Dlatego odbudowa i ponowne uruchomienie nie wystarczy. Myślałem, że kontenery działają jak usługa: zatrzymanie usługi, dokonanie zmian, ponowne uruchomienie i zastosowanie. To był mój największy błąd.
Ponieważ pojemniki są trwałe, musisz je
docker rm <ContainerName>
najpierw usunąć za pomocą . Po wyjęciu kontenera nie można go tak po prostu rozpocząćdocker start
. Należy to zrobić za pomocądocker run
, który sam używa najnowszego obrazu do tworzenia nowej instancji kontenera.Kontenery powinny być jak najbardziej niezależne
Mając tę wiedzę, jest zrozumiałe, dlaczego przechowywanie danych w kontenerach jest kwalifikowane jako zła praktyka, a Docker zaleca zamiast tego woluminy danych / montowanie katalogów hosta : ponieważ kontener musi zostać zniszczony, aby zaktualizować aplikacje, przechowywane w nim dane również zostałyby utracone. Powoduje to dodatkową pracę przy zamykaniu usług, tworzeniu kopii zapasowych danych i tak dalej.
Jest to więc sprytne rozwiązanie, aby całkowicie wykluczyć te dane z kontenera: nie musimy martwić się o nasze dane, gdy są one bezpiecznie przechowywane na hoście, a kontener zawiera tylko samą aplikację.
Dlaczego
-rf
tak naprawdę nie może ci pomócdocker run
Polecenie, ma oczyścić wyłącznik nazwie-rf
. Spowoduje to zatrzymanie trwale utrzymywania kontenerów docker. Używając-rf
, Docker zniszczy kontener po wyjściu z niego. Ale ten przełącznik ma dwa problemy:-d
przełącznikaChociaż
-rf
przełącznik jest dobrą opcją, aby zaoszczędzić pracę podczas programowania na potrzeby szybkich testów, jest mniej odpowiedni w środowisku produkcyjnym. Zwłaszcza z powodu braku opcji uruchomienia kontenera w tle, co byłoby najczęściej wymagane.Jak wyjąć pojemnik
Możemy ominąć te ograniczenia, po prostu usuwając kontener:
Przełącznik
--force
(lub-f
), który używa SIGKILL na uruchomionych kontenerach. Zamiast tego możesz również zatrzymać kontener przed:Obie są równe.
docker stop
używa również SIGTERM . Ale użycie--force
przełącznika skróci skrypt, szczególnie podczas korzystania z serwerów CI:docker stop
zgłasza błąd, jeśli kontener nie jest uruchomiony. To spowodowałoby, że Jenkins i wiele innych serwerów CI błędnie uznało kompilację za nieudaną. Aby to naprawić, musisz najpierw sprawdzić, czy kontener działa, tak jak ja w pytaniu (patrzcontainerRunning
zmienna).Pełny skrypt do przebudowy kontenera Dockera
Zgodnie z tą nową wiedzą, naprawiłem swój skrypt w następujący sposób:
To działa idealnie :)
źródło
--force-recreate
opcja w docker compose jest podobna do opisanej tutaj? A jeśli tak, czy nie warto byłoby zamiast tego skorzystać z tego rozwiązania (przepraszam, jeśli to głupie pytanie, ale jestem dokerem noob ^^)docker-compose
jest mądrzejszy niż zwykłedocker
polecenia. Pracuję regularniedocker-compose
i wykrywanie zmian działa dobrze, więc używam--force-recreate
bardzo rzadko. Tylkodocker-compose up --build
jest ważne, gdy budujesz własny obraz (build
dyrektywy do redagowania pliku) zamiast obrazu z użyciem np piastę Docker.Za każdym razem, gdy zostaną wprowadzone zmiany w pliku dockerfile, komponowaniu lub wymaganiach, uruchom je ponownie przy użyciu
docker-compose up --build
. Aby obrazy zostały odbudowane i odświeżoneźródło
/opt/mysql/data:/var/lib/mysql
?--build
w lokalnych środowiskach deweloperskich , nie ma żadnych wad . Szybkość, z jaką docker ponownie kopiuje pliki, które w innym przypadku mógłby założyć, nie wymaga kopiowania, zajmuje tylko kilka milisekund i oszczędza dużą liczbę momentów WTF.Możesz uruchomić
build
dla określonej usługi, uruchamiając,docker-compose up --build <service name>
gdzie nazwa usługi musi być zgodna z tym, jak ją nazwałeś w pliku Docker-Compose.Przykład Załóżmy, że twój plik docker-compose zawiera wiele usług (aplikacja .net - baza danych - zaszyfrujmy ... itd.) I chcesz zaktualizować tylko aplikację .net, która została nazwana tak jak
application
w pliku docker-compose. Możesz wtedy po prostu biecdocker-compose up --build application
Dodatkowe parametry W przypadku, gdy chcesz dodać dodatkowe parametry do polecenia, takie jak
-d
działanie w tle, parametr musi znajdować się przed nazwą usługi:docker-compose up --build -d application
źródło