Dosya değişikliklerinde Docker kapsayıcısını yeniden oluşturun


93

Bir ASP.NET Core uygulamasını çalıştırmak için, uygulamayı derleyen ve Jenkins kullanarak Git tarafından getirilen konteynerdeki kaynak kodunu kopyalayan bir dockerfile oluşturdum. Bu yüzden çalışma alanımda dockerfile'da aşağıdakileri yapıyorum:

WORKDIR /app
COPY src src

Jenkins, ana bilgisayarımdaki dosyaları Git ile doğru bir şekilde güncellerken, Docker bunu imajıma uygulamıyor.

Oluşturmak için temel komut dosyam:

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

Yenisi oluşturulmadan önce kabı durdurmak / kaldırmak için --rmve --no-cacheparametre gibi farklı şeyler denedim . Burada neyi yanlış yaptığımdan emin değilim. Docker, görüntüyü doğru bir şekilde güncelliyor gibi görünüyor, çünkü çağrısı bir katman kimliği ile sonuçlanacak ve önbellek çağrısı yapılmayacaktır:docker runCOPY src src

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

Bir kapsayıcıyı güncellemenin önerilen yolu nedir?

Tipik senaryom şöyle olurdu: Uygulama sunucuda Docker konteynerinde çalışıyor. Artık uygulamanın bazı bölümleri, örneğin bir dosyayı değiştirerek güncellenir. Şimdi konteyner yeni sürümü çalıştırmalıdır. Docker, mevcut bir kapsayıcıyı değiştirmek yerine yeni bir görüntü oluşturmayı öneriyor gibi görünüyor, bu yüzden benim yaptığım gibi yeniden oluşturmanın genel yolunun doğru olduğunu düşünüyorum, ancak uygulamadaki bazı ayrıntıların iyileştirilmesi gerekiyor.


Oluşturma komutunuz ve her komutun çıktısının tamamı dahil olmak üzere, konteynerinizi oluşturmak için attığınız tam adımları listeleyebilir misiniz?
BMitch

Yanıtlar:


140

Biraz araştırma ve testten sonra, Docker konteynerlerinin kullanım ömrü hakkında bazı yanlış anlamalar yaşadığımı fark ettim. Bir konteynerin yeniden başlatılması, Docker'ın bu arada imaj yeniden oluşturulduğunda yeni bir imaj kullanmasına neden olmaz. Bunun yerine, Docker sadece resmi getirilirken edilir önce kapsayıcı oluşturmadan . Yani bir konteyner çalıştırdıktan sonraki durum kalıcıdır.

Kaldırma neden gerekli

Bu nedenle, yeniden oluşturmak ve yeniden başlatmak yeterli değildir. Container'ların bir hizmet gibi çalıştığını düşündüm: Hizmeti durdurun, değişikliklerinizi yapın, yeniden başlatın ve bunlar geçerli olur. Bu benim en büyük hatamdı.

Kaplar kalıcı olduğundan, docker rm <ContainerName>önce onları kullanarak kaldırmanız gerekir . Bir konteyner kaldırıldıktan sonra onu basitçe başlayamazsınız docker start. Bu, docker runyeni bir kapsayıcı örnek oluşturmak için en son görüntüyü kullanan kullanılarak yapılmalıdır .

Konteynerler olabildiğince bağımsız olmalıdır

Bu bilgiyle, verilerin konteynerlerde saklanmasının neden kötü bir uygulama olarak nitelendirildiği anlaşılır ve Docker bunun yerine veri hacimlerini / ana bilgisayar direktörlerini monte etmeyi öneriyor : Uygulamaları güncellemek için bir konteynerin yok edilmesi gerektiğinden, içeride depolanan veriler de kaybolacaktır. Bu, fazladan çalışmanın hizmetlerin kapatılmasına, verilerin yedeklenmesine vb. Neden olur.

Dolayısıyla, bu verileri tamamen kapsayıcıdan çıkarmak akıllıca bir çözüm: Ana bilgisayarda güvenli bir şekilde depolandığında ve kapsayıcı yalnızca uygulamanın kendisini tuttuğunda verilerimiz için endişelenmemize gerek yok.

Neden -rfsana gerçekten yardım etmeyebilir

docker runKomut, bir sahip Clean up denilen anahtarı -rf. Docker konteynerlerini kalıcı olarak tutma davranışını durduracaktır. -rfDocker kullanıldığında , konteynerden çıkıldıktan sonra onu yok edecektir. Ancak bu anahtarın iki sorunu vardır:

  1. Docker ayrıca kapsayıcıyla ilişkilendirilmiş bir adı olmayan birimleri kaldırır, bu da verilerinizi öldürebilir
  2. Bu seçeneği kullanarak, kapsayıcıları arka planda -danahtar kullanarak çalıştırmak mümkün değildir.

