前言
上个月遇到个诡异的集群启动问题:kube-apiserver进程在,日志也没有报错,端口也在监听,但就是无法创建Pod,kubectl命令卡死不动。查看了半小时日志没看出问题,最后只能翻源码排查。
这一翻才发现,原来kube-apiserver内部不是单一的服务,而是创建了3个Server组成服务链(KubeAPIServer、APIExtensionsServer、AggregatorServer)。AggregatorServer初始化时去连接metrics-server超时,导致整个启动流程卡住。
这次经历让我意识到:要真正理解K8s,必须深入apiserver源码。今天就带大家从main函数开始,完整走一遍kube-apiserver的启动流程。
kube-apiserver是什么?
在深入源码前,我们先明确kube-apiserver的地位:
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes集群 │
├─────────────────────────────────────────────────────────────┤
│ Master节点 │
│ ├─ kube-apiserver ← 集群的"大脑",所有API入口 │
│ ├─ kube-controller-manager │
│ ├─ kube-scheduler │
│ └─ etcd │
├─────────────────────────────────────────────────────────────┤
│ Worker节点 │
│ ├─ kubelet │
│ └─ kube-proxy │
└─────────────────────────────────────────────────────────────┘
kube-apiserver的核心职责:
- API网关:所有K8s资源操作的统一入口(kubectl、kubelet、controller等都通过它操作资源)
- 认证鉴权:验证请求身份,检查是否有权限执行操作
- 准入控制:对请求进行校验和修改(如自动注入Sidecar)
- 数据持久化:将资源状态写入etcd
- ** watch机制**:提供长连接监听资源变化
为什么要学apiserver源码?
- 它是K8s最核心的组件,理解它就理解了K8s的半壁江山
- 排查集群问题时,80%的问题都能在apiserver找到线索
- 要开发K8s扩展(CRD、Operator、APIService),必须懂apiserver架构
apiserver启动全流程概览
先看一张完整的启动流程图:
main()
↓
NewAPIServerCommand() 创建Cobra命令
↓
command.Execute() 执行命令
↓
PersistentPreRunE 设置WarningHandler
↓
RunE 核心启动流程
├─ PrintAndExitIfRequested() 打印版本信息
├─ PrintFlags() 打印启动参数
├─ checkNonZeroInsecurePort() 检查不安全端口
├─ Complete() 补全配置默认值
├─ Validate() 校验参数合法性
↓
Run() 真正的启动
├─ CreateServerChain() 创建3个Server
│ ├─ CreateKubeAPIServer() 核心API Server
│ ├─ createAPIExtensionsServer() CRD扩展Server
│ └─ createAggregatorServer() 聚合层Server
├─ server.PrepareRun() 准备运行
└─ prepared.Run(stopCh) 启动服务 ← 阻塞在此
关键点:kube-apiserver的启动可以分为三个阶段:
- 准备阶段:参数解析、配置补全、参数校验
- 创建阶段:创建3个Server组成服务链
- 运行阶段:启动HTTP服务,阻塞等待
第一阶段:程序入口与命令创建
main函数:一切的开始
apiserver的入口在cmd/kube-apiserver/apiserver.go:
func main() {
// 初始化随机数种子
rand.Seed(time.Now().UnixNano())
// 设置pflag标准化函数(将_转换为-)
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
// 创建Cobra命令
command := app.NewAPIServerCommand()
// 初始化日志
logs.InitLogs()
defer logs.FlushLogs()
// 执行命令
if err := command.Execute(); err != nil {
os.Exit(1)
}
}
代码分析:
- 使用
rand.Seed初始化随机数(用于生成UUID等) - 使用
pflag替代标准库flag,支持POSIX风格长选项 SetNormalizeFunc将--some_flag自动转换为--some-flag- 使用
logs.InitLogs初始化klog日志系统
NewAPIServerCommand:构建Cobra命令树
func NewAPIServerCommand() *cobra.Command {
// 创建默认的ServerRunOptions
opts := options.NewServerRunOptions()
cmd := &cobra.Command{
Use: "kube-apiserver",
Long: `The Kubernetes API server validates and configures data...`,
// 持久化PreRun:设置前执行
PersistentPreRunE: func(*cobra.Command, []string) error {
// 静默client-go的warning(apiserver自己就是服务端,不需要warning)
rest.SetDefaultWarningHandler(rest.NoWarnings{})
return nil
},
// 核心Run函数
RunE: func(cmd *cobra.Command, args []string) error {
verflag.PrintAndExitIfRequested()
fs := cmd.Flags()
// 打印所有启动参数(便于调试)
cliflag.PrintFlags(fs)
// 检查不安全端口(已废弃,必须为0)
if err := checkNonZeroInsecurePort(fs); err != nil {
return err
}
// 补全配置(设置默认值)
completedOptions, err := Complete(opts)
if err != nil {
return err
}
// 校验参数
if errs := completedOptions.Validate(); len(errs) != 0 {
return utilerrors.NewAggregate(errs)
}
// 真正的启动!
return Run(completedOptions, genericapiserver.SetupSignalHandler())
},
}
// 绑定各种选项到命令行参数
opts.AddFlags(cmd.Flags())
return cmd
}
Cobra执行顺序回顾:
PersistentPreRun()
↓
PreRun()
↓
Run() ← 核心逻辑
↓
PostRun()
↓
PersistentPostRun()
第二阶段:参数处理与校验
1. 打印版本信息
verflag.PrintAndExitIfRequested()
如果用户传了--version,打印版本信息后退出:
$ kube-apiserver --version
Kubernetes v1.25.0
2. 打印启动参数
cliflag.PrintFlags(fs)
// 实际输出示例:
// FLAG: --advertise-address="192.168.1.100"
// FLAG: --etcd-servers="https://127.0.0.1:2379"
// FLAG: --secure-port="6443"
// ...
为什么要打印参数?
- 便于排查问题时确认实际使用的配置
- 日志审计需要
- 调试时快速确认参数是否生效
3. 检查不安全端口
func checkNonZeroInsecurePort(fs *pflag.FlagSet) error {
for _, name := range options.InsecurePortFlags {
val, err := fs.GetInt(name)
if err != nil {
return err
}
if val != 0 {
return fmt.Errorf("invalid port value %d: only zero is allowed", val)
}
}
return nil
}
背景:早期K8s支持非安全端口(HTTP),现在为了安全已废弃,必须为0。
4. Complete:补全配置
Complete函数负责填充配置的默认值:
func Complete(s *options.ServerRunOptions) (completedServerRunOptions, error) {
var options completedServerRunOptions
// 补全GenericServerRunOptions
if err := s.GenericServerRunOptions.DefaultAdvertiseAddress(s.SecureServing.SecureBindPort); err != nil {
return options, err
}
// 设置默认的ServiceClusterIPRange
if err := s.ServiceClusterIPRanges.Default("10.0.0.0/24"); err != nil {
return options, err
}
// 设置默认的ServiceNodePortRange
s.ServiceNodePortRange = options.DefaultServiceNodePortRange()
// 补全Etcd配置
if err := s.Etcd.Complete(storagebackend.Config{}, nil); err != nil {
return options, err
}
// 补全认证配置
if err := s.Authentication.Complete(); err != nil {
return options, err
}
// ... 还有很多其他配置
return options, nil
}
Common配置项:
| 配置项 | 说明 | 默认值 |
|---|---|---|
--advertise-address | 对外公告的地址 | 自动检测 |
--secure-port | HTTPS监听端口 | 6443 |
--etcd-servers | etcd集群地址 | 无(必须指定) |
--service-cluster-ip-range | Service VIP网段 | 10.0.0.0/24 |
--service-node-port-range | NodePort范围 | 30000-32767 |
5. Validate:参数校验
Validate函数对配置进行全面的合法性校验:
func (s *ServerRunOptions) Validate() []error {
var errs []error
// 校验MasterCount
if s.MasterCount <= 0 {
errs = append(errs, fmt.Errorf("--apiserver-count should be positive"))
}
// 校验Etcd配置
errs = append(errs, s.Etcd.Validate()...)
// 校验ClusterIP配置
errs = append(errs, validateClusterIPFlags(s)...)
// 校验NodePort范围
errs = append(errs, validateServiceNodePort(s)...)
// 校验API优先级和公平性
errs = append(errs, validateAPIPriorityAndFairness(s)...)
// 校验安全配置
errs = append(errs, s.SecureServing.Validate()...)
// 校验认证配置
errs = append(errs, s.Authentication.Validate()...)
// 校验鉴权配置
errs = append(errs, s.Authorization.Validate()...)
// 校验审计配置
errs = append(errs, s.Audit.Validate()...)
// 校验准入控制配置
errs = append(errs, s.Admission.Validate()...)
// 校验API启用配置
errs = append(errs, s.APIEnablement.Validate(...)...)
// ... 更多校验
return errs
}
校验示例:etcd配置校验
func (s *EtcdOptions) Validate() []error {
var allErrors []error
// 必须指定etcd地址
if len(s.StorageConfig.Transport.ServerList) == 0 {
allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified"))
}
// 校验存储后端类型
if s.StorageConfig.Type != storagebackend.StorageTypeUnset &&
!storageTypes.Has(s.StorageConfig.Type) {
allErrors = append(allErrors, fmt.Errorf("--storage-backend invalid"))
}
// 校验etcd-servers-overrides格式
for _, override := range s.EtcdServersOverrides {
tokens := strings.Split(override, "#")
if len(tokens) != 2 {
allErrors = append(allErrors, fmt.Errorf("--etcd-servers-overrides invalid"))
continue
}
// ... 更多校验
}
return allErrors
}
第三阶段:核心启动流程
Run函数:启动的入口
func Run(completeOptions completedServerRunOptions, stopCh <-chan struct{}) error {
// 打印版本信息
klog.Infof("Version: %+v", version.Get())
// 创建Server链(核心!)
server, err := CreateServerChain(completeOptions, stopCh)
if err != nil {
return err
}
// 准备运行
prepared, err := server.PrepareRun()
if err != nil {
return err
}
// 运行(阻塞)
return prepared.Run(stopCh)
}
StopCh:优雅关闭机制
stopCh用于接收系统信号,实现优雅关闭:
// 创建信号处理器
stopCh := genericapiserver.SetupSignalHandler()
// SetupSignalHandler的实现
func SetupSignalHandler() <-chan struct{} {
return SetupSignalContext().Done()
}
func SetupSignalContext() context.Context {
close(onlyOneSignalHandler) // 确保只调用一次
shutdownHandler = make(chan os.Signal, 2)
ctx, cancel := context.WithCancel(context.Background())
// 监听SIGTERM和SIGINT信号
signal.Notify(shutdownHandler, shutdownSignals...)
go func() {
// 第一次收到信号,取消context
<-shutdownHandler
cancel()
// 第二次收到信号,直接退出
<-shutdownHandler
os.Exit(1)
}()
return ctx
}
优雅关闭流程:
- 收到SIGTERM信号(如kubectl delete pod)
- 取消context,触发stopCh关闭
- HTTP服务器开始优雅关闭(停止接受新连接)
- 等待现有请求处理完成
- 清理资源,退出进程
第四阶段:创建Server链(核心!)
这是kube-apiserver启动最核心的部分——创建3个Server组成服务链。
func CreateServerChain(completedOptions completedServerRunOptions, stopCh <-chan struct{}) (*aggregatorapiserver.APIAggregator, error) {
// 1. 创建KubeAPIServer(核心API)
kubeAPIServerConfig, insecureServingInfo, serviceResolver, pluginInitializer, err :=
CreateKubeAPIServerConfig(completedOptions)
kubeAPIServer, err := CreateKubeAPIServer(
kubeAPIServerConfig,
apiExtensionsConfig.GenericConfig,
completedOptions.APIEnablement.AggregateAPILogger,
)
// 2. 创建APIExtensionsServer(CRD扩展)
apiExtensionsConfig, err := createAPIExtensionsConfig(...)
apiExtensionsServer, err := createAPIExtensionsServer(
apiExtensionsConfig,
kubeAPIServer.GenericAPIServer,
)
// 3. 创建AggregatorServer(API聚合层)
aggregatorConfig, err := createAggregatorConfig(...)
aggregatorServer, err := createAggregatorServer(
aggregatorConfig,
kubeAPIServer.GenericAPIServer,
apiExtensionsServer.Informers,
)
return aggregatorServer, nil
}
3个Server的职责
请求路径
│
▼
┌─────────────────────────────────────────────────────────────┐
│ AggregatorServer │
│ ├─ 路由/metrics → metrics-server │
│ ├─ 路由/custom.metrics.k8s.io → custom-metrics-server │
│ └─ 其他请求 → 转发到下一层 │
└──────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ APIExtensionsServer │
│ ├─ 路由/apis/apiextensions.k8s.io → 处理CRD │
│ └─ 其他请求 → 转发到下一层 │
└──────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ KubeAPIServer │
│ ├─ 路由/api/v1 → 核心API(Pod/Service/Node等) │
│ ├─ 路由/apis/apps/v1 → 应用API(Deployment/DaemonSet等) │
│ └─ 其他请求 → 返回404 │
└─────────────────────────────────────────────────────────────┘
1. KubeAPIServer:核心API服务
KubeAPIServer是K8s最核心的API服务,提供原生资源的管理能力:
func CreateKubeAPIServerConfig(opts completedServerRunOptions) (*master.Config, ...) {
// 创建GenericConfig(通用配置)
genericConfig := genericapiserver.NewConfig(legacyscheme.Codecs)
// 设置认证、鉴权、审计等配置
genericConfig.Authentication = opts.Authentication.ToAuthenticationConfig()
genericConfig.Authorization = opts.Authorization.ToAuthorizationConfig()
genericConfig.AuditBackend = opts.Audit.NewBackend()
// 设置存储配置(etcd)
storageFactory, err := opts.Etcd.CreateStorageFactory()
// 创建Master配置
config := &master.Config{
GenericConfig: genericConfig,
ExtraConfig: master.ExtraConfig{
StorageFactory: storageFactory,
APIResourceConfigSource: opts.APIEnablement,
// ... 其他配置
},
}
return config, nil
}
KubeAPIServer提供的API:
| 路径 | 说明 | 示例资源 |
|---|---|---|
/api/v1 | 核心API | Pod、Service、Node、Namespace |
/apis/apps/v1 | 应用API | Deployment、StatefulSet、DaemonSet |
/apis/networking.k8s.io/v1 | 网络API | Ingress、NetworkPolicy |
/apis/rbac.authorization.k8s.io/v1 | RBAC API | Role、RoleBinding、ClusterRole |
2. APIExtensionsServer:CRD扩展服务
APIExtensionsServer提供CustomResourceDefinition(自定义资源定义)的能力:
func createAPIExtensionsServer(
apiExtensionsConfig *apiextensionsapiserver.Config,
delegateAPIServer genericapiserver.DelegationTarget,
) (*apiextensionsapiserver.CustomResourceDefinitions, error) {
// 创建APIExtensions服务器
server, err := apiExtensionsConfig.Complete().New(delegateAPIServer)
if err != nil {
return nil, err
}
return server, nil
}
CRD的作用:
- 允许用户自定义K8s资源类型
- 不需要修改apiserver代码就能扩展API
- Operator的基础
3. AggregatorServer:API聚合层
AggregatorServer是K8s API聚合层的实现,允许将第三方API服务注册到K8s API中:
func createAggregatorServer(
aggregatorConfig *aggregatorapiserver.Config,
delegateAPIServer genericapiserver.DelegationTarget,
apiExtensionInformers apiextensioninformers.SharedInformerFactory,
) (*aggregatorapiserver.APIAggregator, error) {
// 创建Aggregator服务器
aggregatorServer, err := aggregatorConfig.Complete().NewWithDelegate(delegateAPIServer)
if err != nil {
return nil, err
}
return aggregatorServer, nil
}
Aggregator的应用场景:
| 服务 | 说明 | API路径 |
|---|---|---|
| metrics-server | 资源指标(CPU/内存) | /apis/metrics.k8s.io |
| custom-metrics-server | 自定义指标(业务指标) | /apis/custom.metrics.k8s.io |
| external-metrics-server | 外部指标(云服务指标) | /apis/external.metrics.k8s.io |
| service-catalog | 服务目录 | /apis/servicecatalog.k8s.io |
第五阶段:准备与运行
PrepareRun:启动前的最后准备
func (s *APIAggregator) PrepareRun() (preparedAPIAggregator, error) {
// 准备GenericAPIServer
genericPrepared, err := s.GenericAPIServer.PrepareRun()
if err != nil {
return preparedAPIAggregator{}, err
}
// 注册控制器
// ...
return preparedAPIAggregator{
APIAggregator: s,
GenericAPIServer: genericPrepared,
}, nil
}
Run:启动HTTP服务
func (s preparedAPIAggregator) Run(stopCh <-chan struct{}) error {
// 启动GenericAPIServer(阻塞)
return s.GenericAPIServer.Run(stopCh)
}
// GenericAPIServer.Run
func (s *GenericAPIServer) Run(stopCh <-chan struct{}) error {
// 启动HTTP/HTTPS服务
// ...
// 阻塞等待stopCh
<-stopCh
// 优雅关闭
return nil
}
启动流程总结
┌────────────────────────────────────────────────────────────────┐
│ kube-apiserver启动流程 │
├────────────────────────────────────────────────────────────────┤
│ Phase 1: 程序入口 │
│ ├─ main() │
│ ├─ NewAPIServerCommand() 创建Cobra命令 │
│ └─ Execute() 执行 │
├────────────────────────────────────────────────────────────────┤
│ Phase 2: 参数处理 │
│ ├─ PersistentPreRunE() 设置WarningHandler │
│ ├─ PrintFlags() 打印启动参数 │
│ ├─ checkNonZeroInsecurePort() 检查不安全端口 │
│ ├─ Complete() 补全配置默认值 │
│ └─ Validate() 校验参数合法性 │
├────────────────────────────────────────────────────────────────┤
│ Phase 3: Server链创建(核心) │
│ ├─ CreateKubeAPIServerConfig() 创建核心API配置 │
│ ├─ CreateKubeAPIServer() 创建核心API服务器 │
│ ├─ createAPIExtensionsServer() 创建CRD扩展服务器 │
│ └─ createAggregatorServer() 创建聚合层服务器 │
├────────────────────────────────────────────────────────────────┤
│ Phase 4: 启动服务 │
│ ├─ PrepareRun() 准备运行 │
│ ├─ Run() 启动HTTP服务 │
│ └─ <-stopCh 阻塞等待关闭信号 │
└────────────────────────────────────────────────────────────────┘
踩坑实录:apiserver启动常见问题
坑1:etcd连接失败
现象:apiserver启动报错,--etcd-servers must be specified或连接超时
根因:
- 没有指定etcd地址
- etcd证书配置错误
- 网络不通
解决方案:
# 检查etcd是否运行
etcdctl endpoint health --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/ca.crt \
--cert=/etc/etcd/etcd.crt \
--key=/etc/etcd/etcd.key
# 检查apiserver启动参数
kube-apiserver \
--etcd-servers=https://192.168.1.100:2379,https://192.168.1.101:2379 \
--etcd-cafile=/etc/etcd/ca.crt \
--etcd-certfile=/etc/etcd/apiserver-etcd-client.crt \
--etcd-keyfile=/etc/etcd/apiserver-etcd-client.key
坑2:端口冲突
现象:报错bind: address already in use
根因:6443端口被其他进程占用
解决方案:
# 查找占用端口的进程
sudo lsof -i :6443
# 或者使用netstat
sudo netstat -tlnp | grep 6443
# 修改apiserver监听端口(不推荐,最好释放端口)
kube-apiserver --secure-port=6444
坑3:证书问题
现象:TLS握手失败,证书验证错误
根因:
- 证书过期
- 证书CN/SAN不匹配
- 证书链不完整
解决方案:
# 检查证书有效期
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates
# 检查证书SAN
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A5 "Subject Alternative Name"
坑4:Aggregator初始化卡住
现象:apiserver日志显示aggregator相关错误,服务无法就绪
根因:AggregatorServer初始化时需要连接metrics-server,如果metrics-server不可用会卡住
解决方案:
# 检查metrics-server状态
kubectl get pods -n kube-system | grep metrics-server
# 暂时禁用Aggregator(开发测试环境)
kube-apiserver --enable-aggregator-routing=false
坑5:内存/CPU不足
现象:apiserver启动后OOM或被系统kill
根因:资源限制太小,etcd数据量大
解决方案:
# 如果是容器化部署,增加资源限制
resources:
limits:
cpu: "2000m"
memory: "2Gi"
requests:
cpu: "500m"
memory: "512Mi"
调试技巧:如何跟踪启动流程
1. 使用-v参数查看详细日志
# -v=0: 默认
# -v=2: 重要信息
# -v=4: 详细信息
# -v=6: HTTP请求详情
# -v=8: 完整HTTP内容
kube-apiserver -v=6
2. 查看启动参数
# 查看apiserver进程启动参数
ps aux | grep kube-apiserver
# 或者查看静态Pod配置
cat /etc/kubernetes/manifests/kube-apiserver.yaml
3. 使用pprof分析启动性能
# 启用pprof
kube-apiserver --profiling=true
# 采集CPU profile
curl http://localhost:8080/debug/pprof/profile > cpu.pprof
下一步学习路线
理解了apiserver启动流程后,建议按以下路线继续深入学习:
- HTTP服务启动:GenericAPIServer如何启动HTTP/HTTPS服务
- 认证鉴权链:请求如何经过认证→鉴权→准入控制
- RESTful路由:请求如何路由到对应的handler
- etcd存储:资源如何序列化并存储到etcd
- watch机制:如何实现资源变化的长连接通知
总结
通过本篇源码分析,我们完整了解了kube-apiserver的启动流程:
- 程序入口:main → NewAPIServerCommand → Execute
- 参数处理:PrintFlags → Complete → Validate
- Server链创建:KubeAPIServer → APIExtensionsServer → AggregatorServer
- 服务启动:PrepareRun → Run → 阻塞等待
核心设计:
- 使用Cobra框架处理命令行
- 三阶段模式(Complete→Validate→Run)
- 三层Server架构(核心→扩展→聚合)

1171

被折叠的 条评论
为什么被折叠?



