自举-用Go写Go的编译器、用K8s部署K8s
潘忠显 / 2025-03-20
最近在回顾 K8s 的一些知识,发现有个点比较有意思,跟大家分享一下。
K8s 的控制平面部署方式有一种是自托管模式,简单点讲,通过 K8s 来部署 K8s——一种看上去是鸡生蛋、蛋生鸡的依赖。

用K8s部署K8s控制平面
了解过 K8s 的都大概知道,控制平面是用来管理K8s集群的,比如资源的调度、检测和响应集群事件等。
控制平面组件包括: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 资源(如 Deployments、StatefulSets)来管理控制平面组件。
- 将静态 Pod 的配置迁移到这些资源中。
- 更新 kubelet 配置,移除静态 Pod 的配置文件,确保控制平面组件由 Kubernetes 自身管理。
这样的好处是,可以利用 Kubernetes 的调度和管理能力,提供更好的更新、扩展和自愈能力。
最终的形态就是这样(图中每个七边形都是一个Pod?所以这里的kublet也是自托管模式?):
用Go语言写Go的编译器
「Go语言的编译器是Go写的」这句话会令人迷惑:没有Go语言的编译器,如何能构建Go语言的项目,那也就构建不出Go语言的编译器。
但这肯定难不倒作为程序员的你。这个问题就跟「第一个大学老师没上过大学」一样,最初的 Go 语言的编译器,肯定也不是 Go 写的。如果「第一个大学老师有大学毕业证」,那也应该也是大学创建之后的事情了。
类似地,早期的 Go 编译器是用 C 语言编写的。
后来,随着 Go 语言的发展,现代的 Go 编译器是用 Go 语言本身编写的。

类似地,别的语言也有这样的实现,比如 Rust 语言编译器 rustc
也是通过 Rust 实现的。
自举
上边这种K8s自托管K8s、用Go语言实现Go语言的编译器的过程,叫做自举(bootstrapping)。
(“Bootstrap” 的字面意思是指通过拉动靴子(boot)的带子(strap)来使自己站起来。这种自我提升的比喻,后来被引申到计算机科学和其他领域。)
通过这种方式,系统或语言能够更好地利用自身的特性和优势,提升整体性能和可维护性:
- K8s通过自托管,能利用起自己的调度和管理能力,提供更好的更新、扩展和自愈能力
- Go语言通过自举,不用再对C语言有依赖,比使用C更简单。
自举的过程在软件工程中非常常见,体现了系统或语言的逐步成熟和自我优化能力。