跳转至

Kubernetes 简介

什么是 Kuernetes ?

Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。

为什么使用 Kubernetes 而不是 Docker ?

虽然 Docker 为容器化的应用程序提供了开放标准,但随着容器越来越多出现了一系列新问题: - 单机不足以支持更多的容器分布式环境下容器如何通信? - 如何协调和调度这些容器? - 如何在升级应用程序时不会中断服务? - 如何监视应用程序的运行状况? - 如何批量重新启动容器里的程序? 所以 Kubernetes 应运而生。

Kuernetes 能干什么?

功能 说明
服务发现和负载均衡 Kubernetes 可以使用 DNS 名称或自己的 IP 地址来暴露容器。 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。
存储编排 Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。
自动部署和回滚 你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
自动完成装箱计算 你为 Kubernetes 提供许多节点组成的集群,在这个集群上运行容器化的任务。 你告诉 Kubernetes 每个容器需要多少 CPU 和内存 (RAM)。 Kubernetes 可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源。
自我修复 Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。
密钥与配置管理 Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
批处理执行 除了服务外,Kubernetes 还可以管理你的批处理和 CI(持续集成)工作负载,如有需要,可以替换失败的容器。
水平扩容缩容 使用简单的命令、用户界面或根据 CPU 使用率自动对你的应用进行扩缩。
IPv4/IPv6 双栈 为 Pod(容器组)和 Service(服务)分配 IPv4 和 IPv6 地址。
为可扩展性设计 在不改变上游源代码的情况下为你的 Kubernetes 集群添加功能。

Kubernetes 组件

一组工作机器,称为节点, 会运行容器化应用程序。每个集群至少有一个工作节点。

工作节点会托管 Pod,而 Pod 就是作为应用负载的组件。 控制平面管理集群中的工作节点和 Pod。 在生产环境中,控制平面通常跨多台计算机运行, 一个集群通常运行多个节点,提供容错性和高可用性。

image-20240327164738053

  • 控制平面组件会为集群做出全局决策,比如资源的调度。 以及检测和响应集群事件,例如当不满足部署的 replicas 字段时,要启动新的 Pod)。在集群中的任何节点上运行。 然而,为了简单起见,设置脚本通常会在同一个计算机上启动所有控制平面组件, 并且不会在此计算机上运行用户容器。

  • 控制平面上的组件包括:

kube-apiserver 是什么

  • kube-apiserver: API 服务器

  • kubernetes 集群的中心集线器, 该组件负责公开了 Kubernetes API , 负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。

  • 终端用户和集群中的其他组件,通过 apiserver 与集群进行通信。一些监控系统和第三方服务也会与 API 服务器进行通信,从而与集群进行交互。

  • 使用 kubectl 命令管理集群时,背后其实是通过 RESTful 风格的 HTTP 协议与 api-server 进行通信的。集群内部的组件,如 scheduler, controller等,通过 gRPC 协议与 api-server 进行通信。API 服务器和集群中的其他组件之间的通信通过 TLS 进行,以防止对集群进行未经授权的访问。

Kubernetes api-server 负责以下工作:

  1. API管理:暴露集群API,并处理所有API请求。

  2. 身份验证和授权:使用客户端证书、承载令牌和HTTP Basic Authentication进行身份验证,通过ABAC和RBAC评估进行授权

  3. 处理API请求并验证API对象:如对pod、service等对象进行验证和操作

  4. 它是唯一与etcd通信的组件。

  5. Api-server负责协调控制平面与工作节点组件之间的所有进程。

  6. Api-server有一个内置的bastion apisserver代理。它是API服务器进程的一部分。它主要用于支持从集群外部访问ClusterIP服务,尽管这些服务通常只能在集群内部访问。

  7. 为了减少集群攻击面,确保API服务器的安全至关重要。

  • Kubernetes 是一个分布式系统,需要一个 etcd 这样高效的分布式数据库来支持 Kubernetes 的分布式特性。既能充当后端服务发现,又充当数据库。可称为 Kubernetes 集群的大脑。etcd 是控制平面中唯一的 statfulset 组件。一般使用外置 etcd 集群。

image-20240327171554792

