深入informer

Informer介绍 client-go中提供的informer主要用来监听k8s资源的创建、删除、更新操作,通过事件回调交给controller进一步处理。 informer整体机制如下图: (from client-go under the hood) 上半部分是由client-go实现的,而下半部分黄色图标需要开发者自行实现逻辑,在使用kubebuilder进行controller开发时,框架会自动实现这部分,开发者只需专注Reconcile逻辑。 Reflector:用于Watch指定的kubernetes资源,当资源发生变化时,比如Added、Modified、Deleted调用DeltaFIFO将资源对象与DeltaType存储起来。 DeltaFIFO: 先进先出队列,用于存储资源变化类型及对应资源对象,DeltaType有Added、Updated、Deleted、Sync等;其Pop方法会将队列中的资源对象取出并调用informer注册的函数进行处理。 Indexer:kubernetes资源对象缓存,可以直接从本地缓存读取对象,减少对apiserver的访问;在DeltaFIFO Pop的处理中,将对象资源进行存储、更新、删除。 深入Informer 让我们从NewSharedIndexInformer一起看一下informer的具体实现,Shared Infomer对同一种资源共用一个Reflector,从而减少apiserver负载。 1 新建Informer NewSharedIndexInformer初始化sharedIndexInformer,主要包括注册、处理分发回调事件的processor、新建Indexer、listerWatcher接口实现。 func NewSharedIndexInformer(lw ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration, indexers Indexers) SharedIndexInformer { realClock := &clock.RealClock{} sharedIndexInformer := &sharedIndexInformer{ // 注册、处理回调函数 processor: &sharedProcessor{clock: realClock}, // 创建indexer indexer: NewIndexer(DeletionHandlingMetaNamespaceKeyFunc, indexers), // 实现具体的listwatch接口 listerWatcher: lw, // 资源对象 objectType: exampleObject, resyncCheckPeriod: defaultEventHandlerResyncPeriod, defaultEventHandlerResyncPeriod: defaultEventHandlerResyncPeriod, cacheMutationDetector: NewCacheMutationDetector(fmt.Sprintf("%T", exampleObject)), clock: realClock, } return sharedIndexInformer } 看一下Indexer的具体实现,简单来说是使用 map + sync.

阅读全文

kube-scheduler源码解析

kube-scheduler设计 scheduler作为k8s的核心组件之一,其功能为每个Pod选择一个合适的node,其流程分为3步,首先获得未调度podList,然后通过一系列调度算法为Pod选择合适的node,将数据发送到apiserver。调度算法主要包含两部分predicates(预选) 和 priorities(优选),最后将评分最高的node更新到Pod For given pod: +---------------------------------------------+ | Schedulable nodes: | | | | +--------+ +--------+ +--------+ | | | node 1 | | node 2 | | node 3 | | | +--------+ +--------+ +--------+ | | | +-------------------+-------------------------+ | | v +-------------------+-------------------------+ Pred. filters: node 3 doesn't have enough resource +-------------------+-------------------------+ | | v +-------------------+-------------------------+ | remaining nodes: | | +--------+ +--------+ | | | node 1 | | node 2 | | | +--------+ +--------+ | | | +-------------------+-------------------------+ | | v +-------------------+-------------------------+ Priority function: node 1: p=2 node 2: p=5 +-------------------+-------------------------+ | | v select max{node priority} = node 2 scheduler支持的两种扩展方式

阅读全文

kubelet源码解析之PLEG

kubelet源码分析之PLEG PLEG介绍 Pleg(Pod Lifecycle Event Generator) 是kubelet 的核心模块,PLEG周期性调用container runtime获取本节点containers/sandboxes的信息(像docker ps),并与自身维护的podRecords信息进行对比,生成对应的 PodLifecycleEvent并发送到plegCh中,在kubelet syncLoop中对plegCh进行消费处理,最终达到用户的期望状态 在之前的kubelet版本中由每个pod的podWorker的goroutine来查询runtime进行对比,当pod数量逐渐增大时,大量周期性的查询导致高cpu使用率、低性能、难以扩展等问题,为了改进以上问题,引入了PLEG 创建 在/pkg/kubelet/kubelet.go:660 在函数KubeletNewMainKubelet中伴随Kubelet结构体创建 // 传入runtime、chan缓冲大小、定时周期、podCache创建pleg klet.pleg = pleg.NewGenericPLEG(klet.containerRuntime, plegChannelCapacity, plegRelistPeriod, klet.podCache, clock.RealClock{}) pkg/kubelet/pleg/generic.go:109 工厂函数NewGenericPLEG创建返回接口类型PodLifecycleEventGenerator // NewGenericPLEG instantiates a new GenericPLEG object and return it. func NewGenericPLEG(runtime kubecontainer.Runtime, channelCapacity int, relistPeriod time.Duration, cache kubecontainer.Cache, clock clock.Clock) PodLifecycleEventGenerator { return &GenericPLEG{ // 定时relist周期 relistPeriod: relistPeriod, // KubeGenericRuntimeManager runtime: runtime, // 与kubelet通信带缓冲chan eventChannel: make(chan *PodLifecycleEvent, channelCapacity), podRecords: make(podRecords), // podCache cache: cache, clock: clock, } } // podRecords定义 type podRecord struct { // 历史pod old *kubecontainer.

阅读全文

kubeGenericRuntimeManager kubeGenericRuntimeManager为kubelet提供Runtime接口, 管理pods与containers生命周期, 调用remote runtime api完成操作;Kubelet与CRI交互如下图 SyncPod 接上文Pod处理走到调用kubeGenericRuntimeManager.SyncPod pkg/kubelet/kuberuntime/kuberuntime_manager.go:661 func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult) { // 获得sandbox、container changes podContainerChanges := m.computePodActions(pod, podStatus) ...... // kill pod if podContainerChanges.KillPod { ....... // 先停止pod中所有conatiners,执行preStop,再停止sandbox killResult := m.killPodWithSyncResult(pod, kubecontainer.ConvertPodStatusToRunningPod(m.runtimeName, podStatus), nil) result.AddPodSyncResult(killResult) if killResult.Error() != nil { klog.Errorf("killPodWithSyncResult failed: %v", killResult.Error()) return } // 如果新建sandbox则清楚init containers if podContainerChanges.CreateSandbox { m.purgeInitContainers(pod, podStatus) } } else { // kill掉列表中所有containers,主要是处于未知状态的containers for containerID, containerInfo := range podContainerChanges.

阅读全文

kubelet介绍 在k8s集群中的每个节点上都运行着一个kubelet服务进程,其主要负责向apiserver注册节点、管理pod及pod中的容器,并通过 cAdvisor 监控节点和容器的资源。 节点管理:节点注册、节点状态更新(定期心跳) pod管理:接受来自apiserver、file、http等PodSpec,并确保这些 PodSpec 中描述的容器处于运行状态且运行状况良好 容器健康检查:通过ReadinessProbe、LivenessProbe两种探针检查容器健康状态 资源监控:通过 cAdvisor 获取其所在节点及容器的监控数据 kubelet组件模块 kubelet组件模块如上图所示,下面先对几个比较重要的几个模块进行简单说明: Pleg(Pod Lifecycle Event Generator) 是kubelet 的核心模块,PLEG周期性调用container runtime获取本节点containers/sandboxes的信息(像docker ps),并与自身维护的pods cache信息进行对比,生成对应的 PodLifecycleEvent并发送到plegCh中,在kubelet syncLoop中对plegCh进行消费处理,最终达到用户的期望状态,相关设计可以看这里 podManager提供存储、访问Pod信息的接口,维护static pod和mirror pod的映射关系 containerManager 管理容器的各种资源,比如 CGroups、QoS、cpuset、device 等 KubeletGenericRuntimeManager是容器运行时的管理者,负责于 CRI 交互,完成容器和镜像的管理;关于client/server container runtime 设计可以看这里 statusManager负责维护pod状态信息并负责同步到apiserver probeManager负责探测pod状态,依赖statusManager、statusManager、livenessManager、startupManager cAdvisor是google开源的容器监控工具,集成在kubelet中,收集节点与容器的监控信息,对外提供查询接口 volumeManager 管理容器的存储卷,比如格式化资盘、挂载到 Node 本地、最后再将挂载路径传给容器 深入kubelet工作原理 从上图可以看出kubelet的主要工作逻辑在SyncLoop控制循环中,处理pod更新事件、pod生命周期变化、周期sync事件、定时清理事件;SyncLoop旁还有处理其他逻辑的控制循环,例如处理pod状态同步的statusManager,处理健康检查的probeManager等。 下面将从kubelet源码来分析各个环节的处理逻辑。 kubelet代码(版本1.19)主要位于cmd/kubelet与pkg/kubelet下,首先看下kubelet启动流程与初始化 1 cmd/kubelet/kubelet.go:34 func main() { rand.Seed(time.Now().UnixNano()) command := app.NewKubeletCommand() logs.InitLogs() defer logs.FlushLogs() if err := command.Execute(); err !

阅读全文

k8s conformance test问题记录

K8S conformance test问题记录 K8S conformance test步骤与提交可以参考这里, 本文主要记录相关问题 私有云环境测试镜像准备 在隔离的私有云环境跑测试,需要将K8S conformance test需要的镜像提前准备好并存储到私有镜像仓库中 1. 获取所有测试镜像 sonobuoy images --kubernetes-version v1.19.3 > images #我这里是v1.19.3版本k8s,可以替换 2. 在非离线环境中下载镜像包 for i in `cat images`; do docker pull $i ;done docker save `cat image | tr "\n" " "` -o images.tar 3. 在离线环境加载镜像包 docker load -i images.tar 4. 生成e2e repo配置,并将所有配置都替换为私有镜像仓库地址 sonobuoy gen default-image-config > repo.yaml 5. push镜像 sonobuoy images push --e2e-repo-config repo.yaml 使用私有镜像仓库测试 开始测试 registry_url=xx sonobuoy run --mode=certified-conformance --sonobuoy-image $registry_url/sonobuoy:v0.

阅读全文

k8s 1.17.5高可用部署

k8s 1.17.5高可用部署 环境准备 K8S版本: 1.17.5 IP 操作系统 主机配置 备注 192.168.0.2 debian9.5 4核8G control plane(apiserver/scheduler/controller/etcd) 192.168.0.3 debian9.5 4核8G control plane(apiserver/scheduler/controller/etcd) 192.168.0.4 debian9.5 4核8G control plane(apiserver/scheduler/controller/etcd) 192.168.0.5 debian9.5 4核8G node 192.168.0.6 debian9.5 4核8G node 192.168.0.7 debian9.5 4核8G node 59.111.230.7 LB X 负载均衡, 后端为控制节点(可换为keepalived VIP) 机器初始化(所有节点操作) 使用aliyun debian源 部署docker 18.

阅读全文

作者的图片

沉下心,多坚持

SRE

杭州