【问题标题】:Kubernetes Engine - Pod deployment not updating to the latest imageKubernetes Engine - Pod 部署未更新到最新映像
【发布时间】:2019-11-11 06:45:16
【问题描述】:

我正在关注 Google Cloud Platform 的本教程:https://cloud.google.com/kubernetes-engine/docs/tutorials/hello-app。基本上,我从 Github 上克隆了示例 hello-app 项目在 Google Cloud(使用 Google Cloud Shell)和本地机器上,因为我想使用云方法和本地机器(使用 Google Cloud SDK)练习完成本教程- 然后我会将 Docker 映像推送到云端,然后在 Kubernetes 上构建并运行它。

1- 我的第一次,当我进入第 8 步时,我将源代码字符串从“Hello, World”更改为“Hello, world!版本 2”,以及 Go 文件中的字符串“版本:1.0.0”到“版本:2.0.0”,基本上是以下行:

fmt.Fprintf(w, "Hello, world! Version 2\n")
fmt.Fprintf(w, "Version: 2.0.0\n")

我意识到我更改了本地机器上的源代码(不是云端的那个)。然后我去了控制台中的 Google Cloud Shell,使用v2 标签重新构建了一个 Docker 映像,然后将其推送到 Google Container Registry(没有意识到我正在从存储在云,而不是我本地机器上的那个)。当我使用 kubectl 对现有部署应用滚动更新并使用映像更新时,毫不奇怪,它不起作用。 所以基本上要解决这个问题,我需要从本地机器上的(更改的)源代码项目构建一个映像,并将该映像推送到 Google Container Registry(使用 Google Cloud SDK shell)。这就是理论(我至少根据我的理解假设)。我创建了一个具有完全相同标签(即 v2)的映像,记住已经在 Container Registry 中存储了一个 v2 映像(具有未更改的代码),这是我上一步完成的。我想知道它是否会简单地覆盖 Container Registry 中的现有映像,它确实做到了(查看 Container Registry > Images 部分,我可以看到几秒钟前显示的带有更新的 v2 映像)。 现在一切都为最后一步做好了准备,即通过映像更新对现有部署应用滚动更新:

kubectl set image deployment/hello-web hello-web=gcr.io/${PROJECT_ID}/hello-app:v2

当我收到回复时,这很成功:

deployment.extensions/hello-web image updated

但是,当我导航到 Kubernetes Engine > Workloads 以查看在 Kubernetes 上部署的应用程序时,虽然状态显示 = OK,但在 Managed pods 部分它显示了从昨天和前一天运行的 Pod(在Created on 日期列),而不是今天(6 月 29 日)的部署:

1 (a) - 这让我想到了一个问题(仍然与第一个问题有关),上表中的 Revision 列,这是否意味着我从映像部署新 pod 的次数?因为确实我确实尝试了几次这一步,但徒劳地试图解决这个问题(我想可能是 4 次)。 回到主要问题,同样,如果我尝试使用负载均衡器服务的外部 IP 来加载站点,它不会显示更改的代码。此外,当我检查 Container Registry 中推送的最新映像时,通过导航到 Container Registry > Images,我可以看到几分钟前上传的映像的 v2。所以 Container Registry 确实有我上传的最新镜像(意味着它覆盖了 Container Registry 中相同镜像名称的先前版本 2。否则如果无法覆盖它应该会失败)。所以我不太明白,最后一步(下面)不应该是从 Container Registry 部署最后一个镜像 v2 吗?:

kubectl set image deployment/hello-web hello-web=gcr.io/${PROJECT_ID}/hello-app:v2

我不确定我错过了什么。

2- 由于我是 Docker 新手,我想知道有没有办法从 Container Registry 中提取镜像,并查看镜像中的源代码。否则,如何验证哪个 Image 包含哪个版本的源代码?这可能会导致很多混乱,许多版本的图像以及同样多版本的源代码历史更改。你怎么知道哪个源代码提交对应于哪个 Docker 镜像?

3- 最后,任何人都可以就不同场景下管理 Kubernetes 的最佳实践提出建议。假设您从更新的映像版本部署了容器,但在出现问题或缺少功能后才意识到,因此您希望回滚到以前的部署。那么是否有管理此类场景的最佳实践。

对于冗长的文字表示歉意,并在此先感谢您。