开源的强一致性分布式键值存储,用作 Kubernetes 所有集群数据的后台数据库特点。

  1. 强一致性:如果对一个节点进行了更新,强一致性将确保立即更新到集群中的所有其他节点。在 CAP 定理的限制下,在强一致性和分区容忍的情况下,实现 100% 可用性是不可能的。
  2. 分布式:etcd 被设计成在保留强一致性的前提下,作为一个集群在多个节点上运行
  3. 键值存储:将数据存储为键和值的非关系数据库。它还公开了一个键值 API。数据存储构建在 BoltDB 之上(BoltDB是BoltDB的一个分支)。
  4. Etcd 采用 raft 共识算法,具有较强的一致性和可用性。它以领导者-成员方式工作,以实现高可用性并承受节点故障。

etcdkubernetes 集群中的作用:

当使用 kubectl 获取 kubernetes 对象的详细信息时,信息是从 etcd 获取的。此外,当部署对象(如Pod)时,将在 etcd 中创建一个条目。

  1. etcd 存储 Kubernetes 对象的所有配置、状态和元数据, 包括:pods、secrets、daemonsets、deployment、configmaps、statfulsets等对象
  2. etcd 允许客户端使用 Watch() API 订阅事件。Kubernetes api-server 使用 etcdwatch 功能来跟踪对象状态的变化。
  3. etcd 使用 gRPC公开键值 API。此外,gRPC 网关作为 RESTful 代理,将所有 HTTP API 调用转换为 gRPC 消息。这使得它成为 Kubernetes 的理想数据库。
  4. Etcd 以键值方式,将所有对象存储在 /registry 目录下。例如,一个在 default 命名空间中,名字为 nginxpod,可以在 /registry/pods/default/nginx 下找到。
  • kube-scheduler(调度器)负责在工作节点上调度 Kubernetes pod。部署 pod 时,需要指定 pod 需求,如 CPU、内存、亲和性、污染或容差、优先级、持久卷(PV)等。调度器的主要任务是根据 create 请求,为 pod 选择能够满足需求的最佳节点。

  • 调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。

image-20240327190943005

调度方式

通常情况下,在Kubernetes集群中,会有多个工作节点。调度程序如何从所有工作节点中选择节点的:

  1. kube调度器采用过滤和评分操作选择最佳节点。

  2. 在过滤阶段,调度器会找到适合调度pod的节点。根据待调度的pod需要的资源要求,筛选出满足资源要求的节点。假设有5节点可用资源满足pod的资源要求,那么这5个节点可以作为备选。如果没有节点能够满足资源要求,那么pod是不可调度的,并被移动到调度队列中。如果是一个大型集群,比如有100个工作节点,调度器不会遍历所有节点。通过调节参数percentageOfNodesToScore可以指定大型集群调度器遍历的节点比例。默认情况percentageOfNodesToScore=50%,调度器会尝试以round-robin的方式迭代50%的节点。如果工作节点分布在多个zone,那么调度器将遍历不同zone中的节点。对于超大型集群,percentageOfNodesToScore的默认值是5%

  3. 在评分阶段,调度器给过滤后的工作节点打分,并根据分数对节点进行排序。调度程序通过调用多个调度插件进行评分。最后,将选择评分最高的工作节点来调度pod。如果所有节点的评分相同,则随机选择一个节点进行调度。

  4. 一旦选定了节点,调度器会向api-server发送 “创建pod-node绑定关系” 的事件

关于 Scheduler 其他知识

  1. 它是一个Controller(控制器),会监听API服务器中的pod创建事件。

  2. 调度器有两个阶段。调度阶段和绑定阶段。它们合在一起为调度上下文。调度阶段选择一个工作节点,绑定阶段将该更改应用于集群。

  3. 调度器总是将高优先级pod放在低优先级pod之前进行调度。此外,在某些情况下,当pod在选定节点中开始运行后,pod也有可能会被驱逐或移动到其他节点。如果你想了解更多,请阅读Kubernetes pod优先级指南

  4. 您可以创建自定义调度器,并在集群中与原生调度器一起运行。部署pod时,可以在pod清单中指定自定义调度器。此时,调度结果将基于自定义调度器的逻辑。

  5. 调度器采用可插拔式的调度框架。也就是说,您可以将自定义插件添加到调度工作流中。

  • kube-controller-manager : 运行控制器进程。从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。

