Skip to content

Latest commit

 

History

History
461 lines (325 loc) · 31.4 KB

File metadata and controls

461 lines (325 loc) · 31.4 KB

七、了解 Kubernetes 集群的核心组件

在本章中,我们将从 10,000 英尺的高度查看 Kubernetes 的主要组件,从每个控制器由什么组成,到每个工作人员如何部署和调度 pod 中的容器。了解 Kubernetes 集群的来龙去脉至关重要,以便能够部署和设计一个基于 Kubernetes 的解决方案,作为您的容器化应用的协调者:

  • 控制平面组件
  • Kubernetes 工人的部件
  • 作为基本构件的吊舱
  • Kubernetes 服务、负载平衡器和入口控制器
  • Kubernetes 部署和 DaemonSets
  • Kubernetes 中的持久存储

Kubernetes 控制飞机

Kubernetes 主节点是核心控制平面服务的所在地;并非所有服务都必须驻留在同一个节点上;但是,为了集中化和实用性,它们通常以这种方式部署。这显然提出了服务可用性的问题;然而,通过拥有几个节点并提供负载平衡请求来实现一组高度可用的主节点,可以轻松克服它们。

主节点由四个基本服务组成:

  • kube-apiserver
  • kube 调度程序
  • 库贝-控制器-管理器
  • etcd 数据库

主节点可以在裸机服务器、虚拟机或私有云或公共云上运行,但不建议在其上运行容器工作负载。我们稍后会看到更多。

下图显示了 Kubernetes 主节点组件:

kube-apiserver

API 服务器是将一切联系在一起的东西。它是集群的前端 REST API,接收清单以创建、更新和删除 API 对象,如服务、pods、Ingress 等。

kube-apiserver 是我们唯一应该交谈的服务;它也是唯一一个写入etcd数据库并与之对话以注册集群状态的数据库。有了kubectl命令,我们会发送命令与之交互。这将是我们的瑞士军刀,当涉及到 Kubernetes。

库贝-控制器-管理器

简而言之, kube-controller-manager 守护进程是一组无限的控制循环,为了简单起见,以单个二进制文件的形式提供。它监视集群的定义的期望状态,并通过移动实现它所必需的所有部分来确保它被完成和满足。kube-controller-manager 不仅仅是一个控制器;它包含几个不同的环路,监视集群中的不同组件。其中一些是服务控制器、名称空间控制器、服务帐户控制器以及许多其他控制器。您可以在 Kubernetes GitHub 存储库中找到每个控制器及其定义:

https://github . com/kubricks/kubricks/tree/master/pkg/controller

kube 调度程序

kube-scheduler 将新创建的 pods 调度到有足够空间满足 pods 资源需求的节点。它基本上监听 kube-apiserver 和 kube-controller-manager 新创建的 pods,这些 pods 被放入队列,然后由调度程序调度到可用的节点。kube-scheduler 的定义可以在这里找到:

https://github . com/kubricks/kubricks/blob/master/pkg/scheduler

除了计算资源之外,kube-scheduler 还读取节点的相似性和反相似性规则,以找出节点是否可以运行该 pod。

etcd 数据库

etcd 数据库是一个非常可靠的一致键值存储,用于存储 Kubernetes 集群的状态。它包含节点正在其中运行的 pods 的当前状态、集群当前有多少节点、这些节点的状态是什么、一个部署有多少副本正在运行、服务名称等等。

正如我们之前提到的,只有 kube-apiserver 与etcd数据库进行对话。如果 kube-controller-manager 需要检查集群的状态,它将通过 API 服务器从etcd数据库获取状态,而不是直接查询etcd商店。kube-scheduler 也是如此,如果调度程序需要让它知道一个 pod 已经被停止或者被分配给另一个节点;它将通知 API 服务器,API 服务器将当前状态存储在 etcd 数据库中。

使用 etcd,我们已经覆盖了 Kubernetes 主节点的所有主要组件,这样我们就可以管理集群了。但是集群不仅仅由主人组成;我们仍然需要通过运行应用来执行繁重工作的节点。

Kubernetes 工作节点

