k8s 几种探针作用和用法

在 Kubernetes 中,探针(probes)是一种机制,用于检查容器是否处于正常状态以及容器是否可以接收流量。 Kubernetes 提供了三种类型的探针:存活探针(Liveness Probe)、就绪探针(Readiness Probe)和启动探针(Startup Probe)。 以下是这三种探针的作用和用法: 存活探针(Liveness Probe) 作用:检查容器中的进程是否仍在运行。如果进程崩溃或停止响应,Kubernetes 将重启容器。 用法:建议在容器的生命周期中始终使用存活探针,以确保容器的可靠性。例如,可以配置一个存活探针来检查容器中的进程是否响应 HTTP 请求或 ping 命令。 示例 YAML 配置: livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 该配置文件指示 Kubernetes 发送一个 HTTP GET 请求到容器的 /healthz 路径,并在容器启动后的 5 秒后开始检查容器的运行状况。检查频率为每隔 10 秒发送一次。 就绪探针(Readiness Probe) 作用:检查容器是否准备好接收流量。如果容器尚未准备好接收流量,则 Kubernetes 将不会将流量发送到容器。 用法:建议在容器需要一些额外的时间来启动的情况下使用就绪探针。例如,可以配置一个就绪探针来检查容器是否存在必需的文件或数据库连接。 示例 YAML 配置: readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 该配置文件指示 Kubernetes 检查容器是否可以在 8080 端口接收 TCP 连接,并在容器启动后的 5 秒后开始检查容器的运行状况。检查频率为每隔 10 秒发送一次。 启动探针(Startup Probe) 作用:检查容器内部应用程序是否已经启动,成功后会运行存活和就绪探针。与存活探针和就绪探针不同,它们在容器启动时运行,并在容器启动完成后禁用。 用法:建议在容器启动时需要启动较长时间的应用程序时使用启动探针。例如,可以配置一个启动探针来检查容器中的某个进程或 Web 服务器是否已经启动。 ...

<span title='2023-05-12 11:03:18 +0800 +0800'>五月 12, 2023</span>

在WSL中配置gitlab/github SSH KEY

背景 在公司里普遍使用搭建的gitlab,很多情况下我们使用终端提交,这时候就会频繁的数据账户和密码,为了不输入密码我们会配置SSH KEY来免登录. 步骤 使用ssh-keygen 来生成公钥和私钥 使用ssh-keygen -t ed25519 或者 ssh-keygen -t rsa -b 2048 没什么特别的一路回车 这时候会在你~/.ssh/目录下生成密钥对 以rsa密钥为例,把~/.ssh/id_rsa.pub的内容配置到gitlab 测试使用ssh git@gitlab.xxx.com(你公司的域名)看下是否正常打印你的配置名称,如果不正常使用ssh -Tvvv git@gitlab.xxx.com打印调试信息,看是哪个地方出了问题 已经可以正常提交代码 可能出现的问题 ssh连接没问题,但是git会提示输入用户密码 这种情况看下自己仓库是否使用的是http连接, 如果是替换ssh链接就可以解决git remote set-url origin git@xxx.com:username/blog.git 使用go来拉取包时如果使用http地址拉取怎么办 可以使用Git提供的凭证存储器来配置HTTP协议的自动登录,Git提供了三种凭证存储器,分别是cache、store和osxkeychain。不同的存储器有各自的优缺点,例如cache存储器将凭证信息保存在内存中,store存储器将凭证信息保存在本地的plain-text文件中,osxkeychain存储器则将凭证信息保存到Mac的Keychain应用程序中. 可以使用git config --global credential.helper store来配置,然后随便拉取一个该域名的项目,输入账号密码就会存储到本地,后面就不会再要求输入用户密码

<span title='2023-05-08 14:24:08 +0800 +0800'>五月 8, 2023</span>

go 编译指令build

