kubernetes基础组件原理

kubelet 的工作核心,就是一个控制循环SyncLoop,驱动这个控制循环运行的事件,包括四种:

1.Pod 更新事件

2.Pod 生命周期变化

3.kubelet 本身设置的执行周期

4.定时的清理事件

kubelet 还负责维护着很多其他的子控制循环,比如 Volume Manager、Image Manager、Node Status Manager 等等,这些控制循环的责任,就是通过控制器模式,完成 kubelet 的某项具体职责。

例如:Node Status Manager,就负责响应 Node 的状态变化,然后将 Node 的状态收集起来,并通过 Heartbeat 的方式上报给 APIServer。CPU Manager,就负责维护该 Node 的 CPU 核的信息,以便在 Pod 通过 cpuset 的方式请求 CPU 核的时候,能够正确地管理 CPU 核的使用量和可用量。

kubelet 通过 Watch 机制,监听了与自己相关的 Pod 对象的变化:

这个 Watch 的过滤条件是该 Pod 的 nodeName 字段与自己相同,kubelet 会把这些 Pod 的信息缓存在自己的内存里。

当一个 Pod 完成调度、与一个 Node 绑定起来之后, 这个 Pod 的变化就会触发 kubelet 在控制循环里注册的 Handler,也就是上图中的 HandlePods 部分。

通过检查该 Pod 在 kubelet 内存里的状态,kubelet 就能够判断出这是一个新调度过来的 Pod,从而触发 Handler 里 ADD 事件对应的处理逻辑。(备注:在具体的处理过程当中,kubelet 会启动一个名叫 Pod Update Worker 的、单独的 Goroutine 来完成对 Pod 的处理工作。)

CRI是Container Runtime Interface(容器运行时接口)的简写,CRI解耦了kubelet与容器运行时,让kubelet无需重新编译就可以支持多种容器运行时,kubelet将通过CRI接口来跟第三方容器运行时进行通信,来操作容器与镜像。实现了 CRI 接口的容器运行时通常称为 CRI shim, 这是一个 gRPC Server,监听在本地的 unix socket  上;而 kubelet 作为 gRPC 的客户端来调用 CRI 接口,来进行Pod  和容器、镜像的生命周期管理。另外,容器运行时需要自己负责管理容器的网络,推荐使用 CNI。

CAdvisor

集成在 Kubelet 中的容器监控工具,用于收集本节点和容器的监控信息。

oomWatcher

kubelet的oomwatcher从cadvisor监听事件,如果出现了system oom则记录一个event事件。 对于容器的oom状态,k8s使用docker的状态State.OOMKilled判断是否经历oom事件。

GCManager

垃圾回收是 kubelet 的一个有用功能,它将清理未使用的镜像容器。 Kubelet 将每分钟对容器执行一次垃圾回收,每五分钟对镜像执行一次垃圾回收。

不建议使用外部垃圾收集工具,因为这些工具可能会删除原本期望存在的容器进而破坏 kubelet 的行为。

CPUManager

默认情况下,kubelet 使用CFS配额来执行 Pod 的 CPU 约束。 当节点上运行了很多 CPU 密集的 Pod 时,工作负载可能会迁移到不同的 CPU 核, 这取决于调度时 Pod 是否被扼制,以及哪些 CPU 核是可用的。 许多工作负载对这种迁移不敏感,因此无需任何干预即可正常工作。

ProberManager

ProberManager 实现对容器的健康检查。目前有三种 probe 探针:

liveness: 让Kubernetes知道你的应用程序是否健康,如果你的应用程序不健康,Kubernetes将删除Pod并启动一个新的替换它(与RestartPolicy有关)。Liveness 探测可以告诉 Kubernetes 什么时候通过重启容器实现自愈。

readiness: readiness与liveness原理相同,不过Readiness探针是告诉 Kubernetes 什么时候可以将容器加入到 Service 负载均衡中,对外提供服务。

startupProbe:1.16开始支持的新特性,检测慢启动容器的状态。

Kubelet 定期调用容器中的探针来诊断容器的健康状况。 包含如下三种实现方式:

ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为 0,则表明容器健康;

TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检查,如果端口能被访问,则表明容器健康;

HTTPGetAction:通过容器的 IP 地址和端口号及路径调用 HTTP GET 方法,如果响应的状态码大于等于 200 且小于 400,则认为容器状态健康。

StatusManager

StatusManager 的主要功能是将 pod 状态信息同步到 apiserver,statusManage 并不会主动监控 pod 的状态,而是提供接口供其他 manager 进行调用。比如 probeManager。probeManager 会定时去监控 pod 中容器的健康状况,一旦发现状态发生变化,就调用 statusManager 提供的方法更新 pod 的状态。

EvictionManager

EvictionManager 会监控资源的使用情况,并使用驱逐机制防止计算和存储资源耗尽。

VolumeManager

