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。 在生产环境中,控制平面通常跨多台计算机运行, 一个集群通常运行多个节点,提供容错性和高可用性。
-
控制平面组件会为集群做出全局决策,比如资源的调度。 以及检测和响应集群事件,例如当不满足部署的 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 负责以下工作:
-
API管理:暴露集群API,并处理所有API请求。
-
身份验证和授权:使用客户端证书、承载令牌和HTTP Basic Authentication进行身份验证,通过ABAC和RBAC评估进行授权
-
处理API请求并验证API对象:如对pod、service等对象进行验证和操作
-
它是唯一与etcd通信的组件。
-
Api-server负责协调控制平面与工作节点组件之间的所有进程。
-
Api-server有一个内置的bastion apisserver代理。它是API服务器进程的一部分。它主要用于支持从集群外部访问ClusterIP服务,尽管这些服务通常只能在集群内部访问。
-
为了减少集群攻击面,确保API服务器的安全至关重要。
Kubernetes
是一个分布式系统,需要一个etcd
这样高效的分布式数据库来支持Kubernetes
的分布式特性。既能充当后端服务发现,又充当数据库。可称为Kubernetes
集群的大脑。etcd
是控制平面中唯一的statfulset
组件。一般使用外置etcd
集群。
开源的强一致性分布式键值存储,用作 Kubernetes
所有集群数据的后台数据库特点。
- 强一致性:如果对一个节点进行了更新,强一致性将确保立即更新到集群中的所有其他节点。在
CAP
定理的限制下,在强一致性和分区容忍的情况下,实现100%
可用性是不可能的。 - 分布式:
etcd
被设计成在保留强一致性的前提下,作为一个集群在多个节点上运行 - 键值存储:将数据存储为键和值的非关系数据库。它还公开了一个键值
API
。数据存储构建在BoltDB
之上(BoltDB是BoltDB的一个分支)。 Etcd
采用raft
共识算法,具有较强的一致性和可用性。它以领导者-成员方式工作,以实现高可用性并承受节点故障。
etcd
在 kubernetes
集群中的作用:
当使用 kubectl
获取 kubernetes
对象的详细信息时,信息是从 etcd
获取的。此外,当部署对象(如Pod)时,将在 etcd
中创建一个条目。
etcd
存储Kubernetes
对象的所有配置、状态和元数据, 包括:pods、secrets、daemonsets、deployment、configmaps、statfulsets等对象etcd
允许客户端使用Watch() API
订阅事件。Kubernetes api-server
使用etcd
的watch
功能来跟踪对象状态的变化。etcd
使用gRPC
公开键值API
。此外,gRPC
网关作为RESTful
代理,将所有HTTP API
调用转换为gRPC
消息。这使得它成为Kubernetes
的理想数据库。Etcd
以键值方式,将所有对象存储在/registry
目录下。例如,一个在default
命名空间中,名字为nginx
的pod
,可以在/registry/pods/default/nginx
下找到。
-
kube-scheduler(调度器)负责在工作节点上调度
Kubernetes pod
。部署pod
时,需要指定pod
需求,如 CPU、内存、亲和性、污染或容差、优先级、持久卷(PV)等。调度器的主要任务是根据create
请求,为pod
选择能够满足需求的最佳节点。 -
调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。
调度方式
通常情况下,在Kubernetes集群中,会有多个工作节点。调度程序如何从所有工作节点中选择节点的:
-
kube调度器采用过滤和评分操作选择最佳节点。
-
在过滤阶段,调度器会找到适合调度pod的节点。根据待调度的pod需要的资源要求,筛选出满足资源要求的节点。假设有5节点可用资源满足pod的资源要求,那么这5个节点可以作为备选。如果没有节点能够满足资源要求,那么pod是不可调度的,并被移动到调度队列中。如果是一个大型集群,比如有100个工作节点,调度器不会遍历所有节点。通过调节参数percentageOfNodesToScore可以指定大型集群调度器遍历的节点比例。默认情况percentageOfNodesToScore=50%,调度器会尝试以round-robin的方式迭代50%的节点。如果工作节点分布在多个zone,那么调度器将遍历不同zone中的节点。对于超大型集群,percentageOfNodesToScore的默认值是5%
-
在评分阶段,调度器给过滤后的工作节点打分,并根据分数对节点进行排序。调度程序通过调用多个调度插件进行评分。最后,将选择评分最高的工作节点来调度pod。如果所有节点的评分相同,则随机选择一个节点进行调度。
-
一旦选定了节点,调度器会向api-server发送 “创建pod-node绑定关系” 的事件
关于 Scheduler 其他知识
-
它是一个Controller(控制器),会监听API服务器中的pod创建事件。
-
调度器有两个阶段。调度阶段和绑定阶段。它们合在一起为调度上下文。调度阶段选择一个工作节点,绑定阶段将该更改应用于集群。
-
调度器总是将高优先级pod放在低优先级pod之前进行调度。此外,在某些情况下,当pod在选定节点中开始运行后,pod也有可能会被驱逐或移动到其他节点。如果你想了解更多,请阅读Kubernetes pod优先级指南
-
您可以创建自定义调度器,并在集群中与原生调度器一起运行。部署pod时,可以在pod清单中指定自定义调度器。此时,调度结果将基于自定义调度器的逻辑。
-
调度器采用可插拔式的调度框架。也就是说,您可以将自定义插件添加到调度工作流中。
kube-controller-manager
: 运行控制器进程。从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。
什么是控制器?
控制器是运行无限控制循环的程序。这意味着它会持续运行并观察对象的实际和期望状态。如果实际状态和期望状态存在差异,控制器会进行操作确保 kubernetes
资源/对象 处于期望状态。假设您想要创建一个 Deployment
,您可以在 YAML
中指定它期望的状态,比如,2个副本、1个卷挂载、configmap
等。内置的 controller
将确保 Deployment
始终处于期望的状态。如果用户将副本数更改为 5 个 Controller
将感知这个变化,并保证 Deployment
的副本的个数变成 5
个。
有许多不同类型的控制器。以下是一些内置的 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 作用
-
Kube Controller Manager管理所有的控制器,控制器试图使集群保持在期望的状态。
-
可以使用与自定义资源定义相关联的自定义控制器扩展kubernetes。
什么是 cloud-controller-manager?
-
当在云环境中部署kubernetes时, Cloud Controller Manager(云控制器管理器)充当云平台api和kubernetes集群之间的桥梁。kubernetes核心组件可以独立工作,也允许通过插件方式与云提供商集成。(例如,kubernetes集群和AWS云API之间的接口)
-
cloud-controller-manager 仅运行特定于云平台的控制器。 因此如果你在自己的环境中运行 Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。
-
与 kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的控制回路组合到同一个可执行文件中, 供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。
-
下面的控制器都包含对云平台驱动的依赖:
- 节点控制器(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 中描述的容器处于运行状态且运行状况良好。
kubelet 有什么功能:
-
为pod创建,更新,删除容器
-
负责处理存活(Liveness)、就绪(Readiness)和启动(Startup)探针
-
通过读取pod配置,在主机上为卷挂载创建相应的目录来挂载卷。
-
收集node, pod状态,发送到api server
-
Kubelet也是一个控制器,它监视pod的变化,并利用部署在节点上的 容器运行时 拉取镜像、运行容器等。
-
能够接收来自 API 服务器的 podSpec 之外,还接受来自文件、HTTP端口和 HTTP 服务器的 podSpec。Kubernetes 的静态pod,就是是“从文件中获取podSpec”的一个很好的例子。(静态pod由 kubelet 控制,而不是 API 服务器。)
kubelet 其他知识:
-
Kubelet使用CRI(容器运行时接口)-- gRPC协议,与容器运行时通信。
-
通过暴露http端口提供日志流,并为客户端提供exec会话。
-
通过CSI(容器存储接口container storage interface)-- gRPC协议,配置卷。
-
它使用集群中配置的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代理处理。
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 和容器运行时之间通信的主要协议。
常见的容器运行时
-
containerd:官网推荐的容器运行时,是从docker分离出来的
-
CRI-O:是containerd的一个替代品,专门为ikubernetes创建的一个容器运行时
-
Docker Engine:需要先调用dockershim,然后调用docker,再调用containerd,最后调用底层的 runc
-
Mirantis Container Runtime:是一种商用容器运行时,以前称为 Docker 企业版。
CRI-O 容器运行时与 kubernetes 的交互
-
当 API server 对 pod 发出新的请求时,kubelet 与 CRI-O 守护进程交互,通过 Kubernetes 容器运行时接口启动所需的容器。
-
CRI-O 使用 containers/image 库,根据配置的容器信息,检查并 pull 镜像。
-
CRI-O 为容器生成 OCI 运行时规范(OCI specification ,JSON格式)。
-
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 ""