Go 源码里的这些 go: 指令 && go 自动化工具

Go 源码里的这些 go: 指令 && go 自动化工具 开发人员有很强的自动化重复性任务的倾向,这也适用于编写代码。 样板代码可能包括设置基本文件结构、初始化变量、定义函数或导入库或模块等操作。 在某些情况下,包提供样板代码作为开发人员构建的起点,通常是在代码行为配置之后生成。 尽管样板代码对于应用程序功能可能是必要的和有价值的,但它也可能是浪费和冗余的。出于这个原因,有许多工具可以最小化样板代码。 go generate 是Go编程语言的命令行工具,允许自动生成代码。您可以使用 go generate 为您的项目生成易于修改的特定代码,使该工具在减少样板文件方面功能强大。 go generate 这个命令通常用于在编译前自动生成代码。它可以用来创建那些重复性高或者模式化的代码,从而节省时间和减少错误。想想看,这在哪些情况下会特别有用呢?🤔 比如说下面有一个简单的例子,在代码中: //go:generate echo Hello, cubxxw ! 在这个例子中,当我们运行 go generate 命令时,它将执行注释中指定的命令。在这个例子里,它会打印出 “Hello, cubxxw !"。 因此,元编程(metaprogramming)的主题是一个开发和研究的热门领域,可以追溯到 1960 年代的 Lisp。元编程中一个特别有用的领域是代码生成(code-generation)。支持宏的语言内置了此功能;其他语言扩展了现有功能以支持这一点。 go:generate 在我们之前的讨论中,我们已经介绍了 “Go Generate” 命令的基础知识。现在,我们将深入探讨一些更具体的用例和实践技巧。🚀 让我们从一些术语开始。go generate 工作方式主要由三个参与者之间协调进行的: Generator:是由 go generate 调用的程序或脚本。在任何给定的项目中,可以调用多个生成器,可以多次调用单个生成器等。 Magic comments:是 .go 文件中以特殊方式格式化的注释,用于指定调用哪个生成器以及如何调用。任何以文本 //go:generate 行开头的注释都是合法的。 go generate : 是 Go 工具,它读取 Go 源文件、查找和解析 magic comments 并运行指定的生成器。 需要强调的是,以上是 Go 为代码生成提供的自动化的全部范围。对于其他任何事情,开发人员可以自由使用适合他们的任何工作流程。例如,go generate 应该始终由开发人员手动运行; 它永远不会自动调用(比如不会作为 go build 的一部分)。此外,由于我们通常使用 Go 将二进制文件发送给用户或执行环境,因此很容易理解 go generate 仅在开发期间运行(可能就在运行 go build 之前);Go 程序的用户不会知道哪部分代码是生成的以及如何生成的。(实际上,很多时候会在生成的文件开头加上注释,这是生成的,请别手动修改。)...

一月 25, 2024 · 5 分钟 · 973 字 · 熊鑫伟,我

Go 语言中的并发类型检查与跨平台开发

