September 22, 2023
envoy中 lua filter 与 wasm filter使用教程
在 Envoy 中当我们需要对 http_connection_manager 中的请求进行修改时,如添加或删除一个请求header,一般通过 HTTP Filter 过滤器来实现。
而在Envoy 包含的几十个Filter中,通常会选择 Lua Filter (extensions.filters.http.lua.v3.Lua) 或 Wasm Filter (extensions.filters.http.wasm.v3.Wasm)这两类过滤器。
Lua Filter 与 Wasm Filter 下表是 Lua Filter 与 HTTP Filter 的对比
Lua Filter Wasm Filter 编程语言 Lua,解释型脚本语言 WebAssembly,编译型语言 运行环境 Envoy 内置的 Lua 虚拟机 Envoy 内嵌的 WebAssembly 虚拟机 生态系统 丰富的 Lua 库可供使用 逐渐形成的 WebAssembly 生态系统 性能 较低 较高 安全性 较弱 较强 可移植性 受宿主环境和依赖库限制 平台无关的二进制格式,可在不同环境中运行 在不同的环境中Lua 的行为和功能可能略有差异,特别是在与底层操作系统和硬件交互的方面,而 Wasm 则没有这个问题。
但对于选择哪类 Filter 扩展 Envoy 的过滤器逻辑时,需要根据你的需求和对编程语言的熟悉程度。
September 17, 2023
WebAssembly开发入门教程
wasm简介 WebAssembly(Wasm)是一种通用字节码技术,它可以将其他编程语言(如 Go、Rust、C/C++ 等)的程序代码编译为可在浏览器或服务端环境直接执行的字节码程序。
使用场景 主要有两个使用场景,分别为 浏览器 和 服务端。
浏览器 wasm最早的出现是为了解决浏览器端的性能问题,让web应用可以达到与本地原生应用类似的性能。
对于浏览器chrome 采用了v8 javascript引擎,其内置了一个 Wasm Runtime,因此可以实现对 wasm 的支持,这也正是浏览器可以运动wasm的原因。
服务端 2019 年 3 月,Mozilla 推出了 WebAssembly 系统接口(Wasi),以标准化 WebAssembly 应用程序与系统资源之间的交互抽象,例如文件系统访问、内存管理和网络连接,该接口类似于 POSIX 等标准 API。Wasi 规范的出现极大地扩展了 WebAssembly 的应用场景,使得 Wasm 不仅限于在浏览器中运行,而且可以在服务器端得到应用。同时,平台开发者可以针对特定的操作系统和运行环境提供 Wasi 接口的不同实现,允许跨平台的 WebAssembly 应用程序运行在不同的设备和操作系统上。
开发教程:
Develop WASM Apps: https://wasmedge.org/docs/develop/overview Embed WasmEdge in Your Apps: https://wasmedge.org/docs/embed/overview 运行原理 下面介绍下为什么需要runtime以及常见的运行时有哪些?
为什么需要Runtime WebAssembly (WASM) 需要运行时环境来提供执行和管理 WASM 模块的功能。下面是一些 wasm 需要运行时的原因:
跨平台执行:WebAssembly 是一种跨平台的二进制指令集格式,用于在不同的环境中执行。运行时环境负责将 WASM 模块加载到特定的执行环境中,并提供必要的接口和功能,使其能够在不同的操作系统和硬件平台上运行。 安全性限制:WebAssembly 是一种沙箱化的执行环境,它在运行时提供了严格的安全性限制。运行时负责执行这些限制,以确保 WASM 模块只能访问其限定的资源,并且不能执行恶意操作。 内存管理:WASM 运行时负责管理线性内存,这意味着它负责分配、释放和管理 WASM 模块的内存资源。运行时提供了合适的内存管理功能,以确保模块运行期间的内存访问的正确性和安全性。 调用外部功能:WASM 运行时提供了一种机制,使 WASM 模块能够与宿主环境进行交互,并调用外部的功能和服务。运行时环境定义了模块与宿主环境之间的接口和调用约定,使得模块能够访问特定功能,如文件系统、网络连接等。 性能优化和代码优化:WASM 运行时可以对加载的 WASM 模块进行解析、编译和优化,以提高执行效率和性能。运行时环境可以实现一些优化技术,如即时编译(Just-in-Time Compilation)和调用间内联(Function Inlining),从而使模块的执行更高效。 综上所述,WASM 需要运行时环境来提供必要的功能和接口,以便在跨平台的环境中安全地加载、执行和管理模块。运行时环境扮演了连接 WASM 模块和宿主环境之间的桥梁角色,使得在不同的环境中使用 WASM 变得更加便捷和可靠。
September 5, 2023
istio 中 sidecar 注入实现原理
在 istio 中为了对流量进行有效的管理,一般通过注入的方式将代理 istio-proxy 与应用程序一起位于同一个Pod,然后通过 istio-init initContainer修改 iptables 实现 ingress 或 egress,那么在 istio 中这个注入是如何实现的呢,本节对其实现原理进行一些分析。
实现原理 在上一节《apiserver 中的webhook开发教程》 我们介绍过admission controller 基本实现原理,由此得知当创建一个资源对象的时候,可以通过定义 ValidatingWebhookConfiguration 或 MutatingWebhookConfiguration 实现在创建的进程中对这些 webhook 进行调用。而 MutatingWebhookConfiguration 则可以对请求的资源进行修改。在istio中的 injection 正是基于此原理实现的。
webhook配置 当我们在k8s集群中安装 istio 后,会创建一些资源,如 deployment、service、crd 等
$ istioctl install --set profile=demo -y ✔ Istio core installed ✔ Istiod installed ✔ Egress gateways installed ✔ Ingress gateways installed ✔ Installation complete $ kubectl get deployment -n istio-system NAME READY UP-TO-DATE AVAILABLE AGE istio-egressgateway 1/1 1 1 126m istio-ingressgateway 1/1 1 1 126m istiod 1/1 1 1 131m $ kubectl get pod -n istio-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES istio-egressgateway-7b8b76f497-w2xvj 1/1 Running 0 139m 10.
August 31, 2023
terraform 中的 provider
本文主要对 terraform 中的 Providers 进行介绍,让刚刚接触 terraform 的用户对其有一个大概的了解,以下内容翻译自:https://developer.hashicorp.com/terraform/language/providers
什么是 Providers 实践: Try the Perform CRUD Operations with Providers tutorial.
Terraform 依赖于称为提供商的插件来与云提供商、SaaS 提供商和 其他 API 进行交互。 Terraform 配置必须声明它们需要哪些 providers,以便 Terraform 可以 安装 和 使用 它们。此外,某些提供商在使用之前需要进行配置(例如 端点 URL 或 云区域)。
Providers 能做什么 每一个 Providers 都会有一组 Terraform 可以管理的 resource types 和或 data sources。如我们经常使用的 docker provider, 它提供了一些 Resources 和 Data sources,使用的时候只需要查看一下 provider 提供的有哪些配置直接 。
每个 resouce type 都由 Provider 实现;如果没有Provider的话,Terraform 就无法管理任何类型的基础设施。 大多数提供商配置特定的基础设施平台(云或自托管)。提供商还可以提供本地实用程序来执行诸如为唯一资源名称生成随机数之类的任务。
Providers 来自哪里 providers 与 Terraform 本身分开分发,每个提供程序都有自己的发布节奏和版本号。 Terraform Registry 是公开可用的 Terraform providers,并托管大多数主要基础设施平台的提供程序。
August 19, 2023
k8s 中 CRD controller 开发教程
本文主要介绍 crd controller 的基本开发过程,让每一个刚接触k8s开发的同学都可以轻松开发自己的控制器。
kubebuilder 简介 kubebuilder 是一个帮助开发者快速开发 kubernetes API 的脚手架命令行工具,其依赖 controller-tools 和 controller-runtime 两个库。其中 controller-runtime 简化 kubernetes controller 的开发,并且对 kubernetes 的几个常用库进行了二次封装, 以简化开发工程。而 controller-tool 主要功能是代码生成。
下图是使用 kubebuilder 的工作流程图:
安装 kubebuilder # download kubebuilder and install locally. ➜ curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)" ➜ chmod +x kubebuilder && mv kubebuilder /usr/local/bin/ 确认安装成功
➜ kubebuilder version Version: main.version{KubeBuilderVersion:"3.11.1", KubernetesVendor:"1.27.1", GitCommit:"1dc8ed95f7cc55fef3151f749d3d541bec3423c9", BuildDate:"2023-07-03T13:10:56Z", GoOs:"darwin", GoArch:"amd64"} 相关命令
➜ kubebuilder --help CLI tool for building Kubernetes extensions and tools.
August 3, 2023
apiserver 中的webhook开发教程
k8s: v1.27.3
什么是准入控制插件? 准入控制器 是一段代码,它会在请求通过认证和鉴权之后、对象被持久化之前拦截到达 API 服务器的请求。
准入控制器可以执行 变更(Mutating) 和或 验证(Validating) 操作。 变更(mutating)控制器可以根据被其接受的请求更改相关对象;验证(validating)控制器则不行。
准入控制器限制创建、删除、修改对象的请求。 准入控制器也可以阻止自定义动作,例如通过 API 服务器代理连接到 Pod 的请求。 准入控制器不会 (也不能)阻止读取(get、watch 或 list)对象的请求。
某些控制器既是变更准入控制器又是验证准入控制器。如果两个阶段之一的任何一个控制器拒绝了某请求,则整个请求将立即被拒绝,并向最终用户返回错误。
Kubernetes 1.27 中的准入控制器由下面的列表组成, 并编译进 kube-apiserver 可执行文件,并且只能由集群管理员配置。 在该列表中,有两个特殊的控制器:MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。 它们根据 API 中的配置, 分别执行变更和验证准入控制 webhook。
参考: https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/
同类型的webhook的顺序无关紧要。
什么是准入 Webhook? 除了内置的 admission 插件, 准入插件可以作为扩展独立开发,并以运行时所配置的 Webhook 的形式运行。 此页面描述了如何构建、配置、使用和监视准入 Webhook。
准入 Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。 可以定义两种类型的准入 webhook,即 修改性质的准入 Webhook(Mutating admission) 和 验证性质的准入 Webhook ( Validating admission) 。
Mutalting Webhook 会先被调用,它们可以更改发送到 API 服务器的对象以执行自定义的设置默认值操作。
August 1, 2023
k8s之kube-controller-manager 源码分析
Kubernetes 控制器管理器(kube-controller-manager)是一个守护进程,内嵌随 Kubernetes 一起发布的核心控制回路。 在机器人和自动化的应用中,控制回路是一个永不休止的循环,用于调节系统状态。 在 Kubernetes 中,每个控制器是一个控制回路,通过 API 服务器监视集群的共享状态, 并尝试进行更改以将当前状态转为期望状态。 目前,Kubernetes 自带的控制器例子包括副本控制器、节点控制器、命名空间控制器和服务账号控制器等。
本文不对 kube-controller-manager 管理的每个控制器的执行原理做介绍,只是从全局观看一下kube-controller-manager 启动每个控制器的整体实现过程。
k8s: v1.27.3
文件: cmd/kube-controller-manager/app/controllermanager.go
控制器选项初始化 // cmd/kube-controller-manager/app/controllermanager.go#L104 func NewControllerManagerCommand() *cobra.Command { // 所有内置控制器配置 s, err := options.NewKubeControllerManagerOptions() } 调用 options.NewKubeControllerManagerOptions() 对所有内置控制器及全局配置进行初始化。
func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) { componentConfig, err := NewDefaultComponentConfig() if err != nil { return nil, err } s := KubeControllerManagerOptions{ Generic: cmoptions.NewGenericControllerManagerConfigurationOptions(&componentConfig.Generic), KubeCloudShared: cpoptions.NewKubeCloudSharedOptions(&componentConfig.KubeCloudShared), ServiceController: &cpoptions.ServiceControllerOptions{ ServiceControllerConfiguration: &componentConfig.ServiceController, }, AttachDetachController: &AttachDetachControllerOptions{ &componentConfig.
July 31, 2023
k8s调度器插件开发教程
上一篇 《k8s调度器 kube-scheduler 源码解析》 大概介绍一调度器的内容,提到扩展点的插件这个概念,下面我们看看如何开发一个自定义调度器。
本文源码托管在 https://github.com/cfanbo/sample-scheduler。
插件机制 在Kubernetes调度器中,共有两种插件机制,分别为 in-tree 和 out-of-tree。
In-tree插件(内建插件):这些插件是作为Kubernetes核心组件的一部分直接编译和交付的。它们与Kubernetes的源代码一起维护,并与Kubernetes版本保持同步。这些插件以静态库形式打包到kube-scheduler二进制文件中,因此在使用时不需要单独安装和配置。一些常见的in-tree插件包括默认的调度算法、Packed Scheduling等。 Out-of-tree插件(外部插件):这些插件是作为独立项目开发和维护的,它们与Kubernetes核心代码分开,并且可以单独部署和更新。本质上,out-of-tree插件是基于Kubernetes的调度器扩展点进行开发的。这些插件以独立的二进制文件形式存在,并通过自定义的方式与kube-scheduler进行集成。为了使用out-of-tree插件,您需要单独安装和配置它们,并在kube-scheduler的配置中指定它们。 可以看到 in-tree 插件与Kubernetes的核心代码一起进行维护和发展,而 out-of-tree插件可以单独开发并out-of-tree插件以独立的二进制文件部署。因此 out-of-tree插件具有更大的灵活性,可以根据需求进行自定义和扩展,而 in-tree 插件受限于Kubernetes核心代码的功能和限制。
对于版本升级in-tree插件与Kubernetes版本保持同步,而out-of-tree插件可以单独进行版本升级或兼容。
总的来说,in-tree 插件是Kubernetes的一部分,可以直接使用和部署,而 out-of-tree 插件则提供了更多的灵活性和定制化能力,但需要单独安装和配置。
一般开发都是采用out-of-tree 这各机制。
扩展点 参考官方文档 https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/scheduling-framework/#%E6%89%A9%E5%B1%95%E7%82%B9
下图显示了一个 Pod 的调度上下文以及调度框架公开的扩展点。
一个插件可以在多个扩展点处注册执行,以执行更复杂或有状态的任务。
对于每个扩展点的介绍,可参考上面给出的官方文档,这里不再做介绍。
我们下面开发的是一个 Pod Scheduling Context 部分的 Filter调度器插件,插件的功能非常的简单,就是检查一个 Node 节点是否存在 cpu=true标签,如果存在此标签则可以节点有效,否则节点视为无效,不参与Pod调度。
插件实现 要实现一个调度器插件必须满足两个条件:
必须实现对应扩展点插件接口 将此插件在调度框架中进行注册。 不同扩展点可以启用不同的插件。
插件实现 每个扩展点的插件都必须要实现其相应的接口,所有的接口定义在 https://github.com/kubernetes/kubernetes/blob/v1.27.3/pkg/scheduler/framework/interface.go。
// Plugin is the parent type for all the scheduling framework plugins. type Plugin interface { Name() string } // FilterPlugin is an interface for Filter plugins.
July 28, 2023
k8s调试之 kube-apiserver 组件
上一节《GoLand+dlv进行远程调试》我们介绍了如何使用 GoLand 进行远程调试,本节我们就以 kube-apiserver 为例演示一下调试方法。
服务器环境 作为开发调试服务器,需要安装以下环境
安装 Golang 环境,国内最好设置 GOPROXY 安装 dlv 调试工具 安装 Docker 环境, 同时安装 containerd 服务(对应官方教程中的 containerd.io 安装包)并设置代理 同步代码(本地) 以下为我们本机环境设置。
本机下载 kubernetes 仓库
git clone --filter=blob:none https://github.com/kubernetes/kubernetes.git 这里指定 –filter=bold:none 可以实现最小化下载
这里 k8s 项目目录为 /Users/sxf/workspace/kubernetes, 对应远程服务器目录为 /home/sxf/workspace/kubernetes,如图所示
映射关系配置
同时选择自动上传 Automatic upload (Always) 菜单,这样以后当本地文件有变更时将自动同步到远程服务器。
首次手动同步远程代码(右键Upload here菜单)
如果文件特别多的话,首次同步将会比较慢,可以手动将本地项目打包上传到远程服务器再解压。
环境检测 首先对当前调试环境进行一系列的检查,如果条件不满足将给出提示信息
$ make verify 如果本地 Git 仓库存在未提交的文件的话,则此时将提示先提交。这一块有点不好,我这里直接终止了这个检查继续下一步。
安装Etcd 由于 kube-apiserver 依赖于 ectd ,所以必须先安装etcd。
$ cd workspace/kubernetes $ ./hack/install-etcd.sh Downloading https://github.com/coreos/etcd/releases/download/v3.5.7/etcd-v3.5.7-linux-amd64.tar.gz succeed etcd v3.
July 27, 2023
Goland+dlv远程调试
环境
远程服务器(Linux):192.168.245.137
本地(macOS):GoLand
目的 远程调试就是使用使用本地 IDE 来调试远程服务器上的服务。本地打断点,调用远程服务的接口。本地就会停在断点。
为什么需要远程调试呢?主要有以下几点原因:
运行环境:有时候本机不具备调试环境,如开发的程序依赖太多组件,而这些组件在当前机器并不被支持 性能:一般远程服务器的配置都比较高,编译速度也比较快。而开发机器的配置相对要低一些,每次修改程序都要重新编译,非常的消耗时间。 硬盘空间:编译时产生大量的中间临时文件,多达10个G左右,如果本机硬盘空间不足的话,则根本就没有办法进行本地调试 我这里用的系统是macOS,硬盘只有128G大小,硬盘空间非常的紧张,vmware虚拟机占用了30个G, 在虚拟机里编译时发现期间产生的临时文件达到6个G,硬盘空间已经不远远不够,所以选择使用远程调试这种方式。
这些调试方式对于k8s 开发者来讲应该比较常见,如 调试 kube-apiserver 组件。
安装 dlv(远程) 首先我们在远程服务器安装 Golang 环境 和 dlv 命令。
这里默认已经安装好了 Golang 环境,版本为1.20,如果没有安装的话,则需要先安装一下,参考 https://go.dev
安装 dlv 命令参考 https://github.com/go-delve/delve/tree/master/Documentation/installation
# go install github.com/go-delve/delve/cmd/dlv@latest 查看一下 dlv 的用法
# dlv -h Delve is a source level debugger for Go programs. Delve enables you to interact with your program by controlling the execution of the process, evaluating variables, and providing information of thread / goroutine state, CPU register state and more.