组件概述
Kubernetes API Server 通过名为 kube-apiserver 进程提供服务,它的核心功能是提供集群管理 RESTful API 接口,将 API 操作的对象存储到持久化存储到 ETCD 后端,本质是集群中所有用户和组件的数据交互中心。
架构解析
Kubernetes API Server 从上到下可以分为四层:接口层,访问控制层,注册表层和数据库层。
API 层
Kube Core API Server 核心接口服务器
负责对请求的一些通用处理,认证、鉴权等,以及处理各个内建资源的 REST 服务。
API Extensions Server 可扩展接口服务器
主要处理 CustomResourceDefinition(CRD)和 CustomResource(CR)的 REST 请求,也是 Delegation 的最后一环,如果对应 CR 不能被处理的话则会返回 404。
Aggregator Server 聚合服务器
暴露的功能类似于一个七层负载均衡,将来自用户的请求拦截转发给其他服务器,并且负责整个 APIServer 的 Discovery 功能。
访问控制层
访问控制层对用户进行身份鉴权,然后根据配置的各种访问许可逻辑(Admission Controller),判断是否允许访问。当请求到达 kube-apiserver 时,kube-apiserver 首先会执行在 http filter chain 中注册的过滤器链,该过滤器对其执行一系列过滤操作,主要有认证、鉴权等检查操作。
我们以请求正向的方式进行分析,API Server 监听端口的 HTTP 请求会首先打到 FullHandlerChain。
1
2
3
|
func (a *APIServerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
a.FullHandlerChain.ServeHTTP(w, r)
}
|
FullHandlerChain 是由 DefaultBuildHandlerChain 实际构建出来的处理链。
1
2
3
4
5
|
// staging/src/k8s.io/apiserver/pkg/server/config.go
// filter chain 处理链的注册函数
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
handler := genericapifilters.WithAuthorization(apiHandler, c.Authorization.Authorizer, c.Serializer)
}
|
上面代码片段中的 apiHandler 是 director 对象,所以 filter 结束会进入 director 的 http.Handler。导向器 director 根据初始化的配置,如果 goRestfulContainer 的 WebServices 的 RootPath 中是 /apis
,或者请求前缀与 RootPath 匹配,则进入 Restful 处理链路,否则进入非 Restful 处理链路。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
func (d director) ServeHTTP(w http.ResponseWriter, req *http.Request) {
path := req.URL.Path
for _, ws := range d.goRestfulContainer.RegisteredWebServices() {
switch {
case ws.RootPath() == "/apis":
// ...
d.goRestfulContainer.Dispatch(w, req)
return
case strings.HasPrefix(path, ws.RootPath()):
// ...
d.goRestfulContainer.Dispatch(w, req)
return
}
}
d.nonGoRestfulMux.ServeHTTP(w, req)
}
|
注册表层
Kubernetes 把所有资源都保存在注册表(Registry)中,针对注册表中的各种资源对象,都定义了相应的资源对象类型,以及如何创建资源,转换不同版本的资源,编码解码资源。
InstallREST 函数在启动时候就已经把路由注册进 goRestfulContainer 中,进入 Dispatch 分发路由,会路由到不同的 endpoint handler 中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// k8s.io/apiserver/pkg/endpoints/groupversion.go
// 注册路由位置
func (g *APIGroupVersion) InstallREST(container *restful.Container) error {
prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version)
installer := &APIInstaller{
group: g,
prefix: prefix,
minRequestTimeout: g.MinRequestTimeout,
}
apiResources, ws, registrationErrors := installer.Install()
versionDiscoveryHandler := discovery.NewAPIVersionHandler(g.Serializer, g.GroupVersion, staticLister{apiResources})
versionDiscoveryHandler.AddToWebService(ws)
container.Add(ws)
return utilerrors.NewAggregate(registrationErrors)
}
|
1
2
3
4
|
type DryRunnableStorage struct {
Storage storage.Interface
Codec runtime.Codec
}
|
ETCD 数据库
通过 KV 持久化存储 Kubernetes 对象,API Server 就是利用 ETCD 的 Watch 特性实现了经典 List-Watch 机制。
流程剖析
Create Pod 流程
当使用 kubectl 运行创建 Pod 的命令,按下回车键以后 kubectl 会先执行一些客户端验证操作,然后封装 HTTP 请求。建立 TLS 建立连接后,会进行认证处理。如果请求认证失败,则请求被拒绝,返回 401 状态码。如果认证成功,则被认证为具体的 username,该用户名可供随后的步骤中使用。,客户端认证方式支持如下:
- x509 客户端证书;
- Bearer Token;
- 基于用户名密码的基本认证;
- OpenID 认证。
认证成功后,会进行授权处理。Kubernetes 支持多种授权模块,例如 ABAC 模式,RBAC 模式和 Webhook 模式。管理员创建集群时,会配置 API 服务器应用的授权模块。如果多种授权模式同时被启用,Kubernetes 将检查所有模块,如果其中一种通过授权,则请求授权通过。如果所有的模块全部拒绝,则请求被拒绝(HTTP 状态码 403)。
然后进入准入控制处理流程,准入控制模块是能够修改或拒绝请求的软件模块。作为授权模块的补充,准入控制模块会访问被创建或更新的对象的内容。它们作用于对象的创建,删除,更新和连接(proxy)阶段,但不包括对象的读取。与认证和授权模块不同的是,如果任一个准入控制器拒绝请求,那么整个请求会立即被拒绝。除了拒绝请求外,准入控制器还可以为对象设置复杂的默认值。
一旦请求通过所有准入控制器,将使用对应 API 对象的验证流程对其进行验证,然后写入对象存储。
Watch Pod 流程
在 Watch 在进度到注册表层时,前面经过的流程和创建流程一样。首先会解析资源版本,等待 Cacher 对象 ready,通过 newCacheWatcher 初始化对象,进入 Watch 流程。Kubernetes 为了避免后端存储压力,通过缓存资源数据,避免每次都从后端获取,watchCache 是一个固定大小的用于监测缓存数据变化的数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
func newCacheWatcher(chanSize int, filter filterWithAttrsFunc, forget func(), versioner storage.Versioner, deadline time.Time, allowWatchBookmarks bool, objectType reflect.Type) *cacheWatcher {
return &cacheWatcher{
input: make(chan *watchCacheEvent, chanSize),
result: make(chan watch.Event, chanSize),
done: make(chan struct{}),
filter: filter,
stopped: false,
forget: forget,
versioner: versioner,
deadline: deadline,
allowWatchBookmarks: allowWatchBookmarks,
objectType: objectType,
}
}
|
以下代码块是启动 goroutine 进入处理流程,process 接收 input chan 对象中的信息。
1
2
3
4
5
6
7
8
9
10
11
12
|
func (c *Cacher) Watch(ctx context.Context, key string, resourceVersion string, pred storage.SelectionPredicate) (watch.Interface, error) {
// ...
func() {
// ...
c.watchers.addWatcher(watcher, c.watcherIdx, triggerValue, triggerSupported)
c.watcherIdx++
// ...
}()
// ...
go watcher.process(ctx, initEvents, watchRV)
// ...
}
|
Cacher 初始化的时候会启动,在 dispatchEvents 函数中将每个事件分发到 cacheWatcher 之中。
1
2
3
|
type Cacher struct {
incoming chan watchCacheEvent
}
|
扩展文档
启动参数
--client-ca-file
请求到达 Kubernetes API Server 时检查请求的证书。如果它是由 –client-ca-file 引用的文件中的 CA 证书之一签名的,并且用户是公用名 CN=
的值,而组是组织 O=
的取值,则该请求被视为合法请求。请参阅关于 TLS 身份验证的文档。
--service-account-key-file
参数将对应的公钥传入 kube-apiserver。公钥用于认证过程中的 token 校验。
--kubelet-certificate-authority
给 apiserver 提供一个根证书捆绑,用于 kubelet 的服务证书。
经典代码
1
2
3
4
|
// staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go
// GenericAPIServer 是构造出来的 API Server 对象
type GenericAPIServer struct {
}
|
1
2
3
4
5
6
7
8
9
10
11
|
// staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go
// 完成启动流程
func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
// ...
if s.SecureServingInfo != nil && s.Handler != nil {
// ...
stoppedCh, err = s.SecureServingInfo.Serve(s.Handler, s.ShutdownTimeout, internalStopCh)
// ...
}
// ...
}
|
1
2
3
4
|
// cmd/kube-apiserver/app/options/options.go
// NewServerRunOptions 构造了服务运行所有的对象
func NewServerRunOptions() *ServerRunOptions {
}
|
1
2
|
# 实现具体存储的接口
pkg/storage/etcd3/store.go
|
1
2
3
4
5
|
# Admission Controller 的具体实现位置
k8s.io/apiserver/pkg/admission/initializer/initializer.go
# Admission Controller 各个策略的实现位置
plugin/pkg/admission/*
|