学习 Kubernetes,第二部分,Pod、节点和服务

2025-06-08

学习 Kubernetes,第二部分,Pod、节点和服务

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

第二部分旨在为节点 (Nodes) 和 Pod 提供更多背景信息,并介绍服务 (Service) 的概念。其中包含一些 Kubectl 的理论和实践。

欢迎回到第二部分。到目前为止,诸如kubectlnodes和 之类的概念pods对您来说应该并不陌生,但我们会稍微介绍一下它们的含义,当然,我们也会继续使用我们的工具 来学习 Kubernetes kubectl。我们还将介绍“服务”这个新概念,以及为什么它们是比代理更好的应用公开方式。

这是有关 Kubernetes 的系列文章的一部分:

在本部分中,我们将介绍以下内容:

  • 加深对 Pod 和 Node 的了解
  • 介绍服务和标签
  • 进行一项练习,包括在 Pod 上设置标签并使用标签来查询我们的工件

 资源

重新审视概念

当我们在 Kubernetes 上创建 Deployment 时,该 Deployment 会创建包含容器的 Pod。因此,Pod 与 Node 绑定,并会持续存在,直到被终止删除。让我们进一步了解 Pod 和 Node,并引入一个新主题:服务

 豆荚

Pod 是 Kubernetes 平台上的原子单元,即最小的可部署单元

我们之前已经说过上述内容,但值得再次提及。

还有什么需要了解的?

Pod 是一个抽象概念,它表示一组由一个或多个容器(例如 Docker 或 rkt)以及这些容器的一些共享资源组成的组。这些资源包括:

  • 共享存储,作为卷
  • 网络,作为唯一的集群 IP 地址
  • 有关如何运行每个容器的信息,例如容器镜像版本或要使用的特定端口

一个 Pod 可以包含多个容器。如果 Pod 包含多个容器,则其他容器可以支持主应用程序。辅助应用程序的典型示例包括数据拉取器、数据推送器和代理。您可以在此处
阅读更多关于该用例的信息。

  1. Pod 中的容器共享一个 IP 地址和端口空间,并且:
  2. 始终位于同一地点
  3. 共同安排

让我给你展示一张图片,以便更容易地理解:

正如我们上面看到的,Pod 中可以包含许多不同的工件,它们能够以某种方式进行通信并支持应用程序。

节点

Pod 始终在 Node 上运行

那么 Node 是 Pods 的父级吗?

是的。

节点是一台工作机器,可以是虚拟机,也可以是物理机,具体取决于集群

每个 Node 都由 Master 进行管理。一个 Node 可以包含多个 Pod。

所以这是一对多的关系

Kubernetes 主服务器自动处理集群中各个节点的 Pod 调度

每个 Kubernetes 节点至少运行:

  • Kubelet负责 pod 规范并与 cri 接口对话
  • Kube-Proxy,是节点间通信的主要接口

  • 容器运行时(如 Docker、rkt)负责从注册表中提取容器镜像、解压容器并运行应用程序。

好的,所以一个节点包含一个 Kubelet、一个容器运行时以及一对多的 Pod。我想我明白了。

让我们展示一张图片来让这个信息更加清晰,因为了解发生了什么非常重要,至少在高层次上是这样:

 服务

Pod 是终生的,它们会死亡。事实上,Pod 有一个生命周期

当工作节点死亡时,该节点上运行的 Pod 也会丢失。

我们的应用程序会怎么样?:(

你可能会认为它们和它们的数据都丢失了,但事实并非如此。Kubernetes 的重点就是防止这种情况发生。我们通常会部署类似ReplicaSet.

ReplicaSet,你是​​什么意思?

AReplicaSet是一种高级工件,它可以通过创建新的 Pod将集群驱动回所需状态以保持应用程序运行。

好的,那么如果 Pod 出现故障,ReplicaSet 是否会在其位置上创建一个新的 Pod?

是的,就是这样。如果你专注于定义理想状态,剩下的就交给 Kubernetes 了。

呼,听起来真的很棒。

期望状态的概念非常重要。你需要始终指定每种容器所需的数量。

哦,那么 4 个数据库容器、3 个服务等等?

是的,确实如此。

所以你无需关心细节,只需告诉 Kubernetes 你想要的状态,它就会处理剩下的事情。如果出现问题,Kubernetes 会确保它恢复到期望状态

Kubernetes 集群中的每个 Pod 都有一个唯一的 IP 地址,即使同一节点上的 Pod 也是如此,因此需要有一种方法来自动协调 Pod 之间的更改,以便您的应用程序继续运行。

好的?

是的,可以这样想。如果一个包含你的应用的 Pod 宕机了,另一个 Pod 会代替它运行你的应用。之后用户应该仍然可以使用你的应用。

好的,我明白了。这让我想到……

服务的动机

你永远不应该用 IP 地址来引用 Pod,想象一下,当一个 Pod 宕机后又恢复,但这次 IP 地址不同时会发生什么。正因如此,Service 才存在。

Kubernetes 中的服务是一种抽象,它定义了一组逻辑 Pod 以及访问它们的策略。

让我想到了路由器和子网

是的,我想你可以说它们在某些地方有相似之处。

服务使得依赖的 Pod 之间能够实现松散耦合,并使用 YAML 或 JSON 文件进行定义,就像所有 Kubernetes 对象一样。

这很方便,只需 JSON 和 YAML :)