在 Kubernetes 中执行此任务的工作节点简称为节点。此前,在 2014 年左右,他们被称为爪牙,但这个术语后来被替换为仅仅是节点,因为这个名字与 Salt 的术语混淆,使人们认为 Salt 在 Kubernetes 中扮演了主要角色。

这些节点是您将运行工作负载的唯一位置,因为不建议在主节点上有容器或负载,因为它们需要可用于管理整个集群。

就组件而言,节点非常简单;他们只需要三种服务来完成任务:

  • 忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈
  • 立方体代理
  • 容器运行时

让我们更深入地探讨这三个组件。

容器运行时

为了能够旋转容器,我们需要一个容器运行时间。这是基础引擎,它将在节点内核中创建容器,供我们的 pods 运行。kubelet 将与这个运行时对话,并将根据需要加速或停止我们的容器。

目前,Kubernetes 支持任何符合 OCI 的容器运行时,如 Docker、rktruncrunsc等。

You can learn more about all the specifications from the OCI GitHub page: https://github.com/opencontainers/runtime-spec.

库布雷人

kubelet 是一个低级的 Kubernetes 组件,也是继 kube-apiserver 之后最重要的组件之一;这两个组件对于在集群中提供 pods/容器都是必不可少的。kubelet 是一个运行在 Kubernetes 节点上的服务,它监听 API 服务器来创建 pod。kubelet 只负责启动/停止,并确保吊舱中的容器是健康的;kubelet 将无法管理任何不是它创建的容器。

kubelet 通过名为容器运行时接口 ( CRI )的东西与容器运行时对话来实现目标。CRI 通过 gRPC 客户端向 kubelet 提供可插拔性,GRPc 客户端能够与不同的容器运行时对话。正如我们前面提到的,Kubernetes 支持多个容器运行时来部署容器,这就是它如何实现对不同引擎的如此多样的支持。

You can check the kubelet's source code via the following GitHub link: https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet.

库贝代理

kube-proxy 是驻留在集群的每个节点上的服务,它使吊舱、容器和节点之间的通信成为可能。该服务监视 kube-apiserver 上已定义服务的变化(在 Kubernetes 中,服务是一种逻辑负载平衡器;我们将在本章稍后深入探讨服务)并通过将流量转发到正确端点的iptables规则保持网络最新。Kube-proxy 还在iptables中设置了规则,在服务背后的吊舱之间进行随机负载平衡。

这里有一个由 kube 代理制定的iptables规则的例子:

-A KUBE-SERVICES -d 10.0.162.61/32 -p tcp -m comment --comment "default/example: has no endpoints" -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable

This is a service with no endpoints (no pods behind it).

现在,我们已经完成了组成集群的所有核心组件,我们可以谈论我们可以用它们做什么,以及 Kubernetes 将如何帮助我们编排和管理我们的容器化应用。

永恒的物体

Kubernetes 对象正是:它们是逻辑持久对象或抽象,将代表你的集群的状态。您负责告诉 Kubernetes 您想要的那个对象的状态是什么,以便它可以工作来维护它,并确保该对象存在。

要创建一个对象,它需要具备两个条件:状态和规格。状态由 Kubernetes 提供,它是对象的当前状态。Kubernetes 将根据需要管理和更新该状态,以符合您想要的状态。另一方面,spec字段是您提供给 Kubernetes 的内容,是您告诉它描述您想要的对象的内容,例如,您希望容器运行的图像,您希望运行的图像的容器数量,等等。每个对象都有特定的spec字段用于它们执行的任务类型,您将在一个 YAML 文件上提供这些规范,该文件通过kubectl发送到 kube-apiserver,后者将其转换为 JSON 并作为 API 请求发送。我们将在本章后面深入探讨每个对象及其规格字段。

这里有一个 YAML 被送到kubectl的例子:

cat << EOF | kubectl create -f -
kind: Service
apiVersion: v1
metadata:
 Name: frontend-service
spec:
 selector:
   web: frontend
 ports:
 - protocol: TCP
   port: 80
   targetPort: 9256
EOF