什么是控制器?

控制器是运行无限控制循环的程序。这意味着它会持续运行并观察对象的实际和期望状态。如果实际状态和期望状态存在差异,控制器会进行操作确保 kubernetes 资源/对象 处于期望状态。假设您想要创建一个 Deployment,您可以在 YAML 中指定它期望的状态,比如,2个副本、1个卷挂载、configmap等。内置的 controller 将确保 Deployment 始终处于期望的状态。如果用户将副本数更改为 5 个 Controller 将感知这个变化,并保证 Deployment 的副本的个数变成 5 个。

image-20240328113508543

有许多不同类型的控制器。以下是一些内置的 Kubernetes controllers

  • 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应

  • 命名空间控制器(Namespace Controller):命名空间控制器用于管理Kubernetes集群中的命名空间。它负责创建、删除和监视命名空间,并确保命名空间的资源按照预期进行分配和使用。

  • 部署控制器(Deployment Controller):部署控制器负责管理应用程序的部署。它通过创建和更新副本集(ReplicaSet)来实现部署的目标状态,并确保所需的Pod副本数目达到预期值。如果发生故障或需要进行更新,部署控制器会自动处理副本集的创建、删除和替换。

  • 副本集控制器(ReplicaSet Controller):副本集控制器负责监控Pod副本的状态,并根据用户定义的副本数目来维护Pod的稳定运行。当Pod的副本数目与期望的副本数目不一致时,副本集控制器会自动创建或删除Pod副本,以使副本数目达到预期值。

  • 守护进程集控制器(DaemonSet Controller):守护进程集控制器用于在Kubernetes集群中运行具有相同Pod配置的守护进程。它确保每个节点上都运行一个该类型的Pod副本,无论集群中的节点数目如何变化。当有新的节点加入集群或现有节点离开集群时,守护进程集控制器会相应地调整Pod的副本分布。

  • 任务控制器(Job Controller):任务控制器用于管理一次性任务的执行。它监测代表任务的Job对象,并创建Pod来运行这些任务直至完成。任务控制器确保任务成功完成,并可选择性地重试失败的任务。

  • 定时任务控制器(CronJob Controller):定时任务控制器负责周期性地运行任务。它基于用户定义的时间表创建和管理CronJob对象,并在指定的时间触发任务的执行。定时任务控制器可以帮助自动化需要按计划运行的任务,如定期备份、日志清理等。

  • 端点控制器(Endpoint Controller):端点控制器负责管理Service和与之关联的Pod之间的连接。它根据Service和Pod的变化来更新Endpoint对象,以确保流量正确路由到相应的Pod上。

  • 服务账号控制器(ServiceAccount controller):为新的命名空间创建默认的服务账号(ServiceAccount)。

Kube Controller Manager 作用

  1. Kube Controller Manager管理所有的控制器,控制器试图使集群保持在期望的状态。

  2. 可以使用与自定义资源定义相关联的自定义控制器扩展kubernetes。

什么是 cloud-controller-manager?

  1. 当在云环境中部署kubernetes时, Cloud Controller Manager(云控制器管理器)充当云平台api和kubernetes集群之间的桥梁。kubernetes核心组件可以独立工作,也允许通过插件方式与云提供商集成。(例如,kubernetes集群和AWS云API之间的接口)

  2. cloud-controller-manager 仅运行特定于云平台的控制器。 因此如果你在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。

  3. 与 kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的控制回路组合到同一个可执行文件中, 供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。

