在文件更改时重建 Docker 容器 [英] Rebuild Docker container on file changes

查看:28
本文介绍了在文件更改时重建 Docker 容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

For running an ASP.NET Core application, I generated a dockerfile which build the application and copys the source code in the container, which is fetched by Git using Jenkins. So in my workspace, I do the following in the dockerfile:

WORKDIR /app
COPY src src

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

While Jenkins updates the files on my host correctly with Git, Docker doesn't apply this to my image.

我的基本构建脚本:

#!/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 参数 docker run 以及停止/删除容器 before 新的构建.我不确定我在这里做错了什么.似乎 docker 正在正确更新图像,因为 COPY src src 的调用将导致层 id 并且没有缓存调用:

I tried different things like --rm and --no-cache parameter for docker run and also stopping/removing the container before the new one is build. I'm not sure what I'm doing wrong here. It seems that docker is updating the image correctly, as the call of COPY src src would result in a layer id and no cache call:

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

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

What is the recommended way to update a container?

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

My typical scenario would be: The application is running on the server in a Docker container. Now parts of the app are updated, e.g. by modifying a file. Now the container should run the new version. Docker seems to recommend building a new image instead of modifying a existing container, so I think the general way of rebuilding like I do is right, but some detail in the implementation has to be improved.

推荐答案

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

After some research and testing, I found that I had some misunderstandings about the lifetime of Docker containers. Simply restarting a container doesn't make Docker use a new image, when the image was rebuilt in the meantime. Instead, Docker is fetching the image only before creating the container. So the state after running a container is persistent.

因此,重建和重新启动是不够的.我认为容器像服务一样工作:停止服务,做你的改变,重新启动它,它们就会应用.那是我最大的错误.

Therefore, rebuilding and restarting isn't enough. I thought containers works like a service: Stopping the service, do your changes, restart it and they would apply. That was my biggest mistake.

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

Because containers are permanent, you have to remove them using docker rm <ContainerName> first. After a container is removed, you can't simply start it by docker start. This has to be done using docker run, which itself uses the latest image for creating a new container-instance.

有了这些知识,就可以理解为什么在容器中存储数据是被认定为不良实践,Docker 推荐 数据卷/mounting host directorys 相反:由于必须销毁容器才能更新应用程序,因此其中存储的数据也会丢失.这会导致关闭服务、备份数据等额外工作.

With this knowledge, it's comprehensible why storing data in containers is qualified as bad practice and Docker recommends data volumes/mounting host directorys instead: Since a container has to be destroyed to update applications, the stored data inside would be lost too. This cause extra work to shutdown services, backup data and so on.

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

So it's a smart solution to exclude those data completely from the container: We don't have to worry about our data, when its stored safely on the host and the container only holds the application itself.

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

The docker run command, has a Clean up switch called -rf. It will stop the behavior of keeping docker containers permanently. Using -rf, Docker will destroy the container after it has been exited. But this switch has two problems:

  1. Docker 还会删除没有与容器关联的名称的卷,这可能会杀死您的数据
  2. 使用此选项,无法使用 -d 开关在后台运行容器
  1. Docker also remove the volumes without a name associated with the container, which may kill your data
  2. Using this option, its not possible to run containers in the background using -d switch

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

While the -rf switch is a good option to save work during development for quick tests, it's less suitable in production. Especially because of the missing option to run a container in the background, which would mostly be required.

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

We can bypass those limitations by simply removing the container:

docker rm --force <ContainerName>

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

The --force (or -f) switch which use SIGKILL on running containers. Instead, you could also stop the container before:

docker stop <ContainerName>
docker rm <ContainerName>

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

Both are equal. docker stop is also using SIGTERM. But using --force switch will shorten your script, especially when using CI servers: docker stop throws an error if the container is not running. This would cause Jenkins and many other CI servers to consider the build wrongly as failed. To fix this, you have to check first if the container is running as I did in the question (see containerRunning variable).

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

According to this new knowledge, I fixed my script in the following way:

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

这很完美:)

这篇关于在文件更改时重建 Docker 容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