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

查看:158
本文介绍了在文件更改时重建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.

我用于构建的基本脚本:

My basic script for building:

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

我尝试了不同的操作,例如docker run--rm--no-cache参数,还尝试在构建新容器之前停止/移除容器 .我不确定我在做什么错.似乎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 running 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 <ContainerName>删除它们.删除容器后,您不能简单地通过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.

基于此知识,可以理解为什么将数据存储在容器中是数据卷/mounting主机目录:由于必须销毁容器才能更新应用程序,因此内部存储的数据也将丢失.这会导致额外的工作来关闭服务,备份数据等.

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 Clean up 开关.它将停止永久保留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天全站免登陆