在文件更改时重buildDocker容器

为了运行ASP.NET Core应用程序,我生成了一个dockerfile,它构build应用程序,并复制容器中的源代码,该容器由Git使用Jenkins提取。 所以在我的工作区中,我在dockerfile中执行以下操作:

WORKDIR /app COPY src src 

当Jenkins使用Git正确更新我的主机上的文件时,Docker不会将其应用于我的映像。

我的基本build设脚本:

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

我尝试了不同的东西,例如--rm--no-cache参数,以及构build新容器之前停止/移除容器。 我不确定我在这里做错了什么。 看来docker正在更新正确的图像,因为COPY src src的调用会导致层id和没有caching调用:

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

什么是更新容器的推荐方法?

我的典型场景是:应用程序在Docker容器中的服务器上运行。 现在部分应用程序被更新,例如通过修改文件。 现在容器应该运行新版本。 Docker似乎build议创build一个新的映像,而不是修改一个现有的容器,所以我认为像我这样做的一般重build方式是正确的,但实施中的一些细节有待改进。

经过一番研究和testing,我发现我对Docker容器的生命周期有一些误解。 简单地重启一个容器并不会让Docker使用一个新的图像,当时图像被重build。 相反,Docker仅运行容器之前获取图像。 所以运行一个容器后的状态是持久的。

为什么需要删除

所以重build和重启是不够的。 我以为容器的工作就像一个服务:停止服务,做你的改变,重新启动它,他们将适用。 那是我最大的错误。

因为容器是永久的,所以你必须首先使用docker rm <ContainerName>来移除它们。 一个容器被删除后,你不能简单地通过docker start来启动它。 这必须使用docker run来完成, docker run本身使用最新的镜像来创build一个新的容器实例。

集装箱应尽可能独立

有了这些知识,可以理解为什么在容器中存储数据被认为是不好的做法,而Dockerbuild议使用数据卷/挂载主导向器:因为必须销毁容器来更新应用程序,所以内部存储的数据也会丢失。 这会导致额外的工作closures服务,备份数据等等。

因此,将这些数据完全从容器中排除是一个明智的解决scheme:当数据安全地存储在主机上并且容器仅保存应用程序本身时,我们不必担心数据。

为什么-rf可能不会真的帮你

docker run命令,有一个名为-rf清理开关。 这将停止永久保持docker集装箱的行为。 使用-rf ,Docker在退出后将销毁容器。 但是这个开关有两个问题:

  1. Docker也删除没有与容器相关联的名称的卷,这可能会导致数据中断
  2. 使用这个选项,不可能使用-d开关在后台运行容器

在快速testing的开发过程中, -rf开关是一个很好的select,因此在生产中不太合适。 特别是因为缺less在后台运行容器的选项,这将主要是需要的。

如何删除一个容器

我们可以通过简单地删除容器来绕过这些限制:

 docker rm --force <ContainerName> 

在运行容器上使用SIGKILL的--force (或-f )开关。 相反,您也可以在以下时间停止容器:

 docker stop <ContainerName> docker rm <ContainerName> 

两者是平等的。 docker stop也在使用SIGTERM 。 但是使用--force切换会缩短脚本,特别是在使用CI服务器的时候:如果容器没有运行, docker stop会抛出一个错误。 这会导致Jenkins和其他许多CI服务器错误地认为构build失败。 要解决这个问题,你必须首先检查容器是否按照我在问题中所做的那样运行(请参阅containerRunningvariables)。

用于重buildDocker容器的完整脚本

根据这个新的知识,我以如下方式修正了我的脚本:

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

这完美的作品:)