对象定义的基本字段是第一个,这些字段不会因对象而异,并且非常不言自明。让我们快速看一下它们:

  • kind:kind字段告诉 Kubernetes 您正在定义什么类型的对象:pod、服务、部署等等
  • apiVersion:因为 Kubernetes 支持多个 API 版本,所以我们需要指定一个 REST API 路径,我们希望将我们的定义发送到该路径
  • metadata:这是一个嵌套字段,这意味着您还有几个子字段指向元数据,您将在其中编写基本定义,如对象的名称,将其分配给特定的命名空间,并为其标记一个标签,以将您的对象与其他 Kubernetes 对象相关联

所以,我们现在已经浏览了最常用的字段及其内容;您可以在下面的 GitHub 页面了解更多关于 Kuberntes API 约定的信息:

https://github . com/kubernetes/community/blob/master/contributor/dev/API-convents . MD

创建对象后,可以修改对象的某些字段,但这取决于对象和要修改的字段。

以下是您可以创建的各种 Kubernetes 对象的简短列表:

  • 豆荚
  • 服务
  • 部署
  • 进入
  • 秘密
  • ConfigMap(配置地图)

还有很多。

让我们仔细看看这些项目。

豆荚——Kubernetes 的基础

豆荚是 Kubernetes 中最基本的物品,也是最重要的物品。一切都围绕着他们转;我们可以说 Kubernetes 是为豆荚准备的!所有其他物体都在这里为它们服务,它们所做的所有任务都是让豆荚达到你想要的状态。

那么,什么是豆荚,为什么豆荚如此重要?

pod 是一个逻辑对象,它在同一个网络命名空间、同一个进程间通信 ( IPC )以及有时,根据 Kubernetes 的版本,同一个进程 ID ( PID )命名空间上一起运行一个或多个容器。这是因为它们将运行我们的容器,因此将成为关注的中心。Kubernetes 的全部意义在于成为一个容器编排者,通过 pods,我们使编排成为可能。

正如我们之前提到的,同一个 pod 上的容器生活在一个“泡泡”中,它们可以通过 localhost 相互通信,因为它们彼此都是本地的。一个 pod 中的一个容器与另一个容器具有相同的 IP 地址,因为它们共享一个网络名称空间,但是在大多数情况下,您将在一对一的基础上运行,也就是说,每个 pod 只有一个容器。每个 pod 多个容器仅在非常特定的场景中使用,例如当应用需要一个助手(如数据推送器或代理)时,该助手需要以快速和灵活的方式与主应用通信。

定义 pod 的方式与定义任何其他 Kubernetes 对象的方式相同:通过包含所有 pod 规格和定义的 YAML;

kind: Pod
apiVersion: v1
metadata:
name: hello-pod
labels:
  hello: pod
spec:
  containers:
    - name: hello-container
      image: alpine
      args:
      - echo
      - "Hello World"

让我们浏览一下spec字段下创建 pod 所需的基本 pod 定义:

  • **集装箱:**集装箱是一个阵列;因此,我们在它下面有一组几个子字段。基本上,它定义了将在 pod 上运行的容器。我们可以为容器指定一个名称、将要派生的图像以及运行它所需的参数或命令。参数和命令之间的区别与我们在第 6 章创建高可用性自愈体系结构中谈到创建 Docker 映像时所经历的CMDENTRYPOINT之间的区别相同。请注意,我们刚刚经过的所有字段都是用于containers数组的。它们不是吊舱spec的直接部分。
  • restartPolicy: 这个字段就是这样的:它告诉 Kubernetes 如何处理一个容器,在零或非零退出代码的情况下,它适用于 pod 中的所有容器。您可以从“从不”、“失败”或“始终”选项中进行选择。在未定义 restartPolicy 的情况下,始终为默认值。

这些是你要在吊舱上声明的最基本的规格;其他规范将要求您对如何使用它们以及它们如何与各种其他 Kubernetes 对象交互有更多的背景知识。我们将在本章稍后部分重新讨论它们,其中一些如下:

  • 包封/包围(动词 envelop 的简写)
  • 港口
  • dnspoilcy
  • initContainers
  • 节点选择器
  • 资源限制和请求

要查看集群中当前正在运行的吊舱,您可以运行kubectl get pods:

dsala@MININT-IB3HUA8:~$ kubectl get pods
NAME      READY STATUS    RESTARTS AGE
busybox   1/1 Running   120 5d