服务和标签

服务所针对的 Pod 集通常由 决定LabelSelector

虽然每个 Pod 都有唯一的 IP 地址,但如果没有 Service,这些 IP 不会暴露到集群外部。不过,我们可以通过代理来暴露它们,就像我们在第一部分中展示的那样。

等等,你说“回头再说” LabelSelector。我没太听懂吧?

还记得我们不能通过 IP 来引用 Pod 吗,因为 Pod 可能会宕机,而新的 Pod 可能会回到原来的位置?

是的

嗯,标签就是服务和 Pod 如何通信的答案。这就是我们所说的松耦合。通过为 Pod 添加诸如frontendbackendrelease等标签,我们能够通过 Pod 的逻辑名称来引用它们,而不是通过它们的具体 IP 地址。

哦,我明白了,所以它是一种高级领域语言

嗯,有点。

服务和交通

服务允许您的应用程序接收流量。

type通过在 中指定服务规范,可以以不同的方式公开服务ServiceSpec

  • ClusterIP(默认) - 将服务暴露在集群内部的 IP 上。此类型使服务只能从集群内部访问。
  • NodePort - 使用 NAT 将服务暴露到集群中每个选定节点的相同端口。使用以下方式可从集群外部访问服务:ClusterIP 的超集。
  • LoadBalancer - 在当前云中创建外部负载均衡器(如果支持),并为服务分配一个固定的外部 IP。NodePort 的超集。
  • ExternalNameexternalName - 使用任意名称(在规范中指定)通过返回包含该名称的 CNAME 记录来公开服务。不使用代理。此类型需要 kube-dns v1.7 或更高版本。

好的,我想我明白了。确保我对外访问的是 Service,而不是特定的 Pod。根据我暴露的 Service 类型,这会导致不同的行为吗?

是的,正确。

不过,您说了一些有关标签的事情,我们如何创建它们并将其应用到 Pod 中?

是的,我们接下来讨论这个。

标签

正如我们刚才提到的,服务是一种抽象,它允许 Pod 在 Kubernetes 中消亡和复制,而不会影响您的应用程序。

现在,Services使用标签选择器匹配一组 Pod ,它允许我们像组一样对 Pod 进行操作。

标签是附加到对象的键/值对,可以以多种方式使用:

  • 指定开发、测试和生产的对象
  • 嵌入版本标签
  • 使用标签对对象进行分类

标签可以在创建时或之后附加到对象上。它们可以随时修改。

实验室 - 标签和 kubectl 的乐趣

建议您先阅读本系列的第一部分,其中介绍了如何创建部署。如果没有,则需要先创建一个部署,如下所示:

kubectl run kubernetes-first-app --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --port=8080
Enter fullscreen mode Exit fullscreen mode

现在我们可以出发了。

好的。我知道你们现在可能已经厌倦了所有的理论。

我敢打赌,您一定迫不及待地想通过 Kubernetes 来学习更多实践知识kubectl

好吧,现在是时候了:)。我们将做两件事:

  1. 创建一个服务并了解如何使用该服务公开我们的应用程序
  2. 了解标签以及如何通过在我们的工件上贴上适当的标签来改进我们的查询游戏。

让我们创建一个新的服务。

我们将熟悉该expose命令。

让我们检查一下现有的 Pod,

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

接下来我们看看我们有哪些服务:

kubectl get services
Enter fullscreen mode Exit fullscreen mode

接下来让我们创建一个像这样的服务:

kubectl expose deployment/kubernetes-first-app --type="NodePort" --port 8080
Enter fullscreen mode Exit fullscreen mode