volumeManager通过actualStateOfWorld和desiredStateOfWorld来表明当前的volume挂载状态和期望的volume挂载状态。然后由desiredStateOfWorldPopulator维护desireedStateOfWorld和podManager的一致性;由reconcile维护actualStateOfWorld和desiredStateOfWorld的一致性及磁盘volume挂载和actualStateOfWorld的一致性。通过这些机制,volumeManager完成了volume挂载生命周期的管理。

PluginManager

PluginManager 可以用将系统硬件资源发布到kubelet。

podworker,其功能就是处理当前节点被调度pod的声明周期的,也就是说你建了一个pod,然后调度器将这个pod调度到某个节点上面了,那么kubelet就需要去工作了,它的工作就是启动这个pod,用容器运行时去启动,也就是将进程拉起来,放到某个namespace下面去,通过cgroup对资源做限制,通过网络插件将网络配置好。

kubectl

常用命令格式

创建:kubectl run <name> --image=<image> 或者 kubectl create -f manifest.yaml

查询:kubectl get <resource>

更新 kubectl set 或者 kubectl patch

删除:kubectl delete <resource> <name> 或者 kubectl delete -f manifest.yaml

查询 Pod IP:kubectl get pod <pod-name> -o jsonpath='{.status.podIP}'

容器内执行命令:kubectl exec -ti <pod-name> sh

容器日志:kubectl logs [-f] <pod-name>

导出服务:kubectl expose deploy <name> --port=80

自定义输出列

比如,查询所有 Pod 的资源请求和限制:

Kubectl get pods --all-namespaces -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,"CPU(requests)":.spec.containers[*].resources.requests.cpu,"CPU(limits)":.spec.containers[*].resources.limits.cpu,"MEMORY(requests)":.spec.containers[*].resources.requests.memory,"MEMORY(limits)":.spec.containers[*].resources.limits.memory

日志查看

# Return snapshot logs from pod nginx with only one container

kubectl logs nginx

# Return snapshot of previous terminated ruby container logs from pod web-1

kubectl logs -p -c ruby web-1

# Begin streaming the logs of the ruby container in pod web-1

kubectl logs -f -c ruby web-1

连接到一个正在运行的容器

kubectl attach 123456-7890 -c ruby-container -i -t

在容器内部执行命令

# Get output from running 'date' from pod 123456-7890, using the first container by default

  kubectl exec 123456-7890 date

  # Get output from running 'date' in ruby-container from pod 123456-7890

  kubectl exec 123456-7890 -c ruby-container date

  # Switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod 123456-7890

  # and sends stdout/stderr from 'bash' back to the client

  kubectl exec 123456-7890 -c ruby-container -i -t -- bash -il

Options:

  -c, --container='': Container name. If omitted, the first container in the pod will be chosen

  -p, --pod='': Pod name

  -i, --stdin=false: Pass stdin to the container

  -t, --tty=false: Stdin is a TT

端口转发

kubectl patch

kubectl get pv,pvc -o wide

kubectl get pod,svc,ingress

Kubernetes Service  定义了这样一种抽象:一个  Pod  的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组  Pod  能够被  Service  访问到,通常是通过  Label Selector

Service 在 K8s 中有以下四种类型

1.ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP

2.NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 : NodePort 来访问该服务

3.LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort

4.ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持

apiVersion: v1

kind: Service

metadata:

  name: my-service

spec:

  selector:

    app: MyApp

  ports:

    - protocol: TCP

      port: 80

      targetPort: 9376

上述配置创建一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 "app=MyApp" 的 Pod 上。 Kubernetes 为该服务分配一个 IP 地址(有时称为 “集群IP” ),该 IP 地址由服务代理使用。

endpoint

Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。

    一个service由一组pod组成,这些pod通过Endpoint暴露出来,Endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。

kube-proxy 目前支持三种工作模式:userspace、iptables、ipvs

userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的pod并和其建立链接,以将请求转发到Pod上。

该模式下,kube-proxy充当了一个四层负责均衡器的角色,由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。

iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。

 该模式下,kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。

pvs模式和iptables模式类似,kube-proxy监控Pod的变化并创建相应的ipvs规则,ipvs相对iptables转发效率更高。除此之外,ipvs支持更多的LB算法。

Kubernetes Controller内拥有许多的控制器类型,用来控制pod的状态、行为、副本数量等等,控制器通过Pod的标签来控制Pod ,从而实现对应用的运维,如伸缩、升级等。

常用的控制器类型如下:

ReplicationController 、ReplicaSet、Deployment:无状态服务,保证在任意时间运行Pod指定的副本数量,能够保证Pod总是可用的,支持滚动更新、回滚。典型用法:web服务。

DaemonSet:确保集群内全部(或部分)node节点上都分配一个pod,如果新加node节点,也会自动再分配对应的pod。典型用法:filebeat日志收集、prometheus资源监控。

StatefulSet:有状态服务,如各种数据存储系统。StatefullSet内的服务有着稳定的持久化存储和网络标识,有序部署,有序伸缩。

Job:只运行一次的作业。

CronJob:周期性运行的作业。典型用法:数据库定时备份。

Horizontal Pod Autoscaling(HPA):按照期望的pod的cpu或内存来自动伸缩pod数量。