image-20240328140110563

  • 下面的控制器都包含对云平台驱动的依赖:

    • 节点控制器(Node Controller):该控制器通过与云提供商API通信,更新节点相关信息。例如,节点的label,annotation,主机名、CPU和内存、节点运行状况等
    • 路由控制器(Route Controller):用于在底层云基础架构中设置路由,负责在云平台上配置网络路由。这样不同节点上的pod就可以互相通信了。
    • 服务控制器(Service Controller):负责为kubernetes服务部署负载均衡器,分配IP地址等。用于创建、更新和删除云提供商负载均衡器
    • 存储控制器(Volume controller):通过与云提供商的 API 通信,为 Kubernetes 的 Pod 提供云存储解决方案。它管理存储卷(Volume)的创建、挂载和销毁等操作,使得 Pod 可以在云平台上使用具体的存储资源
    • 网关控制器(Ingress controller):负责为 Kubernetes 的 Ingress 对象配置云平台上的网络入口。它与云提供商的负载均衡器或其他网络服务集成,将外部流量路由到集群中的不同服务。通过 Ingress controller,可以实现将外部请求转发到正确的后端服务及应用程序,并进行负载均衡、SSL 终止等操作。

节点(官网称之为节点,工作中叫做工作节点 woker node.)负责容器化应用的运行。工作节点包含如下组件:

  • kubelet 会在集群中每个节点(node)上运行。 kubelet 作为守护进程,不是在容器中运行的,而是通过 systemd 来管理的。kubelet 不会管理非 Kubernetes 创建的容器。它保证容器(containers)都运行在 Pod 中。

  • kubelet 是基于 PodSpec 来工作的。每个 PodSpec 是一个描述 Pod 的 YAML 或 JSON 对象。 kubelet 接受通过各种机制(主要是通过 apiserver)提供的一组 PodSpec,并确保这些 PodSpec 中描述的容器处于运行状态且运行状况良好。

image-20240328144007903

kubelet 有什么功能:

  1. 为pod创建,更新,删除容器

  2. 负责处理存活(Liveness)、就绪(Readiness)和启动(Startup)探针

  3. 通过读取pod配置,在主机上为卷挂载创建相应的目录来挂载卷。

  4. 收集node, pod状态,发送到api server

  5. Kubelet也是一个控制器,它监视pod的变化,并利用部署在节点上的 容器运行时 拉取镜像、运行容器等。

  6. 能够接收来自 API 服务器的 podSpec 之外,还接受来自文件、HTTP端口和 HTTP 服务器的 podSpec。Kubernetes 的静态pod,就是是“从文件中获取podSpec”的一个很好的例子。(静态pod由 kubelet 控制,而不是 API 服务器。)

kubelet 其他知识:

  1. Kubelet使用CRI(容器运行时接口)-- gRPC协议,与容器运行时通信。

  2. 通过暴露http端口提供日志流,并为客户端提供exec会话。

  3. 通过CSI(容器存储接口container storage interface)-- gRPC协议,配置卷。

  4. 它使用集群中配置的CNI插件为pod分配IP地址,并为pod设置必要的网络路由和防火墙规则。

什么是 kube-proxy ?

  • kube-proxy 是集群中每个节点(node)上所运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。

  • kube-proxy 维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。

  • 如果操作系统提供了可用的数据包过滤层,则 kube-proxy 会通过它来实现网络规则。 否则,kube-proxy 仅做流量转发。

  • Kube-proxy是一个k8s Daemonset,在每个节点上运行。它是实现Kubernetes Services概念的代理组件。(为每组Pod提供具有负载均衡的DNS)。它主要代理UDP、TCP和SCTP。(不能直接代理HTTP)

  • 当使用Service (ClusterIP)公开pod时,Kube-proxy将创建网络规则,将流量发送到分组在Service对象下的后端pod(端点)。也就是说,所有的负载平衡和服务发现都由Kube代理处理。

image-20240328152908981

kube-proxy 是怎么工作的?

Kube代理与API server进行交互,获取有关Service(ClusterIP)和pod ip、port(endpoints)的详细信息。并监视service和endpoint的变化。接着,Kube-proxy可以使用以下任何一种代理模式,将流量路由到service绑定的pod。kube-proxy 会根据不同配置以不同的模式启动:

默认模式。在IPTables模式下,流量由IPtable规则处理。这意味着将为每个service创建IPtable规则。这些规则捕获到达ClusterIP的流量,然后将其转发到后端pod。此外,在此模式下,kube-proxy采用随机的方式选择后端pod进行负载均衡。一旦建立了连接,请求就会转到同一个pod,直到连接被终止。使用 iptables 处理流量的系统开销较低,因为流量由 Linux netfilter 处理, 无需在用户空间和内核空间之间切换。这种方案也更为可靠