或者,您可以在不指定任何 pod 的情况下运行kubectl describe pods。这将打印出集群中运行的每个 pod 的描述。在这种情况下,它将只是busybox吊舱,因为它是当前唯一运行的吊舱:

dsala@MININT-IB3HUA8:~$ kubectl describe pods
Name:               busybox
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               aks-agentpool-10515745-2/10.240.0.6
Start Time:         Wed, 19 Sep 2018 14:23:30 -0600
Labels:             <none>
Annotations:        <none>
Status:             Running
IP:                 10.244.1.7
Containers:
 busybox:
[...] (Output truncated for readability)
Events:
Type    Reason Age                 From      Message
----    ------ ----                ----      -------
Normal  Pulled 45s (x121 over 5d)  kubelet, aks-agentpool-10515745-2  Container image "busybox" already present on machine
Normal  Created 44s (x121 over 5d)  kubelet, aks-agentpool-10515745-2  Created container
Normal  Started 44s (x121 over 5d)  kubelet, aks-agentpool-10515745-2  Started container

Pods 是致命的,这是知道如何管理应用的线索。你必须明白,一旦一个豆荚死亡或被删除,就没有办法把它带回来。它的 IP 和在它上面运行的容器将会消失;它们完全是短暂的。作为卷装载的 pods 上的数据可能存在,也可能不存在,这取决于您如何设置它;然而,这是我们将在本章后面进行的讨论。如果我们的吊舱死亡,我们失去了它们,我们如何确保我们所有的微服务都在运行?部署就是答案。

部署

pod 本身并不是很有用,因为让我们的应用的多个实例在一个 pod 中运行效率并不高。在不同的单元上提供数百份我们的应用,而没有一种方法去寻找它们,将会很快失控。

这就是部署发挥作用的地方。通过部署,我们可以使用控制器管理我们的吊舱。这使得我们不仅可以决定我们想要运行多少,而且我们还可以通过更改我们的容器正在运行的映像版本或映像本身来管理更新。部署是您大部分时间要处理的事情。对于部署以及我们之前提到的 pods 和任何其他对象,它们在 YAML 文件中有自己的定义:

apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-deployment
 labels:
   deployment: nginx
spec:
 replicas: 3
 selector:
   matchLabels:
     app: nginx
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - name: nginx
       image: nginx:1.7.9
       ports:
       - containerPort: 80

让我们开始探索它们的定义。

在 YAML 之初,我们有更多的通用领域,如apiVersionkindmetadata。但是在spec下,我们将找到这个应用编程接口对象的具体选项。

spec下,我们可以添加以下字段:

  • 选择器:通过选择器字段,部署将知道在应用更改时目标是哪个吊舱。选择器下有两个字段供您使用:matchLabelsmatchExpressions。使用matchLabels,选择器将使用豆荚的标签(键/值对)。需要注意的是,您在此指定的所有标签都将是ANDed。这意味着吊舱将要求其具有您在matchLabels下指定的所有标签。matchExpressions很少使用,但是你可以在进一步阅读部分阅读我们推荐的书籍来了解更多。
  • 副本:这将通过复制控制器说明部署需要保持运行的吊舱数量;例如,如果您指定三个副本,并且其中一个 pod 死亡,复制控制器将观察副本规范作为所需的状态,并通知调度程序调度新的 pod,因为自从 pod 死亡以来,当前状态现在是 2。
  • 修订历史限制:每次您对部署进行更改时,此更改都会保存为部署的修订,您可以稍后恢复到以前的状态,或者记录更改的内容。您可以通过kubectl部署历史/部署名称>查询您的历史。使用revisionHistoryLimit,您可以设置一个数字,说明您想要保存多少条记录。
  • 策略:这将让你决定如何处理任何更新或水平吊舱规模。要覆盖默认值rollingUpdate,需要写type键,可以选择两个值:recreaterollingUpdate。虽然recreate是更新您的部署的快速方法,它将删除所有的吊舱,并用新的替换它们,但是它将意味着您将不得不考虑到对于这种类型的策略,系统停机将会发生。另一方面,rollingUpdate更流畅、更慢,非常适合能够重新平衡数据的有状态应用。rollingUpdate开启了另外两个领域的大门,分别是maxSurgemaxUnavailable。第一个是在执行更新时,你想要的总数量之上有多少个豆荚;例如,具有 100 个吊舱和 20% maxSurge的部署在更新时最多将增长到 120 个吊舱。下一个选项将让你选择你愿意杀死多少个豆荚,以便在 100 个豆荚的情况下用新豆荚替换它们。在有 20% maxUnavailable的情况下,只有 20 个吊舱将被杀死,并在继续替换部署的其余部分之前用新的吊舱替换。
  • 模板:这只是一个嵌套的 pod 规范字段,您将在其中包含部署将要管理的 pod 的所有规范和元数据。

