July 24, 2023
分布式存储 Ceph 介绍
Ceph 是一个分布式存储系统,其广泛用于云平台,最常见的就是在 k8s 平台中,目前大部分云厂商都会选择 ceph 做为基础设施中的后端存储。
Ceph是高度可靠、易于管理和免费的。Ceph 的力量可以改变您公司的IT基础设施和管理大量数据的能力。Ceph提供了非凡的可扩展性——成千上万的客户端访问PB到EB的数据。Ceph节点利用商品硬件和智能守护进程,Ceph存储集群容纳大量节点,这些节点相互通信以动态复制和重新分发数据。
简介 对于一个 Ceph 集群至少需要一个 Ceph Monitor、一个 Ceph Manager 和 一个 Ceph OSDs(其个数决定了对象副本的个数)。
Ceph Metadata Server 是运行 Ceph 文件系统客户端所必需的。
最好的做法是为每个监视器配备一个Ceph管理器,但这不是必须的
Monitors Ceph Monitor ( ceph-mon) 维护集群状态的映射,包括监视器映射、管理器映射、OSD 映射、MDS 映射和 CRUSH 映射。这些映射是 Ceph 守护进程相互协调所需的关键集群状态。监视器还负责管理守护进程和客户端之间的身份验证。
通常至少需要三个Monitors才能实现冗余和高可用性。
Ceph Manager Ceph Manager (ceph-mgr) 负责跟踪运行时指标和 Ceph 集群的当前状态,包括存储利用率、当前性能指标和系统负载。Ceph Manager 守护进程还托管基于python的模块来管理和公开Ceph集群信息,包括基于web的 Ceph Dashboard 和 REST API。
通常至少需要两个 Manager 才能实现高可用性。
Ceph OSDs 一个对象存储守护程序(Ceph-OSD)存储数据,处理数据复制、恢复、再平衡,并通过检查其他 Ceph OSD 守护程序的心跳来向 Ceph Monitors 和 Ceph Manager 提供一些监控信息。
July 18, 2023
kubelet 源码之 Plugin注册机制
上一篇《Kubelet 服务引导流程》我们讲了kubelet的大概引导流程, 本节我们看一下 Plugins 这一块的实现源码。
version: v1.27.3
插件模块入口 入口文件 /pkg/kubelet/kubelet.go中的 NewMainKubelet() 函数,
func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,...) (*Kubelet, error) { ... // 插件管理器 /pkg/kubelet/kubelet.go#L811-L814 klet.pluginManager = pluginmanager.NewPluginManager( klet.getPluginsRegistrationDir(), /* sockDir */ kubeDeps.Recorder, ) ... } 这里第一个参数 klet.getPluginsRegistrationDir() 是返回 plugins 所在目录,默认位于kubelet目录下的 plugins_registry 目录,因此完整的路径为 /var/lib/kubelet/plugins_registry。(这些sock文件是由谁创建的呢?)同时将sock放在子目录里。
const( DefaultKubeletPluginsRegistrationDirName = "plugins_registry" ) func (kl *Kubelet) getPluginsRegistrationDir() string { return filepath.Join(kl.getRootDir(), config.DefaultKubeletPluginsRegistrationDirName) } 第二个参数 kubeDeps.Recorder 是一个事件记录器 EventRecorder ,这里不需要关心。
我们看一下函数 NewPluginManager() 的实现。
// pkg/kubelet/pluginmanager/plugin_manager.go#L54-L80 func NewPluginManager( sockDir string, recorder record.
July 7, 2023
kube-proxy 源码解析
k8s版本:v1.17.3
组件简介 kube-proxy是Kubernetes中的一个核心组件之一,它提供了一个网络代理和负载均衡服务,用于将用户请求路由到集群中的正确服务。
kube-proxy的主要功能包括以下几个方面:
服务代理:kube-proxy会监听Kubernetes API服务器上的服务和端口,并将请求转发到相应的后端Pod。它通过在节点上创建iptables规则或使用IPVS(IP Virtual Server)进行负载均衡,以保证请求的正确路由。 负载均衡:当多个Pod实例对外提供相同的服务时,kube-proxy可以根据负载均衡算法将请求分发到这些实例之间,以达到负载均衡的目的。它可以基于轮询、随机、源IP哈希等算法进行负载均衡。 故障转移:如果某个Pod实例不可用,kube-proxy会检测到并将其自动从负载均衡轮询中移除,从而保证用户请求不会被转发到不可用的实例上。 会话保持(Session Affinity):kube-proxy可以通过设置会话粘性(Session Affinity)来将同一客户端的请求转发到同一Pod实例,从而保持会话状态的一致性。 网络代理:kube-proxy还可以实现网络地址转换(NAT)和访问控制列表(ACL)等网络代理功能,通过为集群内的服务提供统一的入口地址和访问策略。 总之 kube-proxy 在Kubernetes集群中扮演着路由和负载均衡的重要角色,为集群内的服务提供可靠的网络连接和请求转发功能。
实现逻辑 组件入口文件为 [cmd/kube-proxy/proxy.go](https://github.com/kubernetes/kubernetes/blob/v1.27.3/cmd/kube-proxy/proxy.go)。
这里我们先介绍一下 options 这个数据结构,它主要有来存储一些配置项
type Options struct { // 配置文件路径 ConfigFile string // 将配置写入到文件 WriteConfigTo string // bool值,如果为true,则删除所有iptables/ipvs 规则,然后退出程序 CleanupAndExit bool // WindowsService should be set to true if kube-proxy is running as a service on Windows. // Its corresponding flag only gets registered in Windows builds WindowsService bool // KubeProxy configuration配置 config *kubeproxyconfig.
June 21, 2023
Kubelet 服务引导流程
版本:v1.17.3
入口文件: /cmd/kubelet/kubelet.go
本文主要是为了通过阅读kubelet启动流程源码,实现对整个kubelet 组件及其服务有所了解,因此许多相关组件服务的运行机制并没有详细介绍,如果有时间的话,可以针对每个组件服务进行详细介绍。
在k8s中 kubelet 是一个极其重要的组件之一,也是 Kubernetes 里面第二个不可被替代的组件(第一个不可被替代的组件当然是 kube-apiserver)。也就是说,无论如何,都不太建议你对 kubelet 的代码进行大量的改动。保持 kubelet 跟上游基本一致的重要性,就跟保持 kube-apiserver 跟上游一致是一个道理。
kubelet 本身,也是按照“控制器”模式来工作的。它实际的工作原理,可以用如下所示的一幅示意图来表示清楚。
可以看到,kubelet 的工作核心,就是一个控制循环,即:SyncLoop(图中的大圆圈)。而驱动这个控制循环运行的事件,包括四种:
Pod 更新事件; Pod 生命周期变化; kubelet 本身设置的执行周期; 定时的清理事件。 所以,跟其他控制器类似,kubelet 启动的时候,要做的第一件事情,就是设置 Listers,也就是注册它所关心的各种事件的 Informer。这些 Informer 就是 SyncLoop 需要处理的数据的来源。此外,kubelet 还负责维护着很多很多其他的子控制循环(也就是图中的小圆圈)。这些控制循环的名字,一般被称作某某 Manager,比如 Volume Manager、Image Manager、Node Status Manager 等等。
简单理解就是先通过建立各类 Informer 来建立与 APIServer 的通讯,这样当资源发生变化时,立刻就能感知到,做出相应的处理。
下面我们就从源码来看一下它的实现过程。在 kubelet 中有两个重要的数据结构,一个是 kubeletServer ,另一个是 kubeletDeps 。
配置项 kubeletServer kubeltServer 封装了启动 kubelet 所需的所有参数,这些可以通过命令行设置,也可以直接设置。
type KubeletServer struct { KubeletFlags kubeletconfig.KubeletConfiguration } 它内嵌了两个数据结构,分别为 KubeletFlags 和 KubeletConfiguration 。其中 kubeletFlags 主要是用来接收执行命令时手动指定的参数,而 KubeletConfiguration 则是从配置文件里读取配置信息,其 API 介绍参考 。
June 11, 2023
创建Pod源码解析
在上一篇《Kubelet 服务引导流程》中我们介绍了 kubelet 服务启动的大致流程,其中提到过对 Pod 的管理,这一节将详细介绍一下对Pod的相关操作,如创建、修改、删除等操作。建议先了解一下上节介绍的内容。
在 kubelet 启动的时候,会通过三种 pod source 方式来获取 pod 信息:
file: 这种方式只要针对 staticPod 来处理,定时观察配置文件是否发生变更情况来写入 pod http方式: 就是通过一个http请求一个 URL 地址,用来获取 simple Pod 信息 clientSet: 这种方式直接与 APIServer 通讯,对 pod 进行watch 上面这三种 pod source ,一旦有pod 的变更信息,将直接写入一个 kubetypes.PodUpdate 这个 channel(参考: https://github.com/kubernetes/kubernetes/blob/v1.27.3/pkg/kubelet/kubelet.go#L278-L313),然后由下面我们要讲的内容进行读取消费。
对于pod 的操作除了这一个地方可以实现对 pod 的操作,还有l四个地方也可以触发对 pod 的操作。
在启动服务函数 Kubelet.Run(updates <-chan kubetypes.PodUpdate{}) 中参数 updates是一个 kubetypes.PodUpdate的类型,其结构如下
type PodUpdate struct { Pods []*v1.Pod Op PodOperation Source string } // PodOperation 定义了将对pod配置进行哪些更改。 type PodOperation int // These constants identify the PodOperations that can be made on a pod configuration.
June 11, 2023
k8s调度器 kube-scheduler 源码解析
版本号:v1.27.2
Kubernetes 调度程序作为一个进程与其他主组件(例如 API 服务器)一起运行。它与 API 服务器的接口是监视具有空 PodSpec.NodeName 的 Pod,并且对于每个 Pod,它都会发布一个 Binding,指示应将 Pod 调度到哪里。
调度过程 +-------+ +---------------+ node 1| | +-------+ | +----> | Apply pred. filters | | | | +-------+ | +----+---------->+node 2 | | | +--+----+ | watch | | | | | +------+ | +---------------------->+node 3| +--+---------------+ | +--+---+ | Pods in apiserver| | | +------------------+ | | | | | | +------------V------v--------+ | Priority function | +-------------+--------------+ | | node 1: p=2 | node 2: p=5 v select max{node priority} = node 2 有关调度算法见: https://github.
May 21, 2023
树莓派安装 kubernetes v1.27.2
Ubuntu 22.04.2 LTS ARM64位系统 kubernetes v1.27.2
以前写过一篇安装教程 https://blog.haohtml.com/archives/30924 ,当时安装的版本是 < v1.24.0 版本,由于k8s 从 v1.24.0 版本开始,弃用了 Dockershim 因此没有办法继续使用 Docker Engine 作为运行时,因此如果还想继续使用旧的运行时的话,则需要安装一个 cri-docker 的软件, 本文主要是介绍(版本 >=v1.24.0 )继续使用 Docker Engine 的安装方法,这里以最新版本 v1.27.1 为例。
安装环境初始化 以下内容来自: https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/
执行下述指令:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # 设置所需的 sysctl 参数,参数在重新启动后保持不变 cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # 应用 sysctl 参数而不重新启动 sudo sysctl --system 通过运行以下指令确认 br_netfilter 和 overlay 模块被加载:
April 25, 2023
istio之pilot-agent 源码分析
源码版本:istio-v1.11.3
为了方便理解,本文会介绍到 vm 和 容器 两种部署形式的情况,一般会在讲解时提到,因此需要注意当前的部署方式,不过他们的架构是完全一样的。
架构 pilot 共分两个主要模块,一个是 pilot-agent 用来提供 pod 中的服务发现 客户端,另一个是 polot-discovery 提供服务发现 服务端。
其中 envoy 和 Istio Agent 就是我们上面所讲的 pilot-agent 模块,其为 数据面 组件,而 Istiod 则为 控制面,模块对应源码见
pilot-agent 对于 polot-agent 它运行在每个pod中 ,并以 sidecar 方式与应用容器运行在同一个pod。如果你使用的是 vm 的话,则可以在当前主机通过 pstree 命令看到进程视图
# pstree -pu 24530 su(24530)───pilot-agent(24611,istio-proxy)─┬─envoy(24619)─┬─{envoy}(24620) │ ├─{envoy}(24621) │ ├─{envoy}(24622) │ ├─{envoy}(24623) │ ├─{envoy}(24624) │ ├─{envoy}(24625) │ ├─{envoy}(24627) │ ├─{envoy}(24628) │ ├─{envoy}(24629) │ ├─{envoy}(24630) │ └─{envoy}(24635) ├─{pilot-agent}(24612) ├─{pilot-agent}(24613) ├─{pilot-agent}(24614) ├─{pilot-agent}(24615) ├─{pilot-agent}(24616) ├─{pilot-agent}(24617) ├─{pilot-agent}(24618) ├─{pilot-agent}(24626) └─{pilot-agent}(24698) 从进程关系可以看到,envoy 属于 pilot-agent 的一个子进程,当前进程以 istio-proxy 用户身份运行。
April 4, 2023
GBP工作原理
https://zhuanlan.zhihu.com/p/305982159 https://www.cnblogs.com/wushuai2018/p/16450239.html
February 15, 2023
kubernetes 之 client-go 之 informer 工作原理源码解析
本方主要介绍有关 client go 架构实现原理,其中一个十分重要的组件就是 informer,它也是我们本文的重点,
Informer 机制 采用 k8s HTTP API 可以查询集群中所有的资源对象并 Watch 其变化,但大量的 HTTP 调用会对 API Server 造成较大的负荷,而且网络调用可能存在较大的延迟。除此之外,开发者还需要在程序中处理资源的缓存,HTTP 链接出问题后的重连等。为了解决这些问题并简化 Controller 的开发工作,K8s 在 client go 中提供了一个 informer 客户端库,可以视其为一个组件。
在 Kubernetes 中,Informer 可以用于监视 Kubernetes API 服务器中的资源并将它们的当前状态缓存到本地(index -> store) ,这样就避免了客户端不断地向 API 服务器发送请求,直接从本地即可。
相比直接采用 HTTP Watch,使用 Kubernetes Informer 有以下优势:
减少 API 服务器的负载:通过在本地缓存资源信息,Informer 减少了需要向 API 服务器发出的请求数量。这可以防止由于 API 服务器过载而影响整个集群的性能。 提高应用程序性能:使用缓存的数据,客户端应用程序可以快速访问资源信息,而无需等待 API 服务器响应。这可以提高应用程序性能并减少延迟。 简化代码:Informer 提供了一种更简单、更流畅的方式来监视 Kubernetes 中的资源更改。客户端应用程序可以使用现有的 Informer 库来处理这些任务,而无需编写复杂的代码来管理与 API 服务器的连接并处理更新。 更高的可靠性:由于 Informer 在本地缓存数据,因此即使 API 服务器不可用或存在问题,它们也可以继续工作。这可以确保客户端应用程序即使在底层 Kubernetes 基础结构出现问题时也能保持功能。 下面一起看一下 client-go 库的实现原理