OpenIM 跨平台源代码类型检查工具 开始 问题 在 OpenIM 的自动化道路中,涉及到越来越全面的自动化设计和测试,在这个过程中,我遇到了一个问题,于是完成了从 go 语言类型检测再到集成本地以及 CI 的全套体验。 问题是这个 issue:https://github.com/openimsdk/open-im-server/issues/1807 我们的 Go 代码在 32 位系统(linux/386)上运行时遇到了整数溢出问题。出现这个问题的原因是 Go 中的 int 类型随体系结构的不同而大小不同:在 32 位系统上相当于 int32,而在 64 位系统上相当于 int64。 恰好在 64 位机器上正常运行,但是在 32 位机器上会出现溢出的问题,于是想着去做一套检测的工具,来解决各个平台的类型检测。 第一部分:Go 语言基础回顾 在深入探讨代码之前,让我们回顾一下 Go 语言的一些基本概念,特别是包管理、并发编程和类型系统。这些概念是理解和使用 Go 语言进行有效编程的基础。 包管理 包的概念 Go 语言中的每一个文件都属于一个包,包是多个 Go 文件的集合。 包用于组织代码,防止命名冲突,并提高代码复用性。 导入包 使用 import 语句来导入其他包。 可以导入标准库包、第三方包,或自定义包。 创建自定义包 在项目中创建一个新的目录,该目录下的 Go 文件属于同一个包。 包名通常与目录名相同,但不是强制性的。 并发编程 Goroutine Go 语言的并发单元称为 goroutine。 使用 go 关键字来启动一个新的 goroutine。 Goroutine 比线程更轻量,能有效利用多核处理器。 Channel Channel 是用于在 goroutines 之间传递消息的管道。 可以是带缓冲的或无缓冲的。 通过 channel 进行数据传递可以避免竞态条件。 类型系统 类型声明 Go 是一种静态类型语言,每个变量都有一个明确的类型。 支持基本类型(如 int, float, bool),复合类型(如 struct, slice),以及用户定义的类型。 接口 接口类型是一种抽象类型,它指定了一组方法,但不实现这些方法。 任何具有这些方法的类型都可以实现该接口。 接口提供了一种方式来指定对象的行为。 类型断言和反射 类型断言用于检查接口值的动态类型。 反射是一种检查、修改变量类型和值的方法。 类型声明 在 Go 语言中,类型声明是定义新类型的方式。Go 支持多种类型,包括基本类型(如 int、float64、bool)、复合类型(如 array、slice、map、struct),以及接口类型。通过类型声明,你可以创建自定义的类型,这对于编写清晰、易于维护的代码非常重要。...

一月 24, 2024 · 15 分钟 · 3176 字 · 熊鑫伟,我

Kubernetes 控制平面 - Kubectl 详细讲解

Kubelet组件解析 理解 kubelet Kubelet组件运行在Node节点上,维持运行中的Pods以及提供kuberntes运行时环境,主要完成以下使命: 1.监视分配给该Node节点的pods 2.挂载pod所需要的volumes 3.下载pod的secret 4.通过docker/rkt来运行pod中的容器 5.周期的执行pod中为容器定义的liveness探针 6.上报pod的状态给系统的其他组件 7.上报Node的状态 kubelet 管理Pod的核心流程主要包括三个步骤。首先,kubelet获取Pod清单,可以通过文件、HTTP endpoint、API Server和HTTP server等方式获取。其次,节点管理主要是节点自注册和节点状态更新,Kubelet在启动时通过API Server注册节点信息,并定时向API Server发送节点新消息,API Server在接收到新消息后,将信息写入etcd。最后,Pod启动流程主要包括镜像拉取、容器启动、探针监控以及状态汇报等步骤。 kubelet是Kubernetes中的一个节点代理程序,负责维护本节点上Pod的生命周期。kubelet是Kubernetes中非常重要的组件之一,它在Kubernetes集群中扮演着非常重要的角色。kubelet可以在每个节点上运行,它监视分配给该Node节点的pods,并执行各种管理容器的操作,如挂载pod所需要的volumes、下载pod的secret等。 kubelet的核心流程主要包括获取Pod清单、节点管理和Pod启动流程。其中,获取Pod清单的方式包括文件、HTTP endpoint、API Server和HTTP server等方式。节点管理主要包括节点自注册和节点状态更新,而Pod启动流程主要包括镜像拉取、容器启动、探针监控以及状态汇报等步骤。 在节点管理方面,kubelet可以通过设置启动参数-register-node来确定是否向API Server注册自己。如果kubelet没有选择自注册模式,则需要用户自己配置Node资源信息,同时需要告知kubelet集群上的API Server的位置。在启动时,kubelet会通过API Server注册节点信息,并定时向API Server发送节点新消息,API Server在接收到新消息后,将信息写入etcd。 在Pod管理方面,kubelet可以通过文件、HTTP endpoint、API Server和HTTP server等方式获取Pod清单。文件方式主要用于static pod,而HTTP和API Server方式则是Kubernetes中常用的方式。HTTP server主要用于kubelet侦听HTTP请求,并响应简单的API以提交新的Pod清单。 在Pod启动流程方面,kubelet会执行各种管理容器的操作,包括镜像拉取、容器启动、探针监控以及状态汇报等步骤。镜像拉取是Pod启动过程中的一项重要工作,kubelet可以通过imageManager模块来管理镜像。容器启动是Pod启动过程的下一步,kubelet通过container runtime来启动容器。探针监控是Pod启动过程中一项非常重要的工作,kubelet会周期性地执行pod中为容器定义的liveness探针,并将结果上报给系统的其他组件。状态汇报是kubelet的一个重要功能,它会上报pod和Node的状态给系统的其他组件,以及上报节点自身的状态和资源使用情况给API Server。 总之,kubelet是Kubernetes中非常重要的组件之一,它负责维护本节点上Pod的生命周期,并执行各种管理容器的操作。kubelet的核心流程包括获取Pod清单、节点管理和Pod启动流程。在节点管理方面,kubelet通过设置启动参数-register-node来确定是否向API Server注册自己。在Pod管理方面,kubelet可以通过文件、HTTP endpoint、API Server和HTTP server等方式获取Pod清单。在Pod启动流程方面,kubelet会执行各种管理容器的操作,包括镜像拉取、容器启动、探针监控以及状态汇报等步骤。 kubelet 架构 每个节点上都运行一一个 kubelet 服务进程,默认监听 10250 端口。 接收并执行 master 发来的指令; 管理 Pod 及 Pod 中的容器; 每个 kubelet 进程会在 API Server上注册节点自身信息,定期向 master 节点汇报节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。 kubelet 架构如下图所示:...

