在文件更改时重建Docker容器

Lio*_*ion 56 git jenkins docker dockerfile asp.net-core

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

WORKDIR /app
COPY src src
Run Code Online (Sandbox Code Playgroud)

虽然Jenkins使用Git正确更新主机上的文件,但Docker不会将此应用于我的图像.

我建立的基本脚本:

#!/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
Run Code Online (Sandbox Code Playgroud)

我尝试不同的东西像--rm--no-cache参数docker run,并停止/删除容器之前,新的一个是建立.我不确定我在这里做错了什么.似乎docker正在更新图像,因为调用COPY src src会导致图层ID并且没有缓存调用:

Step 6 : COPY src src
 ---> 382ef210d8fd
Run Code Online (Sandbox Code Playgroud)

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

我的典型场景是:应用程序在Docker容器中的服务器上运行.现在部分应用程序已更新,例如通过修改文件.现在容器应该运行新版本.Docker似乎建议构建一个新的映像而不是修改现有的容器,所以我认为像我这样重建的一般方法是正确的,但实现中的一些细节必须得到改进.

Lio*_*ion 105

经过一些研究和测试,我发现我对Docker容器的生命周期有一些误解.在此期间重建图像时,简单地重新启动容器不会使Docker使用新图像.相反,Docker仅运行容器之前获取图像.所以运行容器后的状态是持久的.

为什么要删除

因此,重建和重新启动是不够的.我认为容器就像服务一样:停止服务,进行更改,重新启动它们并应用它们.那是我最大的错误.

因为容器是永久性的,所以必须先使用它们将其删除docker rm <ContainerName>.删除容器后,您不能简单地启动它docker start.这必须使用docker run,它本身使用最新的图像来创建一个新的容器实例.

容器应尽可能独立

有了这些知识,可以理解为什么在容器中存储数据被认为是不好的做法而Docker建议使用数据量/装载主机管理器:由于必须销毁容器以更新应用程序,因此内部存储的数据也将丢失.这会导致关闭服务,备份数据等的额外工作.

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

为什么-rf可能真的没有帮助你

docker run命令有一个名为Clean up的开关-rf.它将停止永久保留docker容器的行为.使用后-rf,Docker将在退出后销毁容器.但是这个开关有两个问题:

  1. Docker还会删除没有与容器关联的名称的卷,这可能会导致数据中断
  2. 使用此选项,无法使用-dswitch 在后台运行容器

虽然-rf开关是在开发过程中节省工作以进行快速测试的好选择,但它不太适合生产.特别是因为缺少在后台运行容器的选项,这通常是必需的.

如何删除容器

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

docker rm --force <ContainerName>
Run Code Online (Sandbox Code Playgroud)

在运行容器上使用SIGKILL 的--force(或-f)开关.相反,你也可以在之前停止容器:

docker stop <ContainerName>
docker rm <ContainerName>
Run Code Online (Sandbox Code Playgroud)

两者都是平等的.docker stop也在使用SIGTERM.但是使用--forceswitch会缩短脚本,尤其是在使用CI服务器时:docker stop如果容器未运行则会引发错误.这会导致Jenkins和许多其他CI服务器错误地将构建视为失败.要解决此问题,您必须首先检查容器是否正如我在问题中所做的那样运行(请参阅containerRunning变量).

用于重建Docker容器的完整脚本

根据这些新知识,我通过以下方式修复了我的脚本:

#!/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
Run Code Online (Sandbox Code Playgroud)

这很完美:)

  • “我发现我对Docker容器的生命存在一些误解”,您直言不讳。感谢您的详细解释。我会推荐给Docker新手。这阐明了VM与容器的区别。 (2认同)
  • 在您解释之后,我要做的就是记下我对现有图像所做的事情。为了保留更改,我创建了一个新的Dockerfile来创建一个新映像,该映像已经包含了要添加的更改。这样,创建的新图像就会(有所更新)。 (2认同)
  • @cglacet是的,它很相似,不能直接比较。但是“docker-compose”比普通的“docker”命令更智能。我经常使用“docker-compose”并且更改检测效果很好,所以我很少使用“--force-recreate”。当您构建自定义映像(撰写文件中的“build”指令)而不是使用来自 Docker hub 的映像时,“docker-compose up --build”非常重要。 (2认同)

yun*_*nus 19

每当在dockerfile或compose或需求中进行更改时,请使用重新运行它docker-compose up --build。这样就可以重建和刷新图像