March 19, 2024
如何实现访问k8s集群服务之原理
"当我们想将 k8s 集群里的服务向外暴露时,一般是将 k8s service 指定 LoadBalancer类型。目前大多数云厂商会绑定云平台的负载均衡器,并为其分配一个固定的公网 IP 从而向外提供服务。而对于我们自建的 kubernetes 裸机集群则只能选择类似 MetalLB 这类解决方案,这种情况下如何让用户可以通过这个 IP 访问到自建 k8s 的服务呢,本文来分析一下其实现原理。\n本文的环境安装了 MetallB,它指定分配 IP Pool 为内网 IP 地址,实验环境为 https://blog.haohtml.com/posts/install-kubernetes-in-raspberry-pi/。\n将外部请求流入集群节点 当我们需要访问一台机器时,无论是使用 IP 地址还是域名,最终都需要将其解析为 IP 地址。而要真正建立连接并传输数据,我们必须获取目标 IP 地址对应的 MAC 地址,这是由于 TCP/IP 协议分层机制决定的。\n在 TCP/IP 协议栈的链路层,数据是通过封装成数据帧的方式在局域网内传输的。数据帧中包含了目标 MAC 地址,用于标识应该将数据 …"
February 2, 2024
Raspberry Pi 安装Kubernetes
"这里是 arm64 架构,树莓派 4B, 四核八 G 内存 配置,系统为 Ubuntu 22.04.1 LTS\n$ uname -a Linux ubuntu 5.15.0-1049-raspi #52-Ubuntu SMP PREEMPT Thu Mar 14 08:39:42 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux $ cat /etc/issue Ubuntu 22.04.1 LTS \\n \\l 环境检查 由于 k8s 会使用 8080 和 6443 这两个端口,因此要保证端口可用,然后禁用 swap。\nsudo swapoff -a 最后对安装环境初始化,参考 https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/\n安装 Docker 参考 https://docs.docker.com/engine/install/ubuntu/\n安装成功后,修改 cgroupdriver 为 systemd,同时为了国内访问 docker …"
January 12, 2024
使用kubectl create service 命令无法为pod创建service问题
"在做一个试验时,无意中发现使用 kubectl create service 命令无法为一个通过 deployment 创建出来的pod创建对应的 service, 感觉有点奇怪,经过分析才明白怎么回事,这里将过程记录一下。\n这里需要说明一下,本文操作全部是通过 kubectl create 命令来完成的,并没有使用 kubectl apply -f pod.yaml 这种方式。\n这里先创建一个实验命名空间 lab\n$ kubectl create ns lab 首先创建一个deployment 对象\n$ kubectl create deployment test --image=nginx:1.23-alpine --replicas=2 --port=80 -n lab 确认创建成功\n$ kubectl get deploy,pod -n lab NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/test 2/2 2 2 16s NAME DESIRED CURRENT READY AGE …"
December 2, 2023
pod sandbox 创建netns源码分析
"在上一篇《创建Pod源码解析》文中,我们大概介绍了Pod的整体创建过程。其中有一步很重要,就是在创建三类容器之前必须先创建一个 sandbox (源码),本篇就来分析一下sandbox这一块的 netns 实现过程。\n对 sandbox 的创建由 kubelet 组件通过调用 CRI 容器运行时服务来实现的,对于容器运行的实现目前市面上有多个,如 Docker Engine(不推荐)、 containerd、CRI-O 等,由于目前生产环境中选择 containerd 的占大多数,所以这里我们以 containerd 为例来看一下其实现过程。\nhttps://github.com/containerd/containerd/blob/32bf805e5703bc91387d047fa76625e915ac2b80/pkg/cri/server/sandbox_run.go\n对 sandbox 的创建是由 cri 服务调用 RunPodSandbox()方法来实现的。\n// RunPodSandbox creates and starts a pod-level sandbox. …"
November 28, 2023
Rust中与闭包相关的三个trait
"在 Rust 中,闭包就是一种能捕获 上下文环境变量 的函数。\nlet range = 0..10; let get_range_count = || range.count(); 代码里的这个 get_range_count 就是闭包,range 是被这个闭包捕获的环境变量。\n虽然说它是一种函数,但是不通过 fn 进行定义。在 Rust 中,并不把这个闭包的类型处理成 fn 这种函数指针类型,而是有单独的类型定义。\n切记这里是将闭包处理成是 单独的类型定义,这一点区别与其它开发语言。\n至于按哪一种类型来处理,这个没有办法得知,因为只有在Rust编译器在编译的时候才可以确定其类型,并且在确定类型时,还需要根据这个闭包捕获上下文环境变量时的行为来确定。\n闭包trait分类 根据闭包行为划分为三类trait( 主因是受到所有权影响):\nFnOnce 适用于能被调用一次的闭包,所有闭包都至少实现了这个 trait,因为所有闭包都必须能够被调用。一个会将捕获的值移出闭包体的闭包只实现 FnOnce trait,这是因为它只能被调用一次。其获取了上下文环境变量的所有权。 FnMut 适用于不会将 …"
November 16, 2023
Rust中的迭代器iter
"迭代器模式允许你对一个序列的项进行某些处理。迭代器(iterator)负责遍历序列中的每一项和决定序列何时结束的逻辑。当使用迭代器时,我们无需重新实现这些逻辑。\n在 Rust 中,迭代器是 惰性的(lazy),这意味着在调用方法使用迭代器之前它都不会有效果。例如,示例中的代码通过调用定义于 Vec 上的 iter 方法在一个 vector v1 上创建了一个迭代器。这段代码本身没有任何用处:\nlet v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); 迭代器被储存在 v1_iter 变量中。一旦创建迭代器之后,可以选择用多种方式利用它。\n迭代器分类 Rust 中迭代器根据 所有权 可分为 iter()、iter_mut()、into_iter() 三种迭代器,使用场景:\n获取集合元素不可变引用的迭代器,对应方法为 iter()\n获取集合元素可变引用的迭代器,对应方法为 iter_mut()\n获取集合元素所有权的迭代器,对应方法为 into_iter()\n也就是说当你在 Rust 中看到调用了 iter() 方法,则表示这里使用了不可变迭代器,只能读 …"
November 7, 2023
Rust 中的 Result 与 Option
"在 Rust 中有两个常用的 enum 枚举类型,分别为 Result 和 Option,本节介绍它们两者各自的使用场景和用法。\n这里我们先给出结论\n结果 Result 表示 成功 或 失败 选项 Option 表示 有 或者 无 当从本地读取一个文件时,这时候可能读取成功,也有可能由于文件不存在或权限不足导致读取时候,这种场景一般就需要使用 Result;而当从一组数据集中查询指定元素是否存在时,这时有可能存在,也有可能不存在(用None 表示),这时情况就应该选择Option。\n由此看到,这两个枚举类型的区别理解起来还是挺简单的,下面我们单独对每一种类型做一下详细的介绍。\n结果 Result 定义\nenum Result\u0026lt;T, E\u0026gt; { Ok(T), Err(E), } Result\u0026lt;T, E\u0026gt; 类型拥有两个取值:\nOk(value) 表示操作成功,并包装操作返回的 value(value 拥有 T 泛类型)。 Err(why),表示操作失败,并包装 why,它(但愿)能够解释失败的原因(why 拥有 E 类型)。 举个例子,这里打开一个文件,如果文件存在则 …"
October 2, 2023
kubectr 一款快速查看Pod容器的kubectl插件
"以前工作中经常需要查看Pod里容器相关信息,特别是容器镜像信息,以前一直是通过 kubectl describe命令查看的\n$ kubectl describe my-pod 但由于输出的内容特别多,查看容器关键信息特别麻烦。印象最深的莫过于在部署 istio时,由于国内网络环境不稳定,经常性的遇到镜像下载失败的情况,当时极其的头疼。\n于是最近花了一点时间,开发了一款快速查看 Pod 容器信息的插件 kubectr 。\n安装 安装方法主要有三种\nkrew 安装(推荐) $ kubectl krew install ctr 目前已提交到 krew ,但由于官方审核速度较慢,此安装方法不敢保证可用\n二进制安装 从 https://github.com/cfanbo/kubectr/releases 下载对应的平台版本,并解压到对应的 PATH 环境变量目录即可。\n$ tar zxvf kubectr_linux_amd64.tar.gz $ sudo mv kubectr /usr/local/bin/ $ kubectr -h 源码安装 $ git clone …"
September 22, 2023
envoy中 lua filter 与 wasm filter使用教程
"在 Envoy 中当我们需要对 http_connection_manager 中的请求进行修改时,如添加或删除一个请求header,一般通过 HTTP Filter 过滤器来实现。\n而在Envoy 包含的几十个Filter中,通常会选择 Lua Filter (extensions.filters.http.lua.v3.Lua) 或 Wasm Filter (extensions.filters.http.wasm.v3.Wasm)这两类过滤器。\nLua Filter 与 Wasm Filter 下表是 Lua Filter 与 HTTP Filter 的对比\nLua Filter Wasm Filter 编程语言 Lua,解释型脚本语言 WebAssembly,编译型语言 运行环境 Envoy 内置的 Lua 虚拟机 Envoy 内嵌的 WebAssembly 虚拟机 生态系统 丰富的 Lua 库可供使用 逐渐形成的 WebAssembly 生态系统 性能 较低 较高 安全性 较弱 较强 可移植性 受宿主环境和依赖库限制 平台无关的二进制格式,可在不同环境中运行 在不同的环境 …"
September 17, 2023
WebAssembly开发入门教程
"wasm简介 WebAssembly(Wasm)是一种通用字节码技术,它可以将其他编程语言(如 Go、Rust、C/C++ 等)的程序代码编译为可在浏览器或服务端环境直接执行的字节码程序。\n使用场景 主要有两个使用场景,分别为 浏览器 和 服务端。\n浏览器 wasm最早的出现是为了解决浏览器端的性能问题,让web应用可以达到与本地原生应用类似的性能。\n对于浏览器chrome 采用了v8 javascript引擎,其内置了一个 Wasm Runtime,因此可以实现对 wasm 的支持,这也正是浏览器可以运动wasm的原因。\n服务端 2019 年 3 月,Mozilla 推出了 WebAssembly 系统接口(Wasi),以标准化 WebAssembly 应用程序与系统资源之间的交互抽象,例如文件系统访问、内存管理和网络连接,该接口类似于 POSIX 等标准 API。Wasi 规范的出现极大地扩展了 WebAssembly 的应用场景,使得 Wasm 不仅限于在浏览器中运行,而且可以在服务器端得到应用。同时,平台开发者可以针对特定的操作系统和运行环境提供 Wasi 接口的不同实现,允许 …"