【问题讨论】:

    标签: docker kubernetes google-cloud-platform google-kubernetes-engine


    【解决方案1】:

    当您对部署进行更改时,Kubernetes 只有在您对部署文本进行一些更改时才会真正执行某些操作。在您的示例中,当您 kubectl set image ...:v2 时,由于部署已经是 v2,它会看到 Pod 的当前状态与它的预期匹配并且什么都不做。如果你 kubectl delete pod 这可能会导致它们被重新创建,但 Kubernetes 会再次看到它在节点上已经有一个 v2 映像并重新启动它。

    最简单最干净的方法是确定您已发布 v2(如果不是您期望的 v2),然后将更改后的映像构建/推送/部署为 v3。

    (还可以考虑基于源代码管理提交 ID 或日期戳的图像版本控制方案,这将更容易生成唯一且无状态的。)

    【讨论】:

    • 非常感谢大卫。工作就像一个魅力 :) 很高兴现在遇到这个问题,并了解 Kubernetes 如何处理映像版本。根据您的解释,我确实有几个问题。为了澄清起见,您提到 Deployment 看到 Pod 的当前状态与它的预期匹配并且什么都不做。那么,Deployment 到底是在 Pod 的 Container 中检查镜像名称和版本,还是在 Pod 的其他地方检查镜像?
    • 我的第二个问题,您提到即使在删除 pod 之后,Kubernetes(Kubernetes 和 Deployment 在这种情况下可以互换使用还是它们不同?)会看到它已经有一个 v2 映像节点。那么这是否意味着图像同时记录/定位在 Pod 的容器和底层节点资源上?我试图区分 Kubernetes 层次结构中的所有这些元素:部署、Pod、容器、节点。试图了解 Kubernetes 在检查和更新映像时会查看这些组件中的哪一个。
    • 第三,关于考虑基于源代码控制提交 ID 的映像版本控制方案,是否有一个指南可以告诉我如何在自动化方式(可能通过 CI 服务器配置、yml 文件或其他方式)?
    • 最后,有没有办法在 Docker Image 中查看应用程序的源代码。例如,版本混乱,您不再确定哪个 Docker Image 对应于哪个源代码版本。正如安德烈亚斯在下面所建议的那样,使用--entrypoint bash。我仍然不确定如何使用它来探索 Docker Image 中教程中的 main.go 文件的源代码......
    • 我试过docker run -it --entrypoint bash open -a vim main.go gcr.io/sunlit-mix-243915/hello-app:v2,但得到了错误:Unable to find image 'open:latest' locally docker: Error response from daemon: pull access denied for open, repository does not exist or may require 'docker login。我使用:gcloud auth configure-docker 进行身份验证并设法在 Google Cloud Shell VM 上成功提取 v2 映像。所以不知道如何打开源代码文件。
    【解决方案2】:

    1-) 您确定 :v2 尚未运行吗?

    1a) 修订版是部署的修订版。您所做的每一次更改都会增加修订。将图像从 :v1 更改为 :v2 应该会改变它。

    2) 您可以使用--entrypoint bash 启动任何特定图像并四处浏览。如果您的代码是可读的,您可以像在任何其他计算机上一样阅读它。如果它被编译,它会变得更难。

    另一方面,您应该相信您的构建过程/构建管道能够正确标记构建,并且只需检查标记就足以确定正确的版本正在运行。

    【讨论】:

    • 1-) 我查看了每个 Pod 详细视图,在 Container 部分(名为 hello-web 的容器)下,在图像列下它显示它正在使用图像 gcr.io/sunlit-mix-243915/hello-app:v2。除非图像本身没有更改的代码。检查这个的最好方法是什么?我应该从 Google Cloud 中的容器中提取图像吗?
    • 1a) 我推了 :v2 几次,因为我不断地从本地机器重新构建相同的 v2 映像,使用更改后的代码,将其推到 Google Container Registry,然后重新部署它到 Pod。所以我认为,这不仅仅是计算 v1 和 v2(即标签的变化),而是你将图像重新部署到 Pod 内的容器的次数。
    • 所以,当你推送几个 :v2 时,kubernetes 不会认为有任何改变。此外,除非有指示,否则它不会拉出更改的 :v2 。您可以将 imagePullPolicy 设置为 Always,它会在每个 pod 启动时拉取图像。 (kubernetes.io/docs/concepts/containers/images/#updating-images)。更改为 always 并杀死所有当前的 pod,新的 pod 将拥有您的最新代码。请注意,最好只给它一个新的 uniq 标签。
    • 2) 关于--entrypoint bash,我不确定要传递什么参数来打开,比如main.go 文件,其中包含我需要检查的源代码。我试过docker run -it --entrypoint bash open -a vim main.go gcr.io/sunlit-mix-243915/hello-app:v2,但我得到了错误:Unable to find image 'open:latest' locally docker: Error response from daemon: pull access denied for open, repository does not exist or may require 'docker login'.。我使用:gcloud auth configure-docker 进行身份验证并设法在 Google Cloud Shell VM 上成功提取了v2 映像。所以不知道如何打开源代码文件
    • 非常感谢安德烈亚斯的回答。我从你自己和大卫那里得到了两个答案(第一个答案)。非常感谢你们俩的帮助。如果 StackOverflow 允许,我会用绿色勾号(接受的答案)设置两个答案,但它不允许。我勾选了大卫的答案,纯粹是因为它是第一个并通过提到简单地创建映像的新版本来解决问题,因为 Kubernetes 不会对现有映像版本应用更新。尽管您确实在评论部分也提到了这一点。但我不能同时勾选两个答案。无论如何,我也赞成你的回答。太感谢了。 :)
    【解决方案3】:

    我认为这与 Kubernetes 的 pull 策略有关。您可以强制始终使用拉取策略或使用唯一的图像名称。https://kukulinski.com/10-most-common-reasons-kubernetes-deployments-fail-part-1/。

    【讨论】:

      猜你喜欢
      • 2021-09-21
      • 2017-06-03
      • 1970-01-01
      • 2021-06-13
      • 1970-01-01
      • 2018-12-01
      • 1970-01-01
      • 2020-08-01
      • 2020-07-02
      相关资源
      最近更新 更多