我们已经看到,通过部署,我们管理我们的吊舱,它们帮助我们将吊舱保持在我们期望的状态。所有这些吊舱仍然在一个叫做集群网络的东西中,这是一个封闭的网络,在这个网络中,只有 Kubernetes 集群组件可以相互通信,甚至有自己的一组 IP 范围。我们如何从外面和我们的豆荚说话?我们如何到达我们的应用?这就是服务发挥作用的地方。

服务

名称服务没有完全描述在 Kubernetes 中服务实际上做什么。Kubernetes 服务将流量路由到我们的吊舱。我们可以说服务是将豆荚捆绑在一起的东西。

让我们假设我们有一个典型的前端/后端类型的应用,其中我们的前端模块通过模块的 IP 地址与后端模块进行对话。如果后端的一个吊舱死亡,我们知道吊舱是短暂的,因此我们失去了与后端的通信,所以现在我们处于一个受伤的世界。这不仅是因为新的 pod 将不会与死亡的 pod 具有相同的 IP 地址,而且现在我们还必须重新配置我们的应用以使用新的 IP 地址。这个问题和类似的问题可以通过服务来解决。

服务是一个逻辑对象,它告诉 kube-proxy 根据服务背后的 pods 创建 iptables 规则。服务配置它们的端点,这就是服务背后的单元的调用方式,就像部署知道要控制哪些单元、选择器字段和单元的标签一样。

此图显示了服务如何使用标签来管理流量:

服务不仅会让 kube-proxy 创建路由流量的规则;它还会触发一些叫做 kube-dns 的东西。

Kube-dns 是一组带有SkyDNS容器的 pods,它们运行在提供 dns 服务器和转发器的集群上,这将为服务创建记录,有时是 pods 以便于使用。每当您创建一个服务时,指向该服务的内部集群 IP 地址的 DNS 记录将以service-name.namespace.svc.cluster.local的形式创建。您可以在 Kubernetes GitHub 页面上了解更多关于 Kubernetes DNS 规范的信息:https://GitHub . com/Kubernetes/DNS/blob/master/docs/specification . MD。

回到我们的例子,我们现在只需要配置我们的应用来与服务完全限定域名 ( FQDN )对话,以便与我们的后端豆荚对话。这样,豆荚和服务的 IP 地址就不重要了。如果服务后面的一个 pod 死了,服务将通过使用 A 记录来处理一切,因为我们将能够告诉我们的前端将所有流量路由到 my-svc。服务的逻辑将处理其他一切。

每当在 Kubernetes 中声明要创建的对象时,都可以创建几种类型的服务。让我们仔细看看哪一种最适合我们需要的工作类型:

  • 集群 IP :这是默认服务。无论何时创建集群 IP 服务,它都会创建一个具有集群内部 IP 地址的服务,该地址只能在 Kubernetes 集群内部路由。这种类型非常适合只需要相互对话而不需要离开集群的吊舱。
  • 节点端口:当您创建这种类型的服务时,默认情况下会分配一个从3000032767的随机端口,用于将流量转发到服务的端点吊舱。您可以通过在ports数组中指定节点端口来覆盖此行为。一旦定义好了,你就可以通过<Nodes-IP> : <Node-Port>进入你的吊舱。这对于通过节点 IP 地址从集群外部访问您的豆荚非常有用。
  • 负载均衡器:大多数时候,你会在云提供商上运行 Kubernetes。负载平衡器类型非常适合这些情况,因为您可以通过云提供商的应用编程接口为您的服务分配公共 IP 地址。当您想要从集群外部与您的 pods 通信时,这是理想的服务。使用负载平衡器,您不仅可以分配公共 IP 地址,还可以使用 Azure 从虚拟专用网络中分配私有 IP 地址。因此,您可以通过互联网或在您的专用子网内部与您的 pods 进行对话。