IPVS 为将流量均衡到后端 Pod 提供了更多负载均衡算法:

  • rr(round-robin 轮询):流量被平均分发给后端服务器。默认算法
  • wrr(Weighted Round Robin 加权轮询):流量基于服务器的权重被路由到后端服务器。 高权重的服务器接收新的连接并处理比低权重服务器更多的请求。
  • lc(least connection 最少连接):将更多流量分配给活跃连接数较少的服务器。
  • wlc(Weighted Least Connection 加权最少连接):将更多流量按照服务器权重分配给连接数较少的服务器,即基于连接数除以权重。
  • lblc(Locality based Least Connection 基于地域的最少连接):如果服务器未超载且可用,则针对相同 IP 地址的流量被发送到同一后端服务器; 否则,流量被发送到连接较少的服务器,并在未来的流量分配中保持这一分配决定。
  • lblcr(Locality Based Least Connection with Replication 带副本的基于地域的最少连接):针对相同 IP 地址的流量被发送到连接数最少的服务器。 如果所有后端服务器都超载,则选择连接较少的服务器并将其添加到目标集中。 如果目标集在指定时间内未发生变化,则从此集合中移除负载最高的服务器,以避免副本的负载过高。
  • sh(source hashing源哈希):通过查找基于源 IP 地址的静态分配哈希表,将流量发送到某后端服务器。
  • dh(destination hashing目标哈希):通过查找基于目标地址的静态分配哈希表,将流量发送到某后端服务器。
  • sed(Shortest Expected Delay 最短预期延迟):流量被转发到具有最短预期延迟的后端服务器。 如果流量被发送给服务器,预期延迟为 (C + 1) / U,其中 C 是服务器上的连接数, U 是服务器的固定服务速率(权重)。
  • nq(never queue永不排队):流量被发送到一台空闲服务器(如果有的话),而不是等待一台快速服务器; 如果所有服务器都忙碌,算法将退回到 sed 行为。
  • 容器运行时运行在Kubernetes集群的所有节点上。它负责从镜像仓库拉去镜像、运行容器、为容器分配和隔离资源,以及管理主机上容器的整个生命周期。

  • kubernetes要求容器运行时必须实现了CRI(Container Runtime Interface 容器运行时接口)。CRI 是一个插件接口,它使 kubelet 能够使用各种容器运行时,无需重新编译集群组件,是 kubelet 和容器运行时之间通信的主要协议。

常见的容器运行时

  1. containerd:官网推荐的容器运行时,是从docker分离出来的

  2. CRI-O:是containerd的一个替代品,专门为ikubernetes创建的一个容器运行时

  3. Docker Engine:需要先调用dockershim,然后调用docker,再调用containerd,最后调用底层的 runc

  4. Mirantis Container Runtime:是一种商用容器运行时,以前称为 Docker 企业版。

image-20240329104552562

CRI-O 容器运行时与 kubernetes 的交互

image-20240329110634350

  1. 当 API server 对 pod 发出新的请求时,kubelet 与 CRI-O 守护进程交互,通过 Kubernetes 容器运行时接口启动所需的容器。

  2. CRI-O 使用 containers/image 库,根据配置的容器信息,检查并 pull 镜像。

  3. CRI-O 为容器生成 OCI 运行时规范(OCI specification ,JSON格式)。

  4. CRI-O 启动一个OCI兼容的运行时(runc),按照运行时规范启动容器进程。

除了核心组件之外,kubernetes集群还需要附加组件才能完全运行。是否选择一个插件取决于项目需求和用例。常见的插件有:

=== note "CNI"

!!! note "CNI 与 kubernetes 的交互如下:"

    1. Kube-controller-manager负责为每个节点分配pod CIDR。每个pod从pod CIDR中获得一个唯一的IP地址。

    2. Kubelet与容器运行时交互以启动预定的pod。CRI插件是Container运行时的一部分,它与CNI插件交互以配置pod网络。

    3. CNI Plugin允许使用分布在相同或不同节点的pod之间建立网络。

=== note "CORE-DNS"

=== note ""