欢迎访问我的GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
关于《controller-manager学习三部曲》
- 《controller-manager学习三部曲》是欣宸原创的kubernetes深入学习系列之一,在前面的《client-go实战》系列中,咱们通过反复的实践,对controller的开发和使用已经很熟练了,接下来就该称热打铁去研究kubernetes的源码,了解它的controller是如何设计和实现的,这里面一定有很多值得学习的地方,掌握了这些,反过来又能对咱们自己开发controller有所帮助,所以,别犹豫啦,一起来看看kubernetes的controller吧
- 整个《controller-manager学习三部曲》由以下三部分内容组成
- 寻找入口:kubernetes博大精深,那么多代码和脚本,如何找到controller-manager的代码,以及程序启动的入口?
- 源码分析:这个整个系列的核心,面对诸多controller,kubernetes如何做到这两件事情:第一,将启动命令中的各种flag(cobra中的flag)传递给各个controller,第二,创建和启动每个controller
- 典型controller:controller-manager只负责将controller启动,具体的controller功能是各不相同的,这里会挑一个典型的controller来学习
- 注意:整个系列用的源码来自kubernetes的master分支,go版本是1.20
关于controller-manager
- 下图是kube-system这个namespace下面所有pod的信息,黄色箭头所指即controller-manager,它负责诸多内置controller的创建和启动,还有就是从启动命令中搜集参数,以便各controller使用
本篇概览
- 本文是《三部曲》的第一篇,咱们要从kubernetes源码中找到controller-manager的入口,以便后续的学习
- controller-manager是个典型的go模块工程,所以结构和脚本也是咱们常见的格式(只不过内容多了些)
- 本篇从Makefile入手开始分析,找到编译controller-manager的详细逻辑,没什么难度,只是几个脚本的阅读而已
编译文件
- 执行make命令会用到Makefile文件,里面会调用hack/make-rules/build.sh
- 打开build.sh,里面调用了kube::golang::build_binaries
- 在golang.sh文件中查看kube::golang::build_binaries方法,下面摘取最重要的内容,可见构建用的参数来自KUBE_ALL_TARGETS这个全局变量,咱们先记住这个KUBE_ALL_TARGETS,然后继续看构建的逻辑
- 这时候应该看到了build_binaries_for_platform,可见binaries的内容会被分别存入statics和nonstatics
kube::golang::build_binaries_for_platform() {
# This is for sanity. Without it, user umasks can leak through.
umask 0022
local platform=$1
local -a statics=()
local -a nonstatics=()
local -a tests=()
for binary in "${binaries[@]}"; do
if [[ "${binary}" =~ ".test"$ ]]; then
tests+=("${binary}")
kube::log::info " ${binary} (test)"
elif kube::golang::is_statically_linked_library "${binary}"; then
statics+=("${binary}")
kube::log::info " ${binary} (static)"
else
nonstatics+=("${binary}")
kube::log::info " ${binary} (non-static)"
fi
done
- 然后调用build_some_binaries方法
if [[ "${#statics[@]}" != 0 ]]; then
build_args=(
-installsuffix=static
${goflags:+"${goflags[@]}"}
-gcflags="${gogcflags}"
-asmflags="${goasmflags}"
-ldflags="${goldflags}"
-tags="${gotags:-}"
)
CGO_ENABLED=0 kube::golang::build_some_binaries "${statics[@]}"
fi
if [[ "${#nonstatics[@]}" != 0 ]]; then
build_args=(
${goflags:+"${goflags[@]}"}
-gcflags="${gogcflags}"
-asmflags="${goasmflags}"
-ldflags="${goldflags}"
-tags="${gotags:-}"
)
kube::golang::build_some_binaries "${nonstatics[@]}"
fi
- 最终在build_some_binaries方法中完成编译构建
- 至此,输入make后的大致流程算是知道了,接下来该回头看看那个重要的参数KUBE_SERVER_TARGETS了
关于KUBE_ALL_TARGETS
- 前面曾经提到,构建参数来自KUBE_ALL_TARGETS,这里来看下这个变量里面是啥,定义在golang.sh文件中,如下所示,是由多个变量组成的
readonly KUBE_ALL_TARGETS=(
"${KUBE_SERVER_TARGETS[@]}"
"${KUBE_CLIENT_TARGETS[@]}"
"${KUBE_TEST_TARGETS[@]}"
"${KUBE_TEST_SERVER_TARGETS[@]}"
)
- 选其中一个来看看,这里选KUBE_SERVER_TARGETS,可见是每个需要构建的模块的路径
kube::golang::server_targets() {
local targets=(
cmd/kube-proxy
cmd/kube-apiserver
cmd/kube-controller-manager
cmd/kubelet
cmd/kubeadm
cmd/kube-scheduler
vendor/k8s.io/component-base/logs/kube-log-runner
vendor/k8s.io/kube-aggregator
vendor/k8s.io/apiextensions-apiserver
cluster/gce/gci/mounter
)
echo "${targets[@]}"
}
IFS=" " read -ra KUBE_SERVER_TARGETS <<< "$(kube::golang::server_targets)"
- 现在终于清楚了,在编译构建kubernetes源码的时候,kube-controller-manager模块是用go install命令编译cmd/kube-controller-manager包下的源码生成的,也就是说这个服务的入口在下图位置
启动命令分析
- 找到了程序的入口,还要了解启动服务时的参数,这样在阅读源码时,面对各种不同入参的处理,也能做到心里有数,找准关键代码去看
查看启动命令
- 找个现成的kubernetes系统,看一下真正运行的controller-manager的启动命令是啥样的
- 以我自己测试用的kubernetes环境为例,先查看pod名
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-78fcd69978-jztff 1/1 Running 6 (35d ago) 125d
coredns-78fcd69978-ts7gq 1/1 Running 6 (35d ago) 125d
etcd-hedy 1/1 Running 6 (35d ago) 125d
kube-apiserver-hedy 1/1 Running 7 (35d ago) 125d
kube-controller-manager-hedy 1/1 Running 11 (30h ago) 125d
kube-proxy-2qx6k 1/1 Running 6 125d
kube-scheduler-hedy 1/1 Running 11 (30h ago) 125d
- 可见controller-manager的pod名是kube-controller-manager-hedy,执行以下命令即可查看看pod的详细信息
kubectl describe pod kube-controller-manager-hedy -n kube-system
- 上述命令会输出大量信息,这里只展示我们最关心的内容,即controller-manager的启动命令
Command:
kube-controller-manager
--allocate-node-cidrs=true
--authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
--authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
--bind-address=0.0.0.0
--client-ca-file=/etc/kubernetes/pki/ca.crt
--cluster-cidr=100.64.0.0/10
--cluster-name=kubernetes
--cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
--cluster-signing-key-file=/etc/kubernetes/pki/ca.key
--controllers=*,bootstrapsigner,tokencleaner
--experimental-cluster-signing-duration=876000h
--feature-gates=TTLAfterFinished=true,EphemeralContainers=true
--kubeconfig=/etc/kubernetes/controller-manager.conf
--leader-elect=true
--port=0
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
--root-ca-file=/etc/kubernetes/pki/ca.crt
--service-account-private-key-file=/etc/kubernetes/pki/sa.key
--service-cluster-ip-range=10.96.0.0/22
--use-service-account-credentials=true
- 可见启动controller-manager的时候,kubernetes向其传递了大量的flag
- 至此,本篇的任务已经完成,咱们找到了应用的入口,也清楚了启动时会大概传入哪些参数,在接下来的文章该一同去深入学习controller-manager的源码了
你不孤单,欣宸原创一路相伴
- Java系列
- Spring系列
- Docker系列
- kubernetes系列
- 数据库+中间件系列
- DevOps系列