go:build 是 Go 1.17 版本中引入的一个构建标记,用于根据不同的条件控制代码的编译。go:build 格式如//go:build <标记表达式>, 1.17之前使用+build的方式,这里我们介绍更强大的的go:build. 表达式可以包含由 ||、&& 和 ! 运算符和括号组合的选项,含义与 Go 语言中相同. 构建约束可以出现在任何类型的源文件中(不仅仅是 Go 文件),但是它们必须出现在文件的顶部附近,仅由空行和其他行注释分隔。这些规则意味着在 Go 文件中,构建约束必须出现在包声明之前。 例如,下面的构建约束将约束一个文件在满足“linux”和“386”约束条件或在满足“darwin”条件且未满足“cgo”条件时进行构建://go:build (linux && 386) || (darwin && !cgo) 自定义tag //go:build atest 当我们使用go build -tags atest的情况下会编译此文件,否则不会编译 控制go版本 //go:build go1.17 指定当前文件>=go1.17才编译 //go:build go1.17 && go1.20 版本>= go1.17 并且<= go1.20

<span title='2023-03-07 10:50:47 +0800 +0800'>三月 7, 2023</span>

Intel hex文件格式

Intel HEX格式文件是一种常见的用于表示程序存储器内容的文本格式,常用于将程序存储器内容导出或者导入到不同的开发工具中。它的文件扩展名通常是 .hex。 该文件格式由一系列行组成,每一行以冒号(:)开头,以回车换行符(\r\n)结尾,每一行包含以下几个部分: 起始符号:一个字符,表示该行的起始,必须为“:”。 数据长度:一个字节,表示该行所包含的数据长度,以字节为单位,范围从 0 到 255。 起始地址:两个字节,表示该行数据在存储器中的起始地址,以字节为单位,高位在前,低位在后。 记录类型:一个字节,表示该行数据的类型。常见的记录类型包括数据记录(00)、结束记录(01)等。 数据:一个或多个字节,表示该行的数据内容。数据的长度由数据长度字段指定。 校验和:一个字节,表示该行数据的校验和,为数据长度、起始地址、记录类型和数据的按位异或和的补码。 例如 :10010000214601360121470136007EFE09D2190140 //起始符号是“:”。 //数据长度是“10”。 //起始地址是“0100”。 //记录类型是“00”,表示这是一个数据记录。 //数据部分包含了16个字节的数据:“214601360121470136007EFE09D21901”。 //校验和是“40”。 //这个数据记录包含了16个字节的数据,它们对应的起始地址是0x0100~0x010F。每两个字节表示一个数据,因此这个记录实际包含了8个数据,分别是“21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01”。 :00000001FF //起始符号是“:”。 //数据长度是“00”。 //起始地址是“0000”。 //记录类型是“01”,表示这是一个结束记录。 //数据部分为空。 //校验和是“FF”。 //这个记录表示文件结束。当解析Intel HEX格式文件时,如果读到了一个记录类型为“01”的记录,就表示已经读到了文件的结尾,应该停止解析。 记录类型 在Intel HEX格式文件中,一共定义了5种记录类型。它们分别是: 数据记录(Data Record),记录类型为“00”。 结束记录(End Of File Record),记录类型为“01”。 扩展段地址记录(Extended Segment Address Record),记录类型为“02”。 扩展线性地址记录(Extended Linear Address Record),记录类型为“04”。 起始段地址记录(Start Segment Address Record),记录类型为“03”。 其中,最常用的是数据记录和结束记录。其他三种记录类型则用于更高级的应用,如程序跳转、内存分段等。 举例: 数据记录(Data Record)::10010000214601360121470136007EFE09D2190140 这是一条16字节的数据记录,其记录类型为“00”。数据部分为“214601360121470136007EFE09D21901”。 ...

<span title='2023-02-27 16:45:45 +0800 +0800'>二月 27, 2023</span>

go 编译指令Linkname