-rfAnahtar, hızlı testler için geliştirme sırasında işten tasarruf etmek için iyi bir seçenek olsa da , üretim için daha az uygundur. Özellikle arka planda bir konteyneri çalıştırma seçeneğinin eksik olması nedeniyle, ki bu çoğunlukla gerekli olacaktır.

Bir konteyner nasıl kaldırılır

Bu sınırlamaları, yalnızca kapsayıcıyı kaldırarak atlayabiliriz:

docker rm --force <ContainerName>

--force(Ya da -fkonteyner çalıştıran SIGKILL kullanın) geçer. Bunun yerine, kapsayıcıyı daha önce de durdurabilirsiniz:

docker stop <ContainerName>
docker rm <ContainerName>

İkisi de eşittir. docker stopayrıca SIGTERM kullanıyor . Ancak --forceswitch'i kullanmak , özellikle CI sunucularını kullanırken komut dosyanızı kısaltacaktır: docker stopkonteyner çalışmıyorsa bir hata atar. Bu, Jenkins ve diğer birçok CI sunucusunun yapıyı hatalı olarak başarısız olarak değerlendirmesine neden olur. Bunu düzeltmek için, önce konteynırın soruda yaptığım gibi çalışıp çalışmadığını kontrol etmelisiniz ( containerRunningdeğişkene bakın ).

Docker kapsayıcısını yeniden oluşturmak için tam komut dosyası

Bu yeni bilgiye göre senaryomu şu şekilde düzelttim:

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

Bu mükemmel çalışıyor :)


4
'Docker konteynerlerinin kullanım ömrü hakkında bazı yanlış anlamalar yaşadığımı fark ettim' kelimeleri ağzımdan çıkardınız. Bu kadar detaylı açıklama için teşekkür ederim. Bunu docker yeni başlayanlara tavsiye ederim. Bu, VM ile konteyner arasındaki farkı netleştirir.
Vince Banzon

2
Açıklamanızdan sonra, yaptığım şey mevcut imajıma ne yaptığımı not almak oldu. Değişikliklerin saklanması için, eklemek istediğim değişiklikleri zaten içeren yeni bir imaj oluşturmak için yeni bir Dockerfile oluşturdum. Bu şekilde, oluşturulan yeni görüntü (bir şekilde) güncellenir.
Vince Banzon

--force-recreateliman işçisi oluşturmadeneyimine üzerinde seçenek burada açıklamak ne benzer? Ve eğer öyleyse, onun yerine bu çözümü kullanmaya değmez mi (bu soru
aptalsa

2
@cglacet Evet, benzer, doğrudan karşılaştırılamaz. Ama docker-composebasit dockerkomutlardan daha akıllı . Düzenli olarak çalışıyorum docker-composeve değişiklik tespiti iyi çalışıyor, bu yüzden --force-recreateçok nadiren kullanıyorum. Sadece docker-compose up --buildsen (özel bir görüntü oluşturmaya yaparken önemlidir buildoluşturma dosyasında yönergesi) yerine Docker hub örneğin bir resim kullanmadan.
Lion

35

Dockerfile veya compose veya gereksinimlerde değişiklik yapıldığında, bunu kullanarak yeniden çalıştırın docker-compose up --build. Böylece görüntüler yeniden oluşturulur ve yenilenir


1
Bir hizmet olarak MySQL docker konteynerine sahip olmak, eğer bir birim için bir birim kullanılırsa DB bundan sonra boş olur /opt/mysql/data:/var/lib/mysqlmu?
Martin Thoma

Bana göre her zaman --buildyerel geliştirme ortamlarında kullanmanın herhangi bir dezavantajı yok gibi görünüyor . Docker'ın, kopyalamaya ihtiyaç duymayacağını varsayabileceği dosyaları yeniden kopyalama hızı yalnızca birkaç milisaniye sürer ve çok sayıda WTF anını kaydeder.
Danack

1

Kaçabilirsiniz buildçalıştırarak belirli bir hizmet için docker-compose up --build <service name>hizmet adı size liman işçisi-oluşturma dosyasında koydun nasıl eşleşmelidir nerede.

Örnek Docker-compose dosyanızın birçok hizmet (.net uygulaması - veritabanı - şifreleyelim ... vb.) İçerdiğini ve yalnızca applicationdocker-compose dosyasında olarak adlandırılan .net uygulamasını güncellemek istediğinizi varsayalım . Daha sonra basitçe koşabilirsinizdocker-compose up --build application

Ekstra parametreler Komutunuza, örneğin -darka planda çalışma gibi fazladan parametreler eklemek istemeniz durumunda , parametre servis adından önce olmalıdır: docker-compose up --build -d application

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.