让我们回顾一下 YAML 对服务的定义:

apiVersion: v1
kind: Service
metadata:  
 name: my-service
spec:
 selector:    
   app: front-end
 type: NodePort
 ports:  
 - name: http
   port: 80
   targetPort: 8080
   nodePort: 30024
   protocol: TCP

服务的 YAML 非常简单,规格会有所不同,这取决于您创建的服务类型。但是您必须考虑的最重要的事情是端口定义。让我们看看这些:

  • port:这是暴露的服务端口
  • targetPort:这是 pods 上服务向其发送流量的端口
  • nodePort:这是将要暴露的端口

虽然我们现在了解了如何与集群中的 pod 进行通信,但我们仍然需要了解如何管理每次 pod 终止时丢失数据的问题。这就是持续卷 ( PV )发挥作用的地方。

Kubernetes 和持久存储

集装箱世界中的持久存储是一个严重的问题。当我们研究 Docker 映像时,我们了解到跨容器运行的唯一持久存储是映像的层,并且它们是只读的。容器运行的层是读/写的,但是当容器停止时,该层中的所有数据都会被删除。有了豆荚,这是一样的。当容器死亡时,写入其中的数据就消失了。

Kubernetes 有一组对象来处理豆荚间的存储。我们首先要讨论的是卷。

解决了持久存储最大的问题之一。首先,体积实际上不是物体,而是吊舱规格的定义。创建容器时,可以在容器的规格字段下定义体积。此窗格中的容器将能够在其装载命名空间上装载该卷,并且该卷将在容器重新启动或崩溃时可用。不过,卷是绑定到容器的,如果容器被删除,卷也将消失。卷上的数据是另一回事;数据持久性将取决于该卷的后端。

Kubernetes 支持几种类型的卷或卷源,以及它们在 API 规范中的调用方式,范围从本地节点的文件系统映射、云提供商的虚拟磁盘和软件定义的存储备份卷。本地文件系统装载是常规卷中最常见的装载。需要注意的是,使用本地节点文件系统的缺点是数据不能在集群的所有节点上使用,只能在计划 pod 的那个节点上使用。

让我们来看看在 YAML 如何定义带有体积的吊舱:

apiVersion: v1
kind: Pod
metadata:
 name: test-pd
spec:
 containers:
 - image: k8s.gcr.io/test-webserver
   name: test-container
   volumeMounts:
   - mountPath: /test-pd
     name: test-volume
 volumes:
 - name: test-volume
   hostPath:
     path: /data
   type: Directory

注意spec下面怎么有个叫volumes的字段,然后又有个叫volumeMounts的。

第一个字段(volumes)是您定义要为该 pod 创建的卷的位置。此字段将始终需要名称,然后是卷源。根据来源的不同,要求也会有所不同。在这个例子中,源是hostPath,这是一个节点的本地文件系统。hostPath支持多种类型的映射,从目录、文件、块设备,甚至 Unix 套接字。

在第二个字段volumeMounts下,我们有mountPath,,它是您定义容器内要将卷装载到的路径的地方。name参数是您如何指定吊舱使用哪个体积。这很重要,因为您可以在volumes下定义几种类型的卷,并且名称将是 pod 知道哪些卷安装到哪个容器的唯一方法。

我们不会浏览所有不同类型的卷,因为除非您要使用特定的卷,否则了解它们是不相关的。重要的是要知道它们的存在,以及我们可以有什么样的来源。