九月 28, 2023 · 2 分钟 · 421 字 · Xinwei Xiong, Me

Kubernetes 控制平面 - 调度器

调度器 kube-scheduler 负责分配调度 Pod 到集群内的节点上,它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。 调度器需要充分考虑诸多的因素: 公平调度; 资源高效利用; QoS; affinity 和 anti-affinity; 数据本地化(data locality) ; 内部负载干扰(inter-workload interference) ; deadlines。 kube-scheduler 调度分为两个阶段, predicate 和 priority: predicate: 过滤不符合条件的节点; priority:优先级排序,选择优先级最高的节点。. predicate 策略 PodFitsHostPorts:检查是否有 Host Ports 冲突。 PodFitsPorts:同P odFitsHostPorts。 PodFitsResources:检查 Node 的资源是否充足,包括允许的Pod数量、CPU、内存、GPU个数以及其他的OpaqueIntResources。 HostName:检查 pod.Spec.NodeName 是否与候选节点一致。 MatchNodeSelector:检查候选节点的 pod.Spec.NodeSelector 是否匹配 NoVolumeZoneConflict:检查 volume zone 是否冲突。 MatchInterPodAffinity:检查是否匹配 Pod 的亲和性要求。 NoDiskConflict:检查是否存在 Volume 冲突,仅限于 GCE PD、AWS EBS、Ceph RBD以及 iSCSI。 PodToleratesNodeTaints:检查 Pod 是否容忍 Node Taints。 CheckNodeMemoryPressure:检查 Pod 是否可以调度到 MemoryPressure 的节点上。 CheckNodeDiskPressure:检查 Pod 是否可以调度到 DiskPressure 的节点上。 NoVolumeNodeConflict:检查节点是否满足 Pod 所引用的 Volume 的条件。 priority 策略 SelectorSpreadPriority:优先减少节点上属于同一个 Service 或 Replication Controller 的 Pod 数量。 尽量将同一个 rc 下的多个副本分散到不同节点,增加可用性 InterPodAffinityPriority:优先将Pod调度到相同的拓扑上(如同一个节点、Rack、Zone等)。 LeastRequestedPriority:优先调度到请求资源少的节点上。 BalancedResourceAllocation:优先平衡各节点的资源使用。 NodePreferAvoidPodsPriority:alpha....

