Jason Pan

自举-用Go写Go的编译器、用K8s部署K8s

潘忠显 / 2025-03-20


最近在回顾 K8s 的一些知识,发现有个点比较有意思,跟大家分享一下。

K8s 的控制平面部署方式有一种是自托管模式,简单点讲,通过 K8s 来部署 K8s——一种看上去是鸡生蛋、蛋生鸡的依赖。

k8s-deployment-options

用K8s部署K8s控制平面

了解过 K8s 的都大概知道,控制平面是用来管理K8s集群的,比如资源的调度、检测和响应集群事件等。

k8s-control-plane

控制平面组件包括:kube-apiserver、etcd、kube-scheduler、kube-controller-manager 等,这些组件可以在集群中的任何节点上运行。

传统部署

最简单的,安装脚本通常会在同一个计算机上启动所有控制平面组件, 并且不会在此计算机上运行用户容器。

这也就是所谓的传统部署——直接在专用机器或虚拟机上运行,通常作为 systemd 服务进行管理。

也就是我们直接在节点上拉起了 etcd、kube-api-server 这些服务进程。

静态 Pod

集群中每个节点上都有运行 Kubelet。kubelet 可以接收一组通过各类机制提供给它的 PodSpec(其实就是一些 Pod 的配置)然后确保这些 Pod 中的容器能够健康运行。

这样的话,就可以将控制平面组件作为静态 Pod 部署,由特定节点上的 kubelet 管理。当然,这个过程需要 kubeadm 类似的工具来协助。

自托管(Self-Hosted)

不管是通过传统部署还是静态Pod的方式,都可以启动起控制平面,然后管理K8s集群了。

这时候,就可以通过以下三步,将控制平面迁移到「自托管模式」:

这样的好处是,可以利用 Kubernetes 的调度和管理能力,提供更好的更新、扩展和自愈能力

最终的形态就是这样(图中每个七边形都是一个Pod?所以这里的kublet也是自托管模式?):

k8s-self-hosted

用Go语言写Go的编译器

「Go语言的编译器是Go写的」这句话会令人迷惑:没有Go语言的编译器,如何能构建Go语言的项目,那也就构建不出Go语言的编译器。

但这肯定难不倒作为程序员的你。这个问题就跟「第一个大学老师没上过大学」一样,最初的 Go 语言的编译器,肯定也不是 Go 写的。如果「第一个大学老师有大学毕业证」,那也应该也是大学创建之后的事情了。

类似地,早期的 Go 编译器是用 C 语言编写的。

后来,随着 Go 语言的发展,现代的 Go 编译器是用 Go 语言本身编写的。

go-bootstrap-plan

类似地,别的语言也有这样的实现,比如 Rust 语言编译器 rustc 也是通过 Rust 实现的。

自举

上边这种K8s自托管K8s用Go语言实现Go语言的编译器的过程,叫做自举(bootstrapping)

(“Bootstrap” 的字面意思是指通过拉动靴子(boot)的带子(strap)来使自己站起来。这种自我提升的比喻,后来被引申到计算机科学和其他领域。)

通过这种方式,系统或语言能够更好地利用自身的特性和优势,提升整体性能和可维护性

自举的过程在软件工程中非常常见,体现了系统或语言的逐步成熟和自我优化能力