go:linkename是go的编译指令,可以在一个包中使用另一个包中的非导出函数或变量 具体使用方法举例 在pkg1包中有个未导出的函数add package pkg1 func add(a, b int) int { return a + b } 在pkg2中想要使用pkg1.add,正常来说add开头是小写是不能被另一个包使用的,这时候我们想要在另一个包中使用就有两种方法: 在pkg1中定义一个可以导出的函数,这种就是在写个Add函数包裹一下,这种就不举例了 在pkg2中使用linkname编译指令修改函数或变量的名称和可见性(不太建议) 这里我们举例第二种 package pkg2 import ( _ "goasm/pkg1" //需要引入pkg1, 让pkg1参与代码编译,否则编译器找不到, 这句也可以写在别的文件中,只要让pkg1参与编译就行, relocation target goasm/pkg1.add not defined _ "unsafe" //编译器要求导入unsafe包,否则不能使用linkname指令 ) //下面就是linkname编译指令使用方法, 在函数声明上添加注释, 其中pkg1_add是函数名称, goasm/pkg1.add 是要连接的函数, 这句指令的效果就是,调用pkg1_add就是在调用goasm/pkg1包中的add函数 //go:linkname pkg1_add goasm/pkg1.add func pkg1_add(a, b int) int func Add2(a, b int) int { return pkg1_add(a, b) } 总结: go:linkname的使用是依赖于编译器的实现,因此使用时需要慎重考虑其可维护性和可移植性。 总之了解就好,不是迫不得已不要真的使用

<span title='2023-02-24 14:35:25 +0800 +0800'>二月 24, 2023</span>

Swap开启和关闭

树莓派 /etc/dphys-swapfile 是 Raspberry Pi 上的一个文件,用于控制swap文件的设置和使用。该文件用于设置swap文件的大小、位置以及启用和禁用swap。 在 Raspberry Pi 上,如果想要使用swap文件,可以通过以下步骤配置和使用swap文件: 安装 dphys-swapfile 包,使用命令: sudo apt-get update sudo apt-get install dphys-swapfile 打开 /etc/dphys-swapfile 文件,配置swap文件的大小和位置。例如,将以下行: CONF_SWAPSIZE=100 #修改为0可关闭swap CONF_SWAPFILE=/var/swap 启用 sudo dphys-swapfile setup sudo dphys-swapfile swapon 禁用 sudo dphys-swapfile swapoff 其他linux 在Linux中,可以通过以下步骤关闭swap: 查看当前的swap情况,使用命令: swapon -s 如果没有任何输出,则说明当前系统没有启用swap。 如果系统启用了swap,需要先关闭swap,使用命令: swapoff -a 执行此命令会关闭所有swap分区。 临时禁用swap,使用命令: echo 0 > /proc/sys/vm/swappiness 执行此命令可以临时禁用swap,即使系统启用了swap,也不会自动将数据交换到swap分区。 永久禁用swap,可以修改/etc/fstab文件,注释掉swap分区的行,或者直接删除swap分区的行。例如,将以下行: #/dev/sda2 swap swap defaults 0 0

<span title='2023-02-23 15:37:31 +0800 +0800'>二月 23, 2023</span>

针对循环查询的逻辑优化思路

在工作中总能碰见有人的接口使用循环查询数据库的情况,针对这种情况我总结了一些针对这种情况的初步优化思路. 限制和优点 限制 此种方法只针对循环查询这种类型的优化 优点 不用完全了解业务逻辑,即可完成有效的优化 方法 概述 先明确循环的位置, 以及循环内要查的数据 采用包一层的思路(计算机界没有什么是包一层不能解决的, 如果不能就再包一层😊), 把查询提前到循环外, 通过提供相同的查询逻辑(在内存里的查询),替换循环中的查询(数据库的查询),必须保证新的查询和老查询功能一致. 听起来好像没什么特别的,我们来看下具体实施过程 伪代码 假设有一个这种函数 func GetPersonList(xx) { ps := models.GetPersonByXX() for _, v := range ps { //xxxx很多逻辑,很复杂 orders := models.GetOrderByPerson(v.ID) //这里循环查数据库,我们需要看懂这块的查询条件和返回值 //xxx很多逻辑,很复杂 } } 我们可以这样优化 //1. 在models层实现一个批量查询接口 models.GetOrderByPersons(id ...int) //2. 包一层实现一个数据缓存结构 type OrderDataCache struct { order map[int/*person id */] []Order //这里的结构根据具体查询定义, 上述例子是通过person id查 } //3. 初始化数据缓存结构函数, 根据你具体的业务实现 func NewOrderDataCache(personID ....int) OrderDataCache { //调用批量查询 orders := models.GetOrderByPersons(id ...int) for _, v := range orders { //处理成[personid] []Order 结构 } return OrderDataCache{ //[personid] []Order } } //4. 用来替换循环查询的方法, 和单次查询的查询条件和返回值保持一致 func (o OrderDataCache) GetOrderByPerson( persionID int) []Order { //这里实现一个和orders := models.GetOrderByPerson(v.ID) 一样的查询逻辑 return o.order[persionID] } func GetPersonList(xx) { ps := models.GetPersonByXX() orderCache := NewOrderDataCache(ps中提取id) //6.批量查询 for _, v := range ps { //xxxx很多逻辑,很复杂 orders := orderCache.GetOrderByPerson(v.ID) //7. 查询替换成我们新的方法 //xxx很多逻辑,很复杂 } }

<span title='2023-02-02 17:06:48 +0800 +0800'>二月 2, 2023</span>

Proto Plugin

1.插件命名规则 ​ proto插件名称需要使用protoc-gen-xxx ​ 当使用protoc –xxx_out时就会调用proto-gen-xxx插件 2.protobuf解析一般流程 方法1: 先通过标准输入生成CodeGeneratorRequest 通过CodeGeneratorRequest初始化插件plugin 通过插件plugin获取文件File 遍历文件,处理内容,生成文件 像标准输出写入响应plugin.Response 示例代码: s := flag.String("a", "", "a") flag.Parse() //生成Request input, _ := ioutil.ReadAll(os.Stdin) var req pluginpb.CodeGeneratorRequest proto.Unmarshal(input, &req) //设置参数,生成plugin opts := protogen.Options{ ParamFunc: flag.CommandLine.Set, } plugin, err := opts.New(&req) if err != nil { panic(err) } fmt.Fprintf(os.Stderr, "a=%s\n", *s) // protoc 将一组文件结构传递给程序处理,包含proto中import中的文件 for _, file := range plugin.Files { if !file.Generate { //显示传入的文件为true continue } fmt.Fprintf(os.Stderr, "path:%s\n", file.GoImportPath) genF := plugin.NewGeneratedFile(fmt.Sprintf("%s_error.pb.go", file.GeneratedFilenamePrefix), file.GoImportPath) //用来处理生成文件的对象 GenFile(genF, file, *s) } // 生成response resp := plugin.Response() out, err := proto.Marshal(resp) if err != nil { panic(err) } // 相应输出到stdout, 它将被 protoc 接收 fmt.Fprintf(os.Stdout, string(out)) 方法2: var s = flag.String("aaa", "", "aaa") var s1 = flag.String("bbb", "", "aaa") flag.Parse() protogen.Options{ ParamFunc: flag.CommandLine.Set, //设置命令行参数 --xxx_out=aaa=10,bbb=20:. }.Run(func(gen *protogen.Plugin) error { //Run内部封装了方法1的步骤 for _, f := range gen.Files { if !f.Generate { //判断是否需要生成代码, 影响这里是否是true的原因是protoc是否指定这个文件 continue } //遍历各种message/service...,同方法1 } }) 示例代码: ...

<span title='2022-10-19 11:39:19 +0800 +0800'>十月 19, 2022</span>

树莓派安装k8s

本地系统为树莓派官方64位系统 Raspberry Pi OS Lite 64(Debian GNU/Linux 11) 在master和node都需要执行的步骤 本机cgroup配置 在执行kubeadm init 时出现 missing required cgroup: memory时,可以在/boot/cmdline.txt(有的系统可能在/boot/firmware/cmdline.txt)中追加 cgroup_enable=memory cgroup_memory=1 cgroup_enable=memory: 启用Cgroup子系统中的内存控制 cgroup_memory=1: 将内存控制子系统的版本设置为1 在某些特定的发行版中,可能会出于兼容性或其他原因而禁用了Cgroup子系统中的内存控制功能,所以需要手动开启 关闭swap 网上很多教程通过编辑/etc/fstab编辑swap, 但是在树莓派系统中,并不使用fstab配置,正确的做法是 编辑/etc/dphys-swapfile 找到配置项CONF_SWAPSIZE (通过名称我们可以知道该配置项为swap大小)该值配置为0 使配置生效 sudo /etc/init.d/dphys-swapfile restart 或者 sudo reboot 重启 通过free -h命令查看swap大小 系统模块加载 # 必要的模块加载 # overlay 文件系统 # br_netfilter 网桥网络包过滤 cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF # 这个命令会将 "overlay" 和 "br_netfilter" 内核模块的名称添加到 /etc/modules-load.d/k8s.conf 文件中,以便在系统启动时自动加载这些模块 sudo modprobe overlay sudo modprobe br_netfilter # sudo modprobe overlay:加载 overlay 的内核模块,该模块提供了用于 overlayfs 的文件系统类型。在使用容器化技术如 Docker 时,通常需要使用 overlayfs 进行容器镜像的存储和管理。因此,在启用容器化环境时,需要确保该模块已加载。 # sudo modprobe br_netfilter:加载 br_netfilter 的内核模块,该模块提供了用于 Linux 桥接网络的过滤和 NAT 功能。在使用 Kubernetes 集群时,通常需要将容器内部的网络流量转发到主机上的网络设备,以实现容器与外部网络的通信。因此,在启用 Kubernetes 集群时,需要确保该模块已加载。 # 开启转发和流量可观测(开机启动) # sysctl params required by setup, params persist across reboots # bridge-nf-call-iptables 让ip表可以看到桥接流量 # bridge-nf-call-ip6tables 让ip6表可以看到桥接流量 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 # 这个命令的作用是将其写入 /etc/sysctl.d/k8s.conf 文件中。在系统启动时,这些参数就会被自动设置。 # net.bridge.bridge-nf-call-iptables: 设置为 1,表示将 Linux 桥接网络中的 IP 数据包转发给 iptables 进行过滤。在使用 Kubernetes 时,需要启用此功能以实现网络策略等功能。 # net.bridge.bridge-nf-call-ip6tables: 设置为 1,表示将 Linux 桥接网络中的 IPv6 数据包转发给 ip6tables 进行过滤。 # net.ipv4.ip_forward: 设置为 1,表示启用 IPv4 数据包的转发功能。在使用 Kubernetes 时,需要启用此功能以实现跨节点的容器网络互通。 # Apply sysctl params without reboot(不用开机立刻生效) sudo sysctl --system CRI安装 根据官方文档配置环境doc ...

<span title='2022-10-05 20:49:13 +0800 +0800'>十月 5, 2022</span>

树莓派系统关闭swap

网上很多教程通过编辑/etc/fstab编辑swap, 但是在树莓派系统中,并不使用fstab配置,正确的做法是 编辑/etc/dphys-swapfile 找到配置项CONF_SWAPSIZE (通过名称我们可以知道该配置项为swap大小)该值配置为0 使配置生效 sudo /etc/init.d/dphys-swapfile restart 或者 sudo reboot 重启 通过free -h命令查看swap大小

<span title='2022-10-02 21:10:36 +0800 +0800'>十月 2, 2022</span>