Kubernetes Pod深度解析:构建可靠微服务的秘密武器(上)
本文旨在全面而深入地探讨Kubernetes(K8s)中的Pod概念,为读者提供对其核心特性和应用场景的深入理解。Pod作为Kubernetes的最小部署单元,承载着容器化应用的核心功能,是构建云原生应用的重要基石。
🐇明明跟你说过:个人主页
🏅个人专栏:《Kubernetes航线图:从船长到K8s掌舵者》 🏅
🔖行路有良友,便是天堂🔖
目录
一、引言
1、Kubernetes概述
Kubernetes,简称K8s,是一个开源的容器编排平台,用于自动化地部署、扩展和管理容器化应用程序。该平台最初由Google公司设计和开发,并于2014年正式发布。Kubernetes在希腊语中是舵手或飞行员的意思,象征着其在容器编排领域的主导地位。如今,它已成为容器编排领域的事实标准,被广泛应用于各种场景中,包括Web应用程序、大数据处理、人工智能等。
2、Pod概述
Pod是Kubernetes集群中最小的部署和管理的基本单元,它是协同寻址和协同调度的关键组件。Pod可以看作是一个或多个容器的集合,代表集群中运行的一个或多个服务(进程)的抽象集合。这些容器在Pod内共享网络和存储资源,形成一个逻辑上的虚拟机,但并非真正的虚拟机。
在Pod中,多个容器可以共享同一网络命名空间,因此它们共享Pod的IP和端口命名空间。这使得Pod内的容器可以通过localhost进行内部通信,只要注意避免端口冲突即可。同时,Pod内的多个容器也可以共享存储卷,这个存储卷会被定义为Pod的一部分,并且可以挂载到该Pod里的所有容器的文件系统上。
二、Pod的基本概念
1、Pod的定义与特性
Pod的定义:
- Pod 是 Kubernetes 中最小的可部署和可管理的计算单元。它是一个或多个容器的集合,共享网络和存储资源,并且在相同的宿主机上运行。
- Pod 中包含一个或多个容器,这些容器共享相同的网络命名空间、IP 地址和存储卷。
- Pod 的生命周期包括创建、运行、终止等阶段。Pod 可以由 Kubernetes API 创建、删除或修改,并且 Kubernetes 控制器负责管理 Pod 的生命周期。
Pod的特性:
- 容器共享网络命名空间:Pod 中的容器共享相同的网络命名空间,它们可以直接通过 localhost 进行通信,无需进行端口映射。
- 容器共享存储卷:Pod 中的容器可以共享相同的存储卷,这使得它们可以在容器之间共享数据。
- 资源共享和限制:Pod 可以为其包含的容器分配资源,如 CPU、内存等,并可以定义资源限制,以确保容器不会超出其分配的资源。
- 调度约束:Pod 可以定义调度约束,如节点亲和性、节点反亲和性、Pod 亲和性等,以影响 Pod 被调度到哪些节点上运行。
2、Pod与容器的关系
Pod与容器在Kubernetes中扮演着不同的角色,但它们之间又存在着紧密的联系。简而言之,容器是应用程序的运行时环境,而Pod则是这些容器的逻辑分组和管理单位。
容器是一种轻量级的、可移植的、自包含的软件打包技术,它使得开发者可以将应用程序及其依赖项打包到一个可执行的包中。在Kubernetes中,容器是实际运行应用程序的组件,它们提供了应用程序所需的隔离性和可移植性。每个容器都运行在自己的命名空间中,拥有独立的文件系统、进程和网络资源。
而Pod则是Kubernetes中用于管理容器的最小单元。一个Pod可以包含一个或多个容器,这些容器共享相同的网络命名空间、存储卷和其他资源。Pod提供了一个逻辑主机的抽象,使得容器可以作为一个整体进行部署和管理。Pod内的容器可以通过localhost进行通信,并且共享相同的IP地址和网络端口。此外,Pod还可以定义存储卷,这些存储卷可以被挂载到Pod内的所有容器上,实现数据共享。
Pod与容器之间的关系可以类比为“篮子”与“鸡蛋”的关系。Pod就像是篮子,而容器则是篮子里的鸡蛋。Pod为容器提供了一个统一的运行环境和管理界面,使得开发者可以更加方便地管理和调度容器。通过Pod,开发者可以定义容器的依赖关系、资源限制、存储配置等,以满足应用程序的需求。
三、Pod的生命周期
1、Pod的创建与调度
Pod的创建:
- 用户提交创建请求:用户通过kubectl命令行工具或其他Kubernetes API客户端提交Pod的创建请求。这通常涉及编写一个描述Pod及其容器配置、资源需求和其他相关设置的YAML文件。
- API Server的认证与接收:API server接收到Pod创建请求后,首先进行身份认证和授权检查,确保请求来自合法的用户且具备相应的权限。
- 写入etcd存储:一旦认证和授权通过,API server将Pod对象的初始状态写入etcd。etcd是一个分布式的键值存储系统,用于持久化保存Kubernetes集群的状态信息。
Pod的调度:
- 调度器选择合适的Node:Kubernetes Scheduler是一个核心组件,负责将Pod分配到集群中的合适节点上。调度器根据一系列的策略和规则来选择Node,这些策略可以包括资源需求、高可用性、亲和性等。调度器会过滤掉不符合要求的Node,然后从中选择一个最优的Node。
- 节点接受调度请求:被选中的Node会接受调度请求,并准备在其上创建Pod。
- 节点上创建Pod的容器并启动:一旦Node接受调度请求,它会在其上创建Pod的容器并启动它们。这涉及拉取容器镜像、设置容器环境变量、挂载存储卷等操作。
2、Pod的状态与生命周期阶段
Pod的状态:
Pod 在其生命周期中可能处于以下几种状态之一:
- Pending(挂起):Pod 已经被创建,但还没有被调度到集群中的节点上运行。
- Running(运行中):Pod 已经被调度到节点上,并且其中的容器正在运行。
- Succeeded(成功):Pod 中的所有容器已经成功运行完毕,并且成功退出。
- Failed(失败):Pod 中的某个容器已经运行失败。
- Unknown(未知):Kubernetes 无法获取 Pod 的状态信息。
Pod的生命周期:
Pod 在其生命周期中经历了以下几个主要阶段:
- 创建阶段:Pod 的配置清单已经被提交到 Kubernetes 集群,但尚未被调度到节点上运行。
- 调度阶段:Pod 被调度到集群中的节点上,并且等待 kubelet 进程创建和运行 Pod 中的容器。
- 运行阶段:Pod 中的容器正在运行,处于 Running 状态。
- 终止阶段:Pod 中的容器已经运行完毕或失败,Pod 进入了 Succeeded 或 Failed 状态。
四、Pod的配置与管理
1、Pod的配置文件(YAML)详解
Pod的配置文件在Kubernetes中通常采用YAML(YAML Ain't Markup Language)格式进行编写。YAML是一种易于人类阅读的数据序列化标准,广泛用于配置文件和数据描述。在Kubernetes中,Pod的配置文件用于定义Pod的属性、行为以及其中包含的容器。
下面创建一个Pod对象
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
restartPolicy: Always
该配置文件描述了一个名为 nginx-pod 的 Pod,其中包含一个名为 nginx-container 的容器,使用了 nginx:latest 镜像,并监听了容器的 80 端口。Pod 的重启策略为 Always,即容器在退出后会自动重新启动。
- apiVersion:指定 Kubernetes API 的版本,用于告诉 Kubernetes 如何解析该配置文件。在此示例中,使用的是 v1 版本的 API。
- kind:指定要创建的对象类型,这里是 Pod。
- metadata:指定 Pod 的元数据,包括名称(name)和标签(labels)等信息。
- name:指定 Pod 的名称,这里命名为 nginx-pod。
- labels:为 Pod 添加标签,方便对 Pod 进行分类和查询。
- spec:指定 Pod 的规格,包括容器配置、存储卷挂载等信息。
- containers:指定 Pod 中的容器列表,这里只包含一个容器。
- name:指定容器的名称,这里命名为 nginx-container。
- image:指定容器所使用的镜像,这里使用的是 nginx:latest。
- ports:指定容器需要监听的端口,这里容器监听的端口是 80。
- restartPolicy:指定容器的重启策略,这里设置为 Always,表示容器在退出后总是重新启动。
※注意,YAML文件注重格式缩进,如果缩进有问题,在apply时会报错
接下来我们在k8s集群使用上面的YAML文件创建一个Pod
如果还未安装k8s集群,请参考《深度解析:Kubernetes 1.28.2集群安装过程中的关键步骤》这篇文章
[root@master1 ~]# kubectl apply -f nginx.yaml
2、Pod的资源限制
在 Kubernetes 中,可以通过 Pod 的资源限制和配额管理来控制和管理集群中的资源使用情况。
资源限制主要是为Pod中的容器设定所需要的资源数量,最常见的可设定资源是CPU和内存大小。当为Pod中的容器指定了request资源时,它代表容器运行所需的最小资源量。调度器就使用该信息来决定将Pod调度到哪个节点上。而为容器指定limit资源,则是为了确保运行的容器不会使用超出所设的limit资源量。kubelet会确保容器不会超出所设置的limit资源量,并会预留所设的request资源量供该容器使用。如果Pod运行所在的节点具有足够的可用资源,容器可以使用超出所设置的request资源量,但不可以使用超出所设置的limit资源量。
现在,我们重新编辑刚刚的YAML文件,添加资源限制字段
resources:
requests:
cpu: "0.5" # 请求 0.5 个 CPU 核
memory: "256Mi" # 请求 256 MiB 内存
limits:
cpu: "1" # 限制最大使用 1 个 CPU 核
memory: "512Mi" # 限制最大使用 512 MiB 内存
3、Pod的配额管理
Pod的配额管理是Kubernetes资源管理的一个重要环节,主要用于确保集群资源的合理使用和避免资源过度消耗。Pod配额管理主要依赖于Kubernetes的资源配额机制,通过ResourceQuota对象来定义和管理配额规则。
ResourceQuota对象可以定义多种资源的配额限制,包括CPU、内存、存储卷的数量以及存储卷的容量等。管理员可以为整个命名空间或特定的命名空间设置ResourceQuota,以限制在该命名空间内可以创建的资源对象的数量和类型。
当用户在设置了ResourceQuota的命名空间中创建Pod时,Kubernetes会检查该Pod的资源请求和限制是否超过了配额限制。如果超过了限制,那么Pod的创建请求将被拒绝。这样,ResourceQuota确保了用户在特定命名空间中的资源使用不会超过管理员设定的上限。
通过配额管理,管理员可以更好地控制集群资源的分配和使用,避免某个用户或团队过度消耗资源,导致其他用户或团队无法获得足够的资源。同时,配额管理还可以帮助管理员预测和规划集群的资源需求,以便进行更合理的资源规划和扩展。
例如:
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
spec:
hard:
pods: "10" # 设置命名空间中 Pod 的最大数量为 10
services: "5" # 设置命名空间中服务的最大数量为 5
requests.cpu: "2" # 设置命名空间中请求的 CPU 总量为 2 核
requests.memory: "4Gi" # 设置命名空间中请求的内存总量为 4 Gibibyte
在这个示例中,spec.hard 字段用于设置命名空间中各项资源的硬限制。可以设置的资源包括 Pod 数量(pods)、服务数量(services)、CPU 请求量(requests.cpu)和内存请求量(requests.memory)等。
当命名空间中的资源达到了配额限制时,将无法创建新的资源对象,直到释放了一些资源。这样可以确保在 Kubernetes 集群中有效地管理资源使用,防止资源被耗尽导致集群不稳定。
五、Pod的网络与存储
1、Pod的网络模型
Kubernetes 中的每个 Pod 都有自己的 IP 地址,这些 IP 地址属于 Pod 内部的虚拟网络空间。Pod 的网络模型主要包括以下两种方式:
- Overlay 网络模型: 在 Overlay 网络模型中,Kubernetes 在节点之间创建一个虚拟网络层,用于 Pod 之间的通信。Pod 的 IP 地址由容器运行时在节点上创建的网络命名空间分配,这些 IP 地址可以在整个集群中唯一标识一个 Pod。
- Host 网络模型: 在 Host 网络模型中,Pod 直接使用节点的网络命名空间,与节点共享相同的网络栈。这意味着 Pod 的网络配置与节点的网络配置相同,Pod 的 IP 地址与节点的 IP 地址相同。Host 网络模型通常用于需要直接访问节点网络的场景,如使用 Host 网络模式的 Pod 可以直接访问节点上的网络服务。
2、Pod的通信机制
Pod 的通信机制主要包括以下几种方式:
- Pod 内通信: 同一 Pod 中的容器可以通过 localhost 来进行通信,它们共享相同的网络命名空间,因此可以直接通过本地主机进行通信。
- Pod 间通信: 不同 Pod 之间的通信通常通过 Pod IP 地址和端口进行。在同一个 Overlay 网络中,Pod 可以使用其 IP 地址来直接访问其他 Pod。在不同节点上的 Pod 之间的通信通过网络代理和路由器进行转发。
- Pod 与外部网络通信: Pod 可以通过服务(Service)对象来暴露自己的服务,使外部网络能够访问到 Pod 提供的服务。另外,Pod 也可以通过 Ingress 资源来实现对外部 HTTP 和 HTTPS 服务的路由和负载均衡。
3、Pod的存储卷类型
Pod的存储卷类型在Kubernetes中非常丰富,它们为容器提供了持久化或临时存储的能力。以下是一些主要的存储卷类型:
- EmptyDir:EmptyDir卷在容器启动时创建,并在容器移除时删除。它不具有持久化存储的能力,但非常适合用作同一个Pod内的多个容器间共享文件或作为容器数据的临时存储目录。EmptyDir的生命周期与Pod的生命周期相同,因此当Pod被删除时,其中的数据也会丢失。
- HostPath:HostPath卷将节点上的文件系统目录或文件挂载到Pod中。这种卷类型独立于Pod的生命周期,因此具有持久性。然而,如果发生Pod故障转移等情况,并且数据不在所有节点中都有备份,那么可能无法获取到数据。
- awsElasticBlockStore、azureDisk、gcePersistentDisk:这些卷类型分别对应于AWS、Azure和Google Cloud的块存储服务,用于提供持久化的存储解决方案。
- NFS、Glusterfs、CephFS:这些卷类型允许Pod访问网络文件系统,适用于需要在多个Pod之间共享数据的场景。
- PersistentVolumeClaim (PVC):PVC是用户对存储资源的请求。它与PersistentVolume (PV)一起使用,PV是集群中可用的网络存储。通过PVC和PV,用户可以动态地申请和管理存储资源。
- Secret:Secret卷用于存储敏感信息,如密码、令牌或密钥。这些数据可以在Pod中作为文件或环境变量进行访问,但不会被暴露给Kubernetes集群的其他部分。
- ConfigMap:ConfigMap用于将配置信息注入到Pod中。它可以存储各种格式的数据,并在Pod中以文件或环境变量的形式提供。
4、持久化存储与Pod的结合
持久化存储与Pod的结合在Kubernetes中是通过一系列机制和对象实现的,确保即使在Pod的生命周期中发生各种变化,存储的数据也能得以保留和复用。
Kubernetes提供了多种类型的持久化存储卷,如PersistentVolume(PV)和PersistentVolumeClaim(PVC)。PV是集群中可用的网络存储,而PVC则是用户对存储资源的请求。通过PVC和PV的绑定关系,用户可以动态地申请和管理存储资源。这种机制使得Pod可以请求并使用持久化存储,而无需关心存储的具体实现细节。
示例:
1、首先,先创建一个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 1Gi # 指定存储容量
volumeMode: Filesystem # 指定卷的类型为文件系统
accessModes: # 指定访问模式,此处可以根据需求选择 ReadWriteOnce、ReadOnlyMany、或 ReadWriteMany
- ReadWriteOnce
hostPath:
path: /test # 指定存储路径,这里为本地主机的一个目录
- metadata.name 字段定义了 PV 的名称,可以根据实际情况进行修改。
- spec.capacity.storage 字段指定了 PV 的存储容量,这里设置为 1Gi(1 Gibibyte)。
- spec.volumeMode 字段指定了 PV 的卷类型,这里设置为 Filesystem,表示使用文件系统。
- spec.accessModes 字段指定了 PV 的访问模式,这里设置为 ReadWriteOnce,表示 PV 可以被一个节点上的一个 Pod 以读写模式挂载。
- spec.hostPath.path 字段指定了 PV 的存储路径,这里设置为 /test,表示使用本地主机上的 /test目录作为存储路径。
2、创建一个PVC,
这里简单知道PVC是一个卷申请模板即可,用于Pod的持久化存储,在以后的章节中,我们会详细介绍
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: example-pvc
spec:
accessModes:
- ReadWriteOnce # 指定访问模式,与对应的 PV 一致
resources:
requests:
storage: 1Gi # 指定申请的存储容量,与对应的 PV 一致
- metadata.name 字段定义了 PVC 的名称,可以根据实际情况进行修改。
- spec.accessModes 字段指定了 PVC 的访问模式,这里设置为 ReadWriteOnce,与对应的 PV 一致,表示 PVC 可以被一个节点上的一个 Pod 以读写模式挂载。
- spec.resources.requests.storage 字段指定了 PVC 申请的存储容量,这里设置为 1Gi,与对应的 PV 一致。
3、创建一个Pod,使用刚刚创建的PVC
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: nginx:latest
volumeMounts:
- name: data-volume
mountPath: /data # 将 PVC 挂载到容器内部的路径
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: example-pvc # 指定使用的 PVC 的名称
- metadata.name 字段定义了 Pod 的名称,可以根据实际情况进行修改。
- spec.containers 字段定义了 Pod 中的容器列表,这里定义了一个名为 example-container 的容器,使用 nginx:latest 镜像。
- spec.containers.volumeMounts 字段定义了容器挂载的卷的列表,这里定义了一个名为 data-volume 的卷,并指定了挂载路径为 /data。
- spec.volumes 字段定义了 Pod 中使用的卷的列表,这里定义了一个名为 data-volume 的卷,并指定了使用的 PVC 的名称为 example-pvc。
💕💕💕每一次的分享都是一次成长的旅程,感谢您的陪伴和关注。希望这些关于Docker的文章能陪伴您走过技术的一段旅程,共同见证成长和进步!😺😺😺
🧨🧨🧨让我们一起在技术的海洋中探索前行,共同书写美好的未来!!!
更多推荐
所有评论(0)