Pod是通过Controller实现应用的运维,比如弹性伸缩,滚动升级等

Pod 和 Controller之间是通过label标签来建立关系,同时Controller又被称为控制器工作负载

SchedulerKubernetes 的调度器,属于核心组件,主要的任务是把定义的 Pod 分配到集群的节点上,听起来非常简单,但是有很多要考虑的问题:

公平:如果保证每个节点都能被分配资源

资源高效利用: 集群所有资源最大化被使用

效率:调度的性能更好,能够尽快地对大批量的 Pod 完成调度工作

灵活:允许用户根据自己的需求控制调度的逻辑

Scheduler 提供的调度流程分为预选 (Predicates) 和优选 (Priorities) 两个步骤:

预选,K8S会遍历当前集群中的所有 Node,筛选出其中符合要求的 Node 作为候选

优选,K8S将对候选的 Node 进行打分

第一阶段:预选

预选的作用,是找到满足条件的节点,如具有SSD硬盘,系统内存大于某个值,去掉不满足条件的节点。以下是几个比较重要的策略:

防止过度提交

反亲和

亲和

污染和容忍

第二阶段:优选

预选可能找到多个满足条件的node, 优选阶段将按照一些规则对其进行打分并汇总,打分高者最后会被选中。以下是几个优选的策略:

节点漫延

反亲和

亲和

打分后线性相加,得到最后的总分,分高的node将会被选中。

现在再来看 Kubernetes 从一开始就提供的东西:描述各种资源需求的标准 API。例如,

描述 pod、container 等计算需求 的 API;

描述 service、ingress 等虚拟网络功能 的 API;

描述 volumes 之类的持久存储 的 API;

甚至还包括 service account 之类的服务身份 的 API 等等。

用户创建一个资源分两个步骤:

第一步是将对应请求发送给apiserver,通过apiserver把对应资源定义的信息存放在etcd中;第二个步骤是对应资源类型的控制器通过apiserver从etcd中读取对应资源的定义,将其创建出来

k8s上,资源的类型有很多,比如pod,service,PersistentVolume,PersistentVolumeClaim等等,这些都是一些基础的资源类型

k8s上扩展资源类型的方式有三种

第一种是crd,crd是k8s内建的资源类型,该类型资源主要用来创建用户自定义资源类型的资源;即通过crd资源,可以将用户自定义资源类型转换为k8s上资源类型;

第二种是自定义apiserver;这种方式要比第一种方式要复杂一点,需要用户手动开发程序实现对应功能的apiserver,让其用户创建自定义类型资源能够通过自定义apiserver实现;

第三种方式就是修改现有k8sapiserver,让其支持对应用户自定义资源类型

自定义控制器

  自定义资源类型我们可以使用crd资源实现,也可以使用自定义apiserver或修改原有apiserver代码实现

自定义控制器也是同样的逻辑,使用自定义控制器的目的也是让对应自定义类型资源能够被自定义控制器监听,一旦对应资源发生变动,它能够将其在k8s上创建出来,并一直保持和用户期望的状态吻合;自定义控制器和自定义资源类型可以分开实现,也可以合并在一起实现,即自定义控制器程序能够自动创建crd资源,让其对应自定义类型资源能够被k8s识别并将其创建出来;具体是分开实现还是合并在一起实现,取决开发自定义控制器程序员

crd资源是k8s上的标准资源之一,它的定义主要有apiVersion,kind,metadata,spec和status;其中kind类型为CustomResourceDefinition,apiVersion是apiextensions.k8s.io/v1;这两个是固定格式;spec字段是用来定义对应指定资源类型资源的相关属性

CRD:用来声明用户的自定义资源,例如它是 namespace-scope 还是 cluster-scope 的资源、有哪些字段等等,K8s 会自动根据这个定义生成相应的 API;

CRD 是资源类型定义,具体的资源叫 CR。

Operator 框架:“operator” 在这里的字面意思是“承担运维任务的程序”, 它们的基本逻辑都是一样的:时刻盯着资源状态,一有变化马上作出反应(也就是 reconcile 逻辑)。

控制器的目的是让 CRD 定义的资源达到我们预期的一个状态,要达到我们定义的状态,我们需要监听触发事件。触发事件的概念是从硬件信号产生 中断 的机制衍生过来的,

其产生一个电平信号时,有水平触发(包括高电平、低电平),也有边缘触发(包括上升沿、下降沿触发等)。

水平触发 : 系统仅依赖于当前状态。即使系统错过了某个事件(可能因为故障挂掉了),当它恢复时,依然可以通过查看信号的当前状态来做出正确的响应。

边缘触发 : 系统不仅依赖于当前状态,还依赖于过去的状态。如果系统错过了某个事件(“边缘”),则必须重新查看该事件才能恢复系统。

Kubernetes 的 API 和控制器都是基于水平触发的,可以促进系统的自我修复和周期调协。

其 API 实现方式(也是我们常说的声明式 API)是:控制器监视资源对象的实际状态,并与对象期望的状态进行对比,然后调整实际状态,使之与期望状态相匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值