您可以在 Kubernetes 网站(https://Kubernetes . io/docs/concepts/storage/volumes/# volumes-type-of-volumes)和 Kubernetes API 参考文档(https://Kubernetes . io/docs/reference/generated/Kubernetes-API/v 1.11/# volume-v1-core)中了解有关卷定义不同类型的更多信息。

让卷随豆荚一起死去并不理想。我们需要持久的存储,这就是对 PVs 的需求。

持久卷、持久卷声明和存储类

卷和 PVs 之间的主要区别在于,与卷不同,PVs 实际上是 Kubernetes API 对象,因此您可以像单独的实体一样单独管理它们,因此即使在 pod 被删除后,它们仍然存在。

你可能想知道为什么这个小节有 PV、持久卷声明 ( PVCs )和存储类都混在里面。这是因为我们不能只谈一个而不谈其他的;所有这些都是相互依赖的,理解它们之间的相互作用对于为我们的豆荚提供存储至关重要。

让我们从 PVs 和 PVCs 开始。像卷一样,卷也有一个存储源,所以卷的机制也适用于此。您将拥有一个提供逻辑单元号(LUN)的软件定义的存储集群,一个提供虚拟磁盘的云提供商,甚至一个到 Kubernetes 节点的本地文件系统,但是在这里,它们不是被称为卷源,而是被称为持久卷类型

PVs 非常像存储阵列中的 LUN:您创建它们,但没有映射;它们只是一堆等待使用的已分配存储。这里是聚氯乙烯发挥作用的地方。PVC 就像 LUN 映射:它们被备份或绑定到 PV,也是您实际定义、关联并提供给 pod 的内容,然后 pod 可以将其用于容器。

你在豆荚上使用 PVC 的方式和正常体积完全一样。您有两个字段:一个用于指定要使用的聚氯乙烯,另一个用于告诉容器在哪个容器上使用该聚氯乙烯。

聚氯乙烯应用编程接口对象定义的 YAML 应具有以下代码:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: gluster-pvc  
spec:
 accessModes:
 - ReadWriteMany      
 resources:
    requests:
      storage: 1Gi    

pod的 YAML 应具有以下代码:

kind: Pod
apiVersion: v1
metadata:
 name: mypod
spec:
 containers:
   - name: myfrontend
     image: nginx
     volumeMounts:
     - mountPath: "/mnt/gluster"
       name: volume
 volumes:
   - name: volume
     persistentVolumeClaim:
       claimName: gluster-pvc

当 Kubernetes 管理员创建 PVC 时,有两种方法可以满足该请求:

  • 静态:已经创建了几个 PV,然后当用户创建一个 PVC 的时候,任何可以满足需求的可用 PV 都会绑定到那个 PVC 上。
  • 动态:部分 PV 类型可以基于 PVC 定义创建 PVs。创建 PVC 时,PV 类型会动态创建一个 PV 对象,并在后端分配存储;这是动态供应。动态资源调配的问题在于,您需要第三种类型的 Kubernetes 存储对象,称为存储类

存储类就像是对存储进行分层的一种方式。您可以创建一个配置慢速存储卷的类,或者另一个配置超快速固态硬盘的类。但是,存储类比分层稍微复杂一点。正如我们在创建聚氯乙烯的两种方法中提到的,存储类使动态资源调配成为可能。在云环境中工作时,您不希望手动为每个 PV 创建每个后端磁盘。存储类将设置一个名为供应器的东西,它调用与云提供商的应用编程接口对话所必需的卷插件。每个资源调配者都有自己的设置,以便能够与指定的云提供商或存储提供商进行对话。

您可以通过以下方式调配存储类;这是一个使用 Azure 磁盘作为磁盘资源调配器的存储类示例:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
 name: my-storage-class
provisioner: kubernetes.io/azure-disk
parameters:
 storageaccounttype: Standard_LRS
 kind: Shared

每个存储类置备程序和 PV 类型都有不同的要求和参数以及卷,我们已经大致了解了它们的工作原理以及它们的用途。了解特定的存储类别和光伏类型将取决于您的环境;通过点击以下链接,您可以了解更多关于它们的信息:

摘要

在本章中,我们了解了什么是 Kubernetes,它的组件,以及使用编排的优势。

现在,您应该能够识别每个 Kubernetes API 对象、它们的用途以及它们的用例。您应该能够理解主节点如何控制集群以及工作节点中容器的调度。

问题

  1. 什么是 Kubernetes?
  2. Kubernetes 的成分是什么?
  3. Kubernetes 的 API 对象有哪些?
  4. 我们能用库本内斯做什么?
  5. 什么是容器编排器?
  6. 什么是豆荚?
  7. 什么是部署?

进一步阅读