当前位置: 首页 > 知识库问答 >
问题:

根据文件更改重建Docker容器

胡承悦
2023-03-14

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

WORKDIR /app
COPY src src

虽然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

我尝试了不同的方法,例如用于docker run的rm和no cache参数,以及在构建新容器之前停止/删除容器。我不确定我在这里做错了什么。docker似乎正在正确更新图像,因为调用COPY src src将导致层id而没有缓存调用:

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

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

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

共有3个答案

吴单鹗
2023-03-14

您可以通过运行docker compose-up-build来为特定服务运行构建

示例让我们假设docker compose文件包含许多服务(net app-database-Let’s encrypt…等),并且您只想更新。net应用程序,在docker中命名为应用程序。然后,您可以简单地运行docker compose-up--构建应用程序

额外参数如果您想在命令中添加额外参数(例如-d)以在后台运行,则该参数必须位于服务名称之前:docker-composup--build-d apps

蓬弘
2023-03-14

无论何时对dockerfile或compose或requirements进行更改,都可以使用docker compose-up-build重新运行它。以便重建和刷新图像

袁泓
2023-03-14

由于我之前的第一次视觉解释得到了很多积极的反馈,我决定为这个问题和答案创建另一个视频,因为有些东西可以在图形视频中更好地可视化。它可视化并更新了我过去几年在多个系统(以及K8s)上使用Docker获得的知识和经验。

而这个问题是在ASP的背景下提出的。NET内核,它实际上与此框架无关。问题是缺乏对Docker概念的基本理解,因此几乎在每个应用程序和框架中都会出现这种情况。出于这个原因,我在这里使用了一个简单的Nginx web服务器,因为我认为你们中的许多人都熟悉web服务器,但不是每个人都知道像ASP这样的特定框架是如何工作的。NET Core works。

潜在的问题是理解容器与图像的区别,以及它们在生命周期中的不同,这是本视频的基本主题。

经过一些研究和测试,我发现我对Docker容器的寿命有一些误解。简单地重新启动一个容器并不能使Docker使用一个新的图像,而图像是同时重建的。相反,Docker只是在创建容器之前获取图像。因此,运行容器后的状态是持久的。

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

因为容器是永久的,所以必须使用docker rm删除它们

有了这些知识,就可以理解为什么将数据存储在容器中是不好的做法,Docker建议改为使用数据卷/装载主机目录:因为必须销毁容器才能更新应用程序,所以容器中存储的数据也会丢失。这会导致关闭服务、备份数据等的额外工作。

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

docker run命令有一个名为rf的清理开关。它将停止永久保留docker容器的行为。使用rf,Docker将在容器退出后销毁容器。但是这个切换有一个问题:Docker还会删除没有与容器关联的名称的卷,这可能会杀死您的数据

虽然射频开关是一个很好的选择,可以在开发过程中节省快速测试的工作量,但它不太适合生产。尤其是因为缺少在后台运行容器的选项,这是最需要的。

我们只需移除容器即可绕过这些限制:

docker rm --force <ContainerName>

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

docker stop <ContainerName>
docker rm <ContainerName>

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

虽然普通的docker命令,如docker build、docker run等,对于初学者来说是理解基本概念的好方法,但当你已经熟悉docker并想提高效率时,这会让人恼火。更好的方法是使用Docker Compose。虽然它是为多容器环境设计的,但当将单机版与单个容器一起使用时,它也会为您带来好处。尽管多容器环境并不罕见。几乎每个应用程序都至少有一个应用服务器和一些数据库。有些甚至更像缓存服务器、cron容器或其他东西。

version: "2.4"
services:
  my-container:
    build: .
    ports:
      - "5000:5000"

现在您可以只使用docker-compose-build,compose-将负责我手动执行的所有步骤。我更喜欢这个脚本,而不是带有普通docker命令的脚本,我从2016年开始添加了它作为答案。它仍然可以工作,但更复杂,它可以处理某些情况,不如docker-compose-好。例如,如果一切都是up2date,则编写检查,并且只重建那些由于更改而需要重建的东西。

尤其是当您使用多个容器时,compose提供了更多的好处。例如,链接需要手动创建/维护网络的容器。您还可以指定依赖项,以便在应用程序服务器之前启动数据库容器,这取决于启动时的数据库。

过去用Docker撰写1。我注意到了一些问题,尤其是在缓存方面。这会导致容器不更新,即使某些内容已更改。我已经测试了compose v2一段时间了,没有再看到任何这些问题,所以现在似乎已经解决了。

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

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

这非常有效:)

 类似资料:
  • 问题内容: 为了运行ASP.NET Core应用程序,我生成了一个dockerfile,该文件构建了该应用程序,并将源代码复制到了容器中,该容器由Git使用Jenkins获取。因此,在我的工作区中,我在dockerfile中执行以下操作: 虽然Jenkins使用Git正确更新了主机上的文件,但Docker并未将其应用于我的映像。 我的基本构建脚本: 我尝试了各种不同的操作,例如和参数,并 在 构建

  • 是否可以更改卷本地路径? 使用Kitematic,我可以做到这一点。但我没有找到从cli执行此操作的方法。 例如,我运行docker使用: 我想重复使用容器,但如果可能,请更改体积。

  • 问题内容: 我正在通过创建带有一些nodejs指令的来玩docker。现在,每次更改dockerfile时,我都会通过在项目文件夹中运行来重新创建映像,但这每次都会创建一个新映像,并很快吞没我的ssd。 更改dockerfile时,是否有一种方法可以更新现有映像,或者每次更改文件时都被迫创建一个新映像? 抱歉,这是一个愚蠢的问题 问题答案: 只要没有指令,Docker构建支持缓存。如果您正在积极地

  • 例如:如果jar文件位于“D:\apps\jar.jar”中,则日志路径为“D:\log”;如果jar文件位于“C:\apps\jar.jar”中,则日志路径为“C:\log” 我尝试将log4j2.xml中的行(如下)更改为: 并在初始化记录器之前调用此函数:

  • 问题内容: 我正在编写一个node.js程序,该程序将监视包含大量(300 ish)数量的scss项目的目录。将配置Grunt- watch(可以通过节点模块运行,也可以单独运行,无论如何工作),以便每当更改scsss文件时,都将使用罗盘对其进行编译,并将输出文件移至单独的目录,例如: ./1234/style.scss已更改>> grunt-watch运行grunt-compass >> /fo

  • 我试图设置一个提交按钮,根据用户在另一张工作表上所做的选择来更改单元格的内容。 [类似getrange(匹配()). setvalue()的东西] 我似乎找不到用脚本识别正确范围的方法。附件是我的虚拟电子表格。 以下是我希望发生的事情:用户将在“列表”表上选择问题1和2的答案(单元格A2和B2以及单元格验证)。一旦用户单击“列表”工作表上的“提交”按钮,“主”工作表上的关联单元格内容将更改为FAL