介绍
Controller Manager 是控制平面的一个重要组件,负责维护 Kubernetes 集群的整体状态。
流程:
image-20231210114754993
在集群中 Controller Manager 主要做以下几件事情:
Kubernetes 中内置了许多 Controller,当资源状态发生变化时,Controller Manager 会通知这些 Controller 做出决策和执行操作。
Cloud Controller Manager
在云端部署 Kubernetes 时,需要将 Kubernetes 集群与云平台连接起来,以便 Kubernetes 集群可以使用云平台提供的资源,如虚拟机、负载均衡器、存储卷等。Cloud Controller Manager 提供了将 Kubernetes 集群与云平台连接起来的功能。它可以使用云平台的 API 创建和管理云资源
Cloud Controller Manager 主要用于以下场景:
Kubelet 是 Kubernetes 集群中的节点代理,kubelet 组件运行在每个节点上,负责在节点上运行 Pod:
image-20231210160441907
说明:
图片中 kubelet 组件通过 API Server 与集群的控制平面进行通信。从 API Server 获取 Pod 的定义信息,并根据 Pod 的定义信息创建和管理容器。
除此之外,kubelet 还负责以下任务:
Pod 的详细启动流程:
image-20231210162241039
说明
整个创建 Pod 的过程是自动化的,由 Kubernetes 各组件协同工作完成。
在没有 CRI(Container Runtime Interface) 之前,Kubernetes 与 Docker 容器运行时是紧密耦合的。这意味着 Kubernetes 只能使用 Docker 来创建和管理容器。但 CRI 的引入,改变了这一点。CRI 是 K8s 集群的一个插件接口,运行于集群的每个节点中,它使 kubelet 能够使用各种容器运行时而不需要重新编译:
image-20231210164710033
使用 CRI 的主要原因包含:
CRI(Container Runtime Interface)是 Kubernetes 通过 gRPC 协议定义的一系列接口规范。
image-20231210165835899
理解 CRI 作为一组 gRPC 服务涉及以下几个方面:
RuntimeService
负责 Pod 和容器的生命周期管理,例如创建、启动、停止容器等。ImageService
负责镜像管理,例如拉取、列出和删除容器镜像。在容器技术刚刚兴起时,每个容器运行时都使用自己的容器格式和接口。这导致不同容器运行时之间无法互操作,给容器的开发、部署和管理带来了困难。为了解决容器互操作性的问题,Docker、CoreOS 和 appc 维护者于 2015 年 6 月启动了 OCI 项目。OCI 项目旨在定义容器格式和运行时的标准,以促进容器的互操作性。
OCI 由两个主要部分组成:
image-20231210171626184
Image Specification:
描述了容器镜像的结构和内容。它定义了容器镜像的根文件系统、环境变量、启动命令等。Image Specification 使不同容器运行时能够理解和使用容器镜像。
Runtime Specification:
定义了容器运行时的接口。它定义了容器运行时如何创建、启动、停止和删除容器。Runtime Specification 使 Kubernetes 等容器编排系统能够与不同容器运行时进行交互。
总结 OCI 的一些主要优势:
containerd
是 Docker 的一个核心组件,因为containerd
符合 OCI 标准,所以它也可以不依赖 Docker 单独在 Kubernetes 中使用。
为什么更建议在 Kubernetes 单独使用 containerd ?
containerd
提供了容器运行所必需的核心功能,而不包括 Docker 的一些附加功能,这使得它更加轻量和高效。对于需要最小化资源占用的环境,如边缘计算或微服务架构。containerd
占用更少的系统资源(CPU、内存),这对于资源受限的环境非常重要。containerd
完全遵循 OCI 标准,可以无缝地与任何遵循 OCI 规范的容器镜像和运行时接口(如 CRI)一起工作。这种兼容性是在多种云环境和操作系统中部署容器的关键。containerd
可以简化设置并减少冗余。单独使用 containerd 在问题定位上也有优势,这里展示三种不同的容器运行时配置方式与 Kubernetes kubelet 组件的交互:
image-20231210172944007
这里说明因为 OCI 规范,Kubernetes 它已经不再依赖 Docker 作为唯一的容器运行时,并且可以支持多种运行时如 containerd 和 CRI-O。这种解耦提高了 Kubernetes 的灵活性和效率,同时也降低了架构的复杂性。
在 Kubernetes 中使用 Docker 和 containerd 作为容器运行时的差异对比:
image-20231210173721674
说明:因为 OCI 使 Kubernetes 的运行时层更加标准化,减少了额外的抽象层。
containerd 在各个场合中的性能表达都好过预期:
image-20231210174000326
各个运行时的对比:
image-20231210174043727
在 CNI(Container Network Interface) 之前,不同的容器运行时(如 Docker, rkt)有自己的网络配置方法,这导致了兼容性和移植性问题。CNI 为配置容器网络提供了一组标准的接口和插件。CNI 的目的是为容器运行时提供网络配置,以支持在不同环境下的容器网络操作。CNI 的出现解决了以下问题:
CNI 为容器化环境中的网络配置提供了标准化和一致性,并且能够满足容器和容器编排工具的各种网络需求。
CNI 为了能够支持云原生环境中对复杂的网络场景,应对不断演变的技术和应用场景的能力。所以使用模块化设计(插件)实现。
CNI 的插件主要分为以下几类:
常见的主插件包括:
Meta:附加功能:
这些插件可以独立使用或者组合使用,以支持各种网络配置需求。
插件的运行机制设计用于在容器初始化和销毁的时候配置和清理网络。以下是详细的运行机制:
image-20231210194500175
说明:
CNI 插件的运行机制的核心在于提供了一个标准化的方式来设置和管理容器网络,这样不同的容器运行时和编排系统就可以使用各种不同的网络技术,同时保持网络配置的一致性和可移植性。
在使用 CNI 的上下文中,cni-bin-dir
和 cni-conf-dir
是两个重要的目录,它们在 Kubernetes 集群中被 kubelet 用来配置网络。
cni-bin-dir:
这个目录包含了所有 CNI 插件的可执行文件。当 CNI 需要初始化一个容器的网络时,kubelet 会调用这个目录下的对应插件。例如,您可能会在这个目录下找到如 bridge
、loopback
和 host-local
等网络插件的二进制文件。默认情况下,CNI 的二进制文件目录通常是 /opt/cni/bin
。
cni-conf-dir:
这个目录包含了 CNI 配置文件,这些文件以 .conf
或 .conflist
结尾。这些配置文件定义了网络的具体参数,如网络名称、子网、IP 范围、网关、使用的 CNI 插件及其特定的配置选项。默认情况下,CNI 的配置文件目录通常是 /etc/cni/net.d
。
kubelet 在启动时会检查这些目录,并使用这些目录下的插件和配置文件来为容器设置网络。
在 Kubernetes 集群上运行 kubelet
,可以通过传递 --cni-bin-dir
和 --cni-conf-dir
参数来指定这些目录,如果不指定,则会使用默认值。
作为一个 CNI 插件,Flannel 是一个简单的覆盖网络解决方案,Flannel 解决了一系列与容器网络相关的问题:
适合 Flannel 的场景:
Calico 是一个广泛使用的网络和网络安全解决方案,特别是在 Kubernetes 环境中。它使用标准的 IP 路由,提供高性能和高可扩展性的网络解决方案。
为什么会有 Calico ?:
Calico 特点:
适合使用 Calico 的场景:
Calico 为需要高性能、高安全性和可扩展性的网络环境提供了一个强大而灵活的解决方案,适合各种规模和复杂度的网络配置。
CNI 常见插件对比:
image-20231210202903172
容器运行时 CSI(Container Storage Interface)是 Kubernetes 中负责容器存储管理的接口规范。CSI 将容器编排系统(CO)和存储系统解耦,使容器存储管理成为可插拔的插件。
CSI 产生的原因:
Kubernetes 支持多种存储插件,这些插件提供了不同的存储功能和特性。主要有以下几种:
**In-tree Storage **:
Out-of-tree FlexVolume:
Out-of-tree CSI (Container Storage Interface) :
CSI 驱动(Container Storage Interface Driver)是遵循 CSI 规范的一种存储插件,用于容器编排系统(如 Kubernetes)中,实现存储卷的生命周期管理。
image-20231210205711631
CSI 驱动一般包含:
External-attacher、External-provisioner、External-resizer、external-snapshotter、node-driver-register、CSI Driver
CSI 驱动与存储系统进行交互,根据 external-attacher、external-provisioner、external-resizer 和 external-snapshotter 的调用执行具体的存储操作。
emptyDir 是一种常见的临时存储卷,它在 Pod 被创建时创建,在 Pod 被删除时删除。emptyDir 卷最初是空的,可以由 Pod 中的容器使用。要使用 emptyDir,需要在 Pod 的 spec 中定义一个 volume 对象。volume 对象的类型为 emptyDir。示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
部署文件说明:
volumes
中定义一个名为 cache-volume
的 emptyDir 临时存储卷,代表 Pod 使用本地临时存储spec.containers
中指定 nginx
挂载 cache-volume
的卷到容器的 /cache
目录使用emptyDir 易于使用且数据在容器之间共享,适合存储临时文件且需要容器间共享数据的场景。
hostPath 卷是将 Pod 挂载到宿主机上的目录。它是一种本地存储,在 Pod 被删除时不会被删除。示例:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: config-volume
volumes:
- name: config-volume
hostPath:
path: /etc/nginx/conf.d
部署文件说明:
volumes
中定义一个 config-volume
的 hostPath 卷,指定路径为宿主机的 /etc/nginx/conf.d
目录。spec.containers
中的 volumeMounts
属性中引用 cache-volume
卷挂载到容器内 //etc/nginx/conf.d
目录使用为 hostPath
卷指定类型可以提供额外的信息(或者强制性的校验)关于期望的 hostPath
应该如何存在或者创建。
volumes:
- name: my-host-path
hostPath:
path: /some/path/on/host
type: DirectoryOrCreate
在上面的示例中,type: DirectoryOrCreate
指定了如果在宿主机上 /some/path/on/host
路径不存在,Kubernetes 应该创建一个目录。
使用 hostPath 的注意事项:
hostPath
卷绑定到特定节点上,如果 Pod 被调度到其他节点,数据不会随之迁移。hostPath
依赖于宿主机上的特定路径,这可能影响到 Pod 的可移植性。总结:hostPath
卷通常只会用于特定的用例,不推荐在生产环境使用。
针对持久化存储,Kubernetes 引入 StorageClass,Volume,PVC,PVC 等概念,并且将存储独立于 Pod 的生命周期进行管理。
PersistentVolume 是用于存储持久化数据的资源,代表一个集群级别的资源,它代表了一块实际的存储空间,例如一个 NFS 、一个云存储卷或一个本地磁盘。PV 可以被集群中的任何用户通过 PersistentVolumeClaim (PVC) 来请求和使用。
PersistentVolume 具有以下特性:
StorageClass
自动创建)。示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 100Mi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
这个 PersistentVolume
对象表示了一块在宿主机上、位于 /mnt/data
目录的存储,其大小为 100 MB,并且可以被 Kubernetes 集群中的 Pods 使用。但它仅限于部署在同一节点上的 Pod,因为它使用了宿主机的本地路径。
PersistentVolumeClaim (PVC) 是 Pod 对 PersistentVolume 的请求。指定了需要的 PersistentVolume 类型和大小。Kubernetes 将使用该信息来查找可用的 PersistentVolume,并将其分配给 Pod。
PersistentVolume 和 PersistentVolumeClaim 之间的关系
PersistentVolume 和 PersistentVolumeClaim 之间的关系类似于订单和商品的关系。PersistentVolume 是商品,PersistentVolumeClaim 是订单。Pod 使用 PersistentVolumeClaim 来订购 PersistentVolume。
示例:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
在这个配置中,PersistentVolumeClaim 请求一个容量为 100MB 的存储,并且使用名为 manual 的 StorageClass(绑定到现有的 PersistentVolume)。一旦这个 PVC 被提交到 Kubernetes 集群(通过 kubectl apply -f <filename>.yaml
),集群将尝试找到或动态创建一个符合这些要求的 PersistentVolume(PV)并与之绑定。
在 Pod 中使用 PVC
PVC 创建的目的是提供给 Pod 使用。示例:
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
此配置的关键点在于,它创建了一个 Pod,并且通过上面创建的 PVC task-pv-claim
挂载了一个持久化卷到 Nginx 的内容目录中。这意味着任何存储在该目录中的内容(如网页文件)将被持久化。
StorageClass 是一种资源类型,它允许管理员定义不同类型的存储方案和特性,以及如何在集群中供应这些存储。通过使用 StorageClass
,可以实现动态存储卷的供应,这意味着当有新的 PersistentVolumeClaim
(PVC) 请求时,相应的 PersistentVolume
(PV) 会被自动创建和配置,而无需管理员手动预先创建。
StorageClass 和 PVC,PV 之间的关系:
image-20231211070828874
示例 StorageClass 配置:
假设使用 AWS 的 Elastic Block Store (EBS) 作为存储后端:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: my-storage-class
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
说明:
my-storage-class
是这个 StorageClass
的名称。kubernetes.io/aws-ebs
)。type: gp2
指定了使用 AWS 的通用型 SSD 卷。reclaimPolicy: Retain
表示当 PVC 被删除时,相应的 PV 不会被自动删除。allowVolumeExpansion: true
允许以后扩展由这个类创建的存储卷。通过定义 StorageClass,集群的用户可以在创建 PVC 时指定所需的存储类型和配置,而无需关心具体的存储实现细节。
示例 PVC 使用 StorageClass:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
在这个示例中:
PersistentVolumeClaim
的名称是 my-pvc
。storageClassName
设置为 my-storage-class
,这将使用之前定义的 StorageClass
来动态创建 PV。accessModes
是 ReadWriteOnce
,意味着这个存储卷可以被单个节点以读写模式挂载。100Mi
(100兆字节)。当这个 PVC 被提交到集群时,Kubernetes 会自动根据 my-storage-class
StorageClass
的定义来动态创建一个相应的 PV,并将其与这个 PVC 绑定。然后,这个 PVC 可以被 Pod 使用,以访问所供应的持久存储资源。
独占的 Local Volume 是指一种特定类型的持久卷(Persistent Volume,PV),它直接使用节点(Node)上的存储资源,如磁盘、分区或目录。这种类型的卷被称为“独占”因为它们只能被同一节点上的 Pod 使用,而无法跨节点共享或访问。
示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-local-volume
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
local:
path: /mnt/data
在这种情况下,my-local-volume
是一个独占的 Local Volume,它具有 1Gi 的容量,ReadWriteOnce
的访问模式,以及 /mnt/data
的本地路径。
关于持久化存储的最佳实践: