git 在文件更改时重建 Docker 容器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41322541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rebuild Docker container on file changes
提问by Lion
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:
为了运行 ASP.NET Core 应用程序,我生成了一个 dockerfile 来构建应用程序并将源代码复制到容器中,这是由 Git 使用 Jenkins 获取的。因此,在我的工作区中,我在 dockerfile 中执行以下操作:
WORKDIR /app
COPY src src
While Jenkins updates the files on my host correctly with Git, Docker doesn't apply this to my image.
虽然 Jenkins 使用 Git 正确更新了我主机上的文件,但 Docker 不会将其应用于我的图像。
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
I tried different things like --rm
and --no-cache
parameter for docker run
and also stopping/removing the container beforethe 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:
我尝试了不同的东西,比如--rm
和--no-cache
参数docker run
以及在构建新容器之前停止/删除容器。我不确定我在这里做错了什么。似乎 docker 正在正确更新图像,因为调用COPY src src
会导致层 id 并且没有缓存调用:
Step 6 : COPY src src
---> 382ef210d8fd
What is the recommended way to update a container?
更新容器的推荐方法是什么?
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 似乎推荐构建一个新的镜像而不是修改一个现有的容器,所以我认为像我这样重建的一般方式是正确的,但在实现中的一些细节有待改进。
回答by Lion
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 beforecreating the container. So the state after running a container is persistent.
经过一番研究和测试,我发现我对Docker容器的生命周期存在一些误解。简单地重新启动一个容器不会让 Docker 使用一个新的镜像,当镜像在此期间被重建时。相反,Docker 仅在创建容器之前获取图像。所以运行一个容器后的状态是持久的。
Why removing is required
为什么需要删除
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.
因此,重建和重新启动是不够的。我认为容器像服务一样工作:停止服务,做你的改变,重新启动它,它们就会应用。那是我最大的错误。
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 rm <ContainerName>
。移除容器后,您不能简单地通过docker start
. 这必须使用 来完成docker run
,它本身使用最新的镜像来创建一个新的容器实例。
Containers should be as independent as possible
容器应该尽可能独立
With this knowledge, it's comprehensible why storing data in containers is qualified as bad practiceand Docker recommends data volumes/mounting host directorysinstead: 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.
有了这些知识,就可以理解为什么将数据存储在容器中被认为是不好的做法,而 Docker 建议改为使用数据卷/挂载主机目录:由于必须销毁容器才能更新应用程序,因此内部存储的数据也会丢失。这会导致关闭服务、备份数据等额外工作。
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.
因此,将这些数据完全从容器中排除是一个明智的解决方案:我们不必担心我们的数据,因为它安全地存储在主机上并且容器只保存应用程序本身。
Why -rf
may not really help you
为什么-rf
可能不会真正帮助你
The docker run
command, has a Clean upswitch 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:
该docker run
命令有一个名为的清理开关-rf
。它将停止永久保留 docker 容器的行为。使用-rf
,Docker 将在容器退出后销毁容器。但是这个开关有两个问题:
- Docker also remove the volumes without a name associated with the container, which may kill your data
- Using this option, its not possible to run containers in the background using
-d
switch
- Docker 还会删除没有与容器关联的名称的卷,这可能会杀死您的数据
- 使用此选项,无法使用
-d
switch在后台运行容器
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.
虽然-rf
switch 是一个很好的选择,可以在开发过程中节省工作以进行快速测试,但它不太适合生产。特别是因为缺少在后台运行容器的选项,这通常是必需的。
How to remove a container
如何移除容器
We can bypass those limitations by simply removing the container:
我们可以通过简单地移除容器来绕过这些限制:
docker rm --force <ContainerName>
The --force
(or -f
) switch which use SIGKILL on running containers. Instead, you could also stop the container before:
在运行容器上使用 SIGKILL的--force
(or -f
) 开关。相反,您也可以在之前停止容器:
docker stop <ContainerName>
docker rm <ContainerName>
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).
两者是平等的。docker stop
也在使用SIGTERM。但是使用--force
switch 会缩短你的脚本,尤其是在使用 CI 服务器时:docker stop
如果容器没有运行,则会引发错误。这会导致 Jenkins 和许多其他 CI 服务器错误地认为构建失败。要解决此问题,您必须首先检查容器是否像我在问题中所做的那样运行(请参阅containerRunning
变量)。
Full script for rebuilding a Docker container
用于重建 Docker 容器的完整脚本
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
This works perfectly :)
这完美地工作:)
回答by yunus
Whenever changes are made in dockerfile or compose or requirements , re-Run it using docker-compose up --build
. So that images get rebuild and refreshed
每当在 dockerfile 或 compose 或 requirements 中进行更改时,请使用docker-compose up --build
. 以便图像得到重建和刷新