九月 28, 2023 · 4 分钟 · 774 字 · 熊鑫伟,我

深入了解Kubernetes等组件之ETCD

开始前 ETCD 是 Kubernetes 中所有组件中最难的,因为 ETCD 是有状态的,而不是无状态的。 我在之前做 k3s runtime 设计的时候,了解了一些关于 ETCD 和 Raft 算法相关的概念,作为前奏知识,请分别前往 ETCD 以及 Raft算法 进行前奏学习。 这一篇来深入并且贯穿的讲解 ETCD 和 Raft。并且站在 Kubernetes 的角度来深入 剖析 ETCD。 ETCD 介绍 Etcd是CoreOS基于Raft开发的分布式key-value存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。 包含的功能以及特性 前奏 都有学过,看下 Kubernetes 最关心的 存储: 主要功能 基本的key-value存储 监听机制 key的过期及续约机制,用于监控和服务发现 原子Compare And Swap和Compare And Delete,用于分布式锁和leader选举 使用场景 可以用于键值对存储,应用程序可以读取和写入 etcd 中的数据 etcd 比较多的应用场景是用于服务注册与发现 基于监听机制的分布式异步系统 etcd 是一个键值存储的组件,其他的应用都是基于其键值存储的功能展开。 采用kv型数据存储,一般情况下比关系型数据库快。 支持动态存储(内存)以及静态存储(磁盘)。 分布式存储,可集成为多节点集群。 存储方式,采用类似目录结构。(B+tree) 只有叶子节点才能真正存储数据,相当于文件。 叶子节点的父节点一定是目录,目录不能存储数据。 服务注册与发现: 强一致性、高可用的服务存储目录。 基于 Raft 算法的 etcd 天生就是这样一个强一致性、高可用的服务存储目录。 一种注册服务和服务健康状况的机制。 用户可以在 etcd 中注册服务,并且对注册的服务配置 key TTL,定时保持服务的心跳以达到监控健康状态的效果。 消息发布订阅:...

九月 26, 2023 · 6 分钟 · 1264 字 · 熊鑫伟,我

GoReleaser:自动化你的软件发布

GoReleaser 的目标是自动化发布软件时的大部分繁琐工作,通过使用合理的默认值并使最常见的用例变得简单。 准备工作: .goreleaser.yaml 文件:包含所有配置信息。(有关更多信息,请参阅 自定义 ) 干净的工作树:确保代码是最新的,并且已经提交了所有改动。 符合 SemVer 的版本号(例如 10.21.34-prerelease+buildmeta) GoReleaser 的运行步骤: GoReleaser 的运行主要分为以下四个步骤: defaulting:为每个步骤配置合理的默认值 building:构建二进制文件、档案、包、Docker 镜像等 releasing:将版本发布到配置的 SCM、Docker 注册表、blob 存储等 announcing:向配置的频道宣布您的发布 使用 -like 标志可能会跳过某些步骤,如 --skip-foo 快速开始 首先,运行 init 命令来创建示例的 .goreleaser.yaml 文件: goreleaser init 然后,我们运行一个“仅限本地”版本,看看它是否可以使用 release 命令运行: goreleaser release --snapshot --rm-dist 此时,您可以 自定义 生成的 .goreleaser.yaml 文件,或保持原样,这取决于您。最佳做法是将 .goreleaser.yaml 文件放入版本控制系统中。 您还可以使用 GoReleaser 为给定的 GOOS/GOARCH 构建二进制文件 ,这对于本地开发非常有用: goreleaser build --single-target 准备 GitHub 的 Token: export GITHUB_TOKEN="YOUR_GH_TOKEN" GoReleaser 将使用您存储库的最新 Git 标签 。...

九月 16, 2023 · 44 分钟 · 9180 字 · 熊鑫伟,我