kube-apiserver 核心实现 (一)

一、概述

kube-apiserver 组件负责将 kubernetes 的 “资源组,资源版本,资源” 以RESTful 风格的形式对外暴露服务。也是 kubernetes集群中各组件之间沟通的桥梁。

以在 kubernetes 集群中一个 pod 资源对象创建流程为例,如图:

pod-creating-process.png

Kubernetes Pod 资源对象创建流程如下:

  1. 使用 kubectl 工具向 API server 发起创建 Pod 资源对象的请求,在这个过程中会经过一系列的权限认证,包括客户端的认证,rbac 权限检查和 Pod 配置中字段的验证与默认值设置。
  2. API server 验证请求并将其持久保存到 ETCD 集群中。
  3. API server 基于 Watch 机制通知 kube-scheduler 调度器。
  4. kube-scheduler 调度器根据预选,优选调度算法为 Pod 资源对象选择最优的节点并通知 API server。
  5. API server 将最优节点的配置持久化保存到 Etcd 集群中。
  6. kubelet 组件在所在节点上通过与容器运行时交互创建容器。
  7. kubelet 将容器状态上报至 api server。
  8. API server 将容器状态持久化到 Etcd 集群中。

二、go-restful 核心原理

go-restful (https://github.com/emicklei/go-restful)

2. 1 go-restful 介绍

在 kubernetes 源码中使用了 go-restful 框架,主要原因在于 go-restful 框架可定制程度高,go-restful 设计逻辑如图:

go-restful-workflow.png

go-restful 框架支持多个 container,对应着一个 Http server, 每个 container 可以包含多个 web service, web service 就是多个不同类别服务的集合。一个 web service 包含多个 route, 当请求的 url 匹配到相应 route 就会执行该 route 对应的处理函数(handler func)

Note: go-restful 框架中的 Container, 并非指 Docker 容器,仅是 go-resful 框架中的定义。

2.2 go-restful 数据结构与原理

go-restful 核心数据结构如下:

go-restful-datastruct.png

核心原理即将 Container 接收的请求分发匹配的 WebService,再由 WebService 分发给 Router 中的 Handle 函数。

代码示例:

// Dispatch the incoming Http Request to a matching WebService.
func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
	...
	// Find best match Route ; err is non nil if no match was found
	var webService *WebService
	var route *Route
	var err error
	func() {
		c.webServicesLock.RLock()
		defer c.webServicesLock.RUnlock()
		webService, route, err = c.router.SelectRoute(
			c.webServices,
			httpRequest)
	}()
    ...
		// no filters, handle request by route
		route.Function(wrappedRequest, wrappedResponse)
	}
	...
}

dispatch 函数进行分发的过程分为两步:

  1. 使用 c.router.SelectRoute 方法,根据请求匹配到最优的 WebServiceroute组合(?WebService->?route,其中包含两种 RouterSelector, 分别是 RouterJSR311 和 CurlyRouter, CurlyRouter 是基于 RouterJSR311 实现的,在其基础上支持正则表达式和动态参数。go-restful 框架默认使用 CurlyRouter
  2. 根据请求路径调用对应的 Handler 函数,执行 route.Function 函数。

2.3 示例代码

package main

import (
	"io"
	"log"
	"net/http"

	restful "github.com/emicklei/go-restful/v3"
)

func main() {
    // 实例化 WebService
	ws := new(restful.WebService)
    // 为 WebService 定义一条 route, 在 route 中指定请求方法
    // 路径、请求路径,和 Handler 函数
	ws.Route(ws.GET("/hello").To(hello1))
	restful.Add(ws)
	go func() {
		log.Fatal(http.ListenAndServe(":8080", nil))
	}()

    // 实例化 Container
	container2 := restful.NewContainer()
	ws2 := new(restful.WebService)
	ws2.Route(ws2.GET("/hello").To(hello2))
    // 添加 WebService 到 Container 中
	container2.Add(ws2)
	server := &http.Server{
		Addr:    ":8081",
		Handler: container2,
	}
	log.Fatal(server.ListenAndServe())
}

// Handler 函数方法接收 request 和 response,并与用户进行数据交互
func hello1(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "default world\n")
}

func hello2(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "second world\n")
}

在 main 函数中如果未实例化 Container, 那么默认会使用 restful.DefaultContainerDefaultServeMux,可以通过 restful.NewContainer() 函数来创建一个 container, 如上代码所示。

运行上述程序,将会监控 80808081 两个端口,当我们发送 GET 请求到 http://localhost:8080/hello时,会返回 default world, 而 http://localhost:8081/hello 会返回 second world

三 访问 API server 一次 HTTP 请求的完整周期

如图:

apiserver-request-process.png

一次 Http 请求的完整周期:

  1. 用户向 API server 发出 Http 请求
  2. API server 接收到用户发出的请求
  3. API server 启用 goroutine 处理接收到的请求
  4. API server 验证请求内容中的认证信息
  5. API server 解析请求内容
  6. API server 调用路由条目对应的处理函数
  7. API server 获取经Handler处理过的的数据信息
  8. API server 设置请求状态码
  9. API server 响应用户的请求
posted @   木冉96  阅读(227)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示