正如您在上面看到的,我们只是针对我们的一个部署,并使用和类型kubernetes-first-app来引用它[type]/[deployment name]deployment

我们将其公开为类型的服务NodePort,最后我们选择在端口上公开它8080

现在kubectl get services再次运行并查看结果:

如您所见,我们现在有两个服务正在使用,即基本kubernetes服务和新创建的服务kubernetes-first-app

接下来我们需要获取服务的端口并将其分配给变量:

export NODE_PORT=$(kubectl get services/kubernetes-first-app -o go-template='{{(index .spec.ports 0).nodePort}}')
echo NODE_PORT=$NODE_PORT
Enter fullscreen mode Exit fullscreen mode

现在,我们已经将端口存储在环境变量中NODE_PORT,并且准备开始与我们的服务进行通信,如下所示:

curl $(minikube ip):$NODE_PORT
Enter fullscreen mode Exit fullscreen mode

输出结果如下:

创建和应用标签

当我们创建部署和 Pod 时,它会自动分配一个标签。

通过输入

kubectl describe deployment
Enter fullscreen mode Exit fullscreen mode

我们可以看到该标签的名称。

接下来我们可以通过相同的标签查询 Pod

kubectl get pods -l run=kubernetes-first-app
Enter fullscreen mode Exit fullscreen mode

上面我们使用-l来查询特定标签,并将其kubernetes-bootcamp作为标签名称。结果如下:

您可以对您的服务进行类似的查询:

kubectl get services -l run=kubernetes-first-app
Enter fullscreen mode Exit fullscreen mode

这只是表明您可以在不同级别查询具有该标签的 Pod 的特定 Pod 或服务。

接下来我们将看看如何更改标签

首先让我们获取 pod 的名称,如下所示:

POD_NAME=kubernetes-first-app-669789f4f8-6glpx
Enter fullscreen mode Exit fullscreen mode

上面我只是将我的 Pod 名称赋给了一个变量POD_NAME。你可以用 a 来检查一下kubectl getpods你的 Pod 名称。

然后我们可以像这样添加/应用新标签:

kubectl label pod $POD_NAME app=v1
Enter fullscreen mode Exit fullscreen mode

验证新标签是否已设置,如下所示:

kubectl describe pod
Enter fullscreen mode Exit fullscreen mode

或者

kubectl describe pods $POD_NAME
Enter fullscreen mode Exit fullscreen mode

从结果中您可以看到,我们的新标签app=v1已附加到现有标签中。

现在我们可以像这样查询:

kubectl get pods -l app=v1
Enter fullscreen mode Exit fullscreen mode

这就是标签的工作原理,如何获取可用的标签、应用它们并在查询中使用它们。请确保为它们指定一个描述性的名称,例如应用程序版本、特定环境,或者像前端后端这样的名称,这些名称应该符合您的具体情况。

清理

好的,我们创建了一个服务。我们应该学习如何清理它。运行以下命令来删除我们的服务:

kubectl delete service -l run=kubernetes-bootcamp
Enter fullscreen mode Exit fullscreen mode

使用以下命令验证该服务是否不再存在:

kubectl get services
Enter fullscreen mode Exit fullscreen mode

另外,确保我们暴露的 IP 和端口不再能够被访问:

curl $(minikube ip):$NODE_PORT
Enter fullscreen mode Exit fullscreen mode

服务下架并不意味着应用也下架了。应用应该仍然可以在以下平台访问:

kubectl exec -ti $POD_NAME curl localhost:8080
Enter fullscreen mode Exit fullscreen mode

概括

那么我们学到了什么呢?我们对 Pod 和 Node 有了更多的了解。此外,我们还了解到不应该直接与 Pod 对话,而应该使用诸如服务之类的高级抽象。服务使用标签来定义领域语言,并将其应用于不同的 Pod。

好的,我们对 Kubernetes 以及不同概念之间的关系有了更多的了解。我们多次提到了“期望状态” ,但并没有详细介绍如何设置这种状态。本系列的下一篇将介绍如何设置期望状态以及 Kubernetes 如何维护它,敬请期待。

单击此处转到“缩放”的下一部分。

继续阅读:https://dev.to/azure/kubernetes-part-ii-revisiting-pods-and-nodes-and-introducing-services-and-labeling-5fi7
PREV
为被宠坏的人打造的 Microsoft Azure
NEXT
如何使用 Docker 管理云中的部署