Depois de algumas pesquisas e testes, descobri que tinha alguns mal-entendidos sobre a vida útil dos contêineres Docker. Simplesmente reiniciar um contêiner não faz com que o Docker use uma nova imagem, quando a imagem foi reconstruída nesse meio tempo. Em vez disso, o Docker busca a imagem apenas antes de criar o contêiner. Portanto, o estado após a execução de um contêiner é persistente.
Por que a remoção é necessária
Portanto, reconstruir e reiniciar não é suficiente. Achei que os containers funcionassem como um serviço: parando o serviço, faça suas alterações, reinicie-o e eles seriam aplicados. Esse foi meu maior erro.
Como os contêineres são permanentes, você deve removê-los usando docker rm <ContainerName>
primeiro. Depois que um contêiner é removido, você não pode simplesmente iniciá-lo por docker start
. Isso deve ser feito usando docker run
, que por si só usa a imagem mais recente para criar uma nova instância de contêiner.
Os recipientes devem ser o mais independentes possível
Com esse conhecimento, é compreensível por que o armazenamento de dados em contêineres é qualificado como uma prática ruim, e o Docker recomenda volumes de dados / montagem de diretórios de host em vez disso: Como um contêiner deve ser destruído para atualizar aplicativos, os dados armazenados dentro dele também seriam perdidos. Isso causa trabalho extra para desligar serviços, fazer backup de dados e assim por diante.
Portanto, é uma solução inteligente excluir completamente esses dados do contêiner: não precisamos nos preocupar com nossos dados, quando estão armazenados com segurança no host e o contêiner contém apenas o próprio aplicativo.
Por -rf
que não pode realmente ajudá-lo
O docker run
comando tem um switch de limpeza chamado -rf
. Isso interromperá o comportamento de manter os containers docker permanentemente. Usando -rf
, o Docker destruirá o contêiner após sua saída. Mas essa mudança tem dois problemas:
- O Docker também remove os volumes sem um nome associado ao contêiner, o que pode matar seus dados
- Usando esta opção, não é possível executar contêineres em segundo plano usando a
-d
chave
Embora a -rf
opção seja uma boa opção para economizar trabalho durante o desenvolvimento para testes rápidos, é menos adequada na produção. Especialmente por causa da falta da opção de executar um contêiner em segundo plano, o que na maioria das vezes seria necessário.
Como remover um recipiente
Podemos contornar essas limitações simplesmente removendo o contêiner:
docker rm --force <ContainerName>
A opção --force
(ou -f
) que usa SIGKILL em contêineres em execução. Em vez disso, você também pode parar o contêiner antes de:
docker stop <ContainerName>
docker rm <ContainerName>
Ambos são iguais. docker stop
também está usando SIGTERM . Mas usar a --force
opção encurtará seu script, especialmente ao usar servidores CI: docker stop
gera um erro se o contêiner não estiver em execução. Isso faria com que o Jenkins e muitos outros servidores de CI considerassem erroneamente o build como com falha. Para corrigir isso, você deve primeiro verificar se o contêiner está funcionando como eu fiz na pergunta (consulte a containerRunning
variável).
Script completo para reconstruir um contêiner Docker
De acordo com esse novo conhecimento, corrigi meu script da seguinte maneira:
#!/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
Isso funciona perfeitamente :)