一、 简介
Kubernetes,也称为K8s,是一个开源的容器编排系统,用于自动部署、扩展和管理容器化应用程序,帮助开发者更高效地跨集群管理应用。本文总结了 k8s 的基础概念和技术架构。
二、基础概念
1. 云原生(Cloud Native)
云原生是在云计算环境中构建、部署和管理现代应用程序的软件方法。云原生架构基于以下几个核心要素:
- 微服务:将应用分解为一组更小的轻量级服务,而这些服务可通过应用编程接口 (API) 轻松组合并相互连接。
- 容器和编排
- DevOps
- 持续集成和持续交付 (CI/CD)
2. 容器化(Containerization)
容器化是指将应用程序及其依赖项打包成一个容器,使其可以在任何支持容器的环境中运行,方便部署和管理。
- 容器本身不需要运行一个完整的操作系统,因此比虚拟机更轻量。
- 容器可以共享同一个操作系统内核,减少资源浪费。
- 容器可以在任何支持容器的环境中运行,无论是本地、云端还是其他环境。
- 容器提供了应用程序之间的隔离,确保应用程序不会相互影响。
3. 编排(Orchestration)
容器编排指自动化和管理容器化应用程序的部署、扩展、管理和监控的过程。编排涉及到多个容器之间的协调和管理,以确保应用程序的正常运行和高可用性。
- 容器生命周期管理,包括创建、启动、停止和删除。
- 容器路由发现与网络管理,确保服务之间可以相互通信。
- 容器负载均衡与弹性伸缩,流量分发,自动增加或减少容器实例。
- 监控和日志:监控应用程序的性能和日志,确保应用程序的正常运行。
二、 集群架构
kubectl: 使用 Kubernetes API 与 Kubernetes 集群的控制面进行通信的命令行工具
API server:公开 Kubernetes HTTP API ,负责处理接受请求的工作,是 Kubernetes 控制平面的前端
controller manager:负责运行控制器进程
schedular: 节点调度器,查找尚未绑定到节点的 Pod,并将每个 Pod 分配给合适的节点。
etcd: key-value 数据库,负责 Kubernetes 所有集群数据的持久化存储
pod: 一个或多个应用容器的组合,并且包含共享的存储、IP 地址和有关如何运行它们的信息,只有容器紧耦合并且需要共享磁盘等资源时,才应将其编排在一个 Pod 中。
runtime: 运行容器的启动器,负责解析容器镜像并创建隔离的运行环境。
kubelet:节点管理器,负责 Kubernetes 控制面和节点之间通信的进程,确保 Pod 及其容器正常运行
kube-proxy: 在每个节点上所运行的网络代理,允许从集群内部或外部的网络会话与 Pod 进行网络通信
1. 集群与节点
集群是指一组计算机或节点,共同工作以提供一种分布式计算环境。集群中的节点可以是物理机或虚拟机,集群可以提供高可用性、可扩展性和负载均衡等特性。一个 Kubernetes 实例是一个集群,这些节点由控制面负责管理。
2. 工作负载(workload)
一个工作负载是运行在 Kubernetes 上的一个应用,通常你不需要直接创建 Pod,甚至单实例 Pod。相反,你会使用工作负载资源来创建和管理一组 Pod 副本。Kubernetes 提供了以下几种工作负载资源:
- Deployments 通常适用于不保持状态的负载,任何 Pod 都是可替换的
- StatefulSets 用来管理有状态应用的工作负载,每个 Pod 都有一个永久不变的 ID
- DaemonSets 确保每个节点 node 上都运行有 pod,适用于需要在每个节点上部署的系统级任务:日志收集、节点监控(采集 CPU、内存、磁盘等指标),网络插件(确保每个节点运行网络组件,实现 Pod 间网络互通),安全扫描工具等。
- Jobs 一次性任务,运行完成后就会停止,CronJob 通过重复调度启动一次性的 Job。
容器镜像:一个随时可以运行的软件包, 包含运行应用程序所需的一切:代码和它需要的所有运行时、应用程序和系统库,以及一些基本设置的默认值。
引用依赖:一个工作负载依赖于另一个工作负载的运行状态或输出。
灰度发布:同时维护新旧版本,是将新版本逐渐推广到生产环境中的一种发布策略。将一部分用户路由到新版本,一部分用户路由到旧版本,若新版本表现较好,则逐渐增加路由到新版本的用户流量,直到所有用户都使用新版本。
Scaling 扩缩容
- Horizontal Scaling 垂直扩缩,将更多资源(例如:内存或 CPU)分配给已经为工作负载运行的 Pod,是通过替换容器镜像来实现的。
- Vertical Scaling 横向扩缩,是通过改变工作负载中的副本数量来实现的。Pod 自动扩缩容实现为一个间歇运行的控制回路,默认间隔为 15 秒。在每个时间段内,控制器管理器都会根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率,进而计算出目标副本数。
3. 存储
Volume 卷为 Pod 中的容器提供了一种通过文件系统访问和共享数据的方式,数据共享可以发生在容器内不同本地进程之间,或在不同容器之间,或在多个 Pod 之间。容器中的文件在磁盘上是临时存放的,而卷可以提供持久化存储数据,这样即使 Pod 重启或被替换,存储的数据仍然可用。当 Pod 被启动时,容器中的进程看到的文件系统视图是由它们的容器镜像 的初始内容以及挂载在容器中的卷所组成的。
Storage Class 存储类,可以理解为存储系统的配置文件,定义了如何创建 PV,例如,使用哪种存储卷(块存储或文件系统)。
Volume Snapshot 卷快照是数据卷在某个时间点的副本,可以用于创建新的数据卷或恢复数据卷到之前的状态。卷快照是只读的,可以被用来创建新的 PVC。
Persistent Volume 持久卷是集群中的一块存储资源,可以由管理员事先制备, 或者使用存储类来动态制备。PVC 存储声明是用户创建的,用于请求一定量的存储空间,描述了所需的存储空间的大小、访问模式(例如,读写或只读)和新建方式,会耗用 PV 资源。
4. 网络
Pod:集群中的每个 Pod 都会获得自己的、独一无二的集群范围 IP 地址。Pod 有自己的私有网络命名空间,Pod 内的所有容器共享这个命名空间, 运行在同一个 Pod 中的不同容器的进程彼此之间可以通过 localhost 进行通信。
集群网络 处理 Pod 之间的通信,所有 Pod 可以与所有其他 Pod 直接进行通信, 无论它们是在同一个节点还是在不同的节点上。
Service 为由一个或多个后端 Pod 实现的服务提供一个稳定长效的 IP 地址或主机名, 其中组成服务的各个 Pod 可以随时变化。Service 的暴露方式是四层,只关心 TCP/UDP 协议的流量转发,用 IP 端口暴露服务。
● ClusterIP 通过集群的内部 IP 公开 Service,只能够在集群内部访问,可以使用 Ingress 或者 Gateway API 向公共互联网公开服务。
● NodePort 通过每个节点上的 IP 和静态端口公开 Service,作用域可以为集群内或集群外,可以自由设置自己的负载均衡解决方案 。
● LoadBalancer 使用云平台的负载均衡器向外部公开 Service,来自外部负载均衡器的流量将被直接重定向到后端各个 Pod 上,是一种更简单但可配置性较低的 Ingress 机制。
Ingress 为集群外部到集群内部服务提供 HTTP(S) 流量路由,并将流量分发到各个关联的 service 上。Ingress 的暴露方式是七层,使用 URL 暴露服务,可以按权重/header/cookie 切分流量,从而将同一个 url 路由到多个服务中进行灰度发布。
5. 调度
在 Kubernetes 中,调度是指将 Pod 放置到合适的节点上,以便对应节点上的 Kubelet 能够运行这些 Pod。调度器通过 Kubernetes 的监测机制来发现集群中新创建且尚未被调度到节点上的 Pod,然后选择一个最佳节点来运行新创建的或尚未调度的 Pod。
节点调度:pod 与节点间的调度策略
- 亲和调度:将 Pod 调度到具有特定标签或属性的节点上
- 反亲和调度:将 Pod 调度到不具有特定 CPU 架构/内存大小/存储类型的节点上
可用区打散:打散策略将工作负载的 Pod 平均打散部署在各个可用区,提高应用的高可用性,至少需要两个可用区。
Pod 调度:pod 间的调度策略
- 亲和调度:将 Pod 调度到与其他 Pod 相同的节点上,以共享资源
- 反亲和调度:确保多个 Pod 被调度到不同的节点上,以提高可用性
容忍调度:容忍度是指 Pod 对节点上的污点(节点上的资源不足/网络不稳定/存储空间不足)的容忍程度,容忍度可以被设置为:
- NoSchedule:Pod 将不会被调度到具有该污点的节点上
- PreferNoSchedule:Pod 将尽量避免被调度到具有该污点的节点上,但如果没有其他选择,仍然可以被调度到该节点上
- NoExecute:Pod 将不会被调度到具有该污点的节点上,并且如果已经被调度到该节点上,将被驱逐