kubernetes/dashboard源码分析

16 篇文章 0 订阅

from https://www.gitbook.com/book/fanux/k8s-source-code/details

dashbodard采用前后端分离设计,前端是使用angular的单页应用,用ES6编写,后端使用go语言的go-restful框架当作http服务器。本文以介绍后端为主。

架构图

 

客户端通过浏览器发送请求给Backend,Backend使用k8s的restful api操作kubernetes资源和获取集群信息。

目录结构

</kubernetes/dashboard/        
▸ build/                      
▸ docs/                     
▸ i18n/                       
▾ src/                         
  ▾ app/                       
    ▸ assets/                 
    ▸ backend/          --->后端的代码目录           
    ▸ externs/              
    ▸ frontend/               
  ▸ deploy/                  
  ▸ test/                      
▸ vendor/

主要关心的几个目录:

    ▾ backend/                                                                                 
      ▾ client/                           -->访问k8s的客户端                 
          apiserverclient.go    
          heapsterclient.go    
      ▾ handler/                          -->http server handler            
          apihandler.go                                                   
          confighandler.go   
          gziphandler.go                                                     
          localehandler.go                       
      ▸ resource/                        -->具体操作资源的方法,如获取pods列表     
      ▸ validation/                                                   
        dashboard.go                     -->main入口

主要流程分析

func main() {
    //......忽略忽略忽略
    http.Handle("/api/", handler.CreateHTTPAPIHandler(apiserverClient, heapsterRESTClient, config))
    //......忽略忽略忽略
    log.Print(http.ListenAndServe(fmt.Sprintf(":%d", *argPort), nil))
}

main里面启动了一个http服务器。 (ps:go的http.Handle第一个参数是一个url,第二个参数是一个接口,任何实现了 ServeHTTP(ResponseWriter, *Request)方法的对象都可以作为入参数)

我们看一下CreateHTTPAPIHandler的逻辑:

func CreateHTTPAPIHandler(client *clientK8s.Client, heapsterClient client.HeapsterClient,
    clientConfig clientcmd.ClientConfig) http.Handler {
    //......忽略忽略忽略
    /*这里以获取pod列表为例来看其流程*/
    apiV1Ws.Route(
        apiV1Ws.GET("/pod").
            To(apiHandler.handleGetPods).
            Writes(pod.PodList{}))
    //......忽略忽略忽略 
}

这个部分使用了go-restful框架,一个非常好的开发restful api的库,kubernetes本身也是用的这个库。 To方法给定一个处理前端请求的方法

func (apiHandler *APIHandler) handleGetPods(
    request *restful.Request, response *restful.Response) {

    result, err := pod.GetPodList(apiHandler.client, apiHandler.heapsterClient, namespace, dataSelect)

    response.WriteHeaderAndEntity(http.StatusCreated, result)
}

这个handler里面调用了resource下面的pod资源管理器,讲结果写到响应中。再看pod.GetPodList具体实现:

func GetPodList(client k8sClient.Interface, heapsterClient client.HeapsterClient,
    nsQuery *common.NamespaceQuery, dsQuery *common.DataSelectQuery) (*PodList, error) {

    channels := &common.ResourceChannels{
        PodList: common.GetPodListChannelWithOptions(client, nsQuery, api.ListOptions{}, 1), 
    }   

    //从通道中获取pod列表
    return GetPodListFromChannels(channels, dsQuery, heapsterClient)
}

继续看common.GetPodListChannelWithOptions:

func GetPodListChannelWithOptions(client client.PodsNamespacer, nsQuery *NamespaceQuery,
    options api.ListOptions, numReads int) PodListChannel {

    //创建了两个管道,一个存放pod列表,一个存放错误信息。
    channel := PodListChannel{
        List:  make(chan *api.PodList, numReads),
        Error: make(chan error, numReads),
    }   

    //创建一个协程,将获取到的pod列表信息写入通道中
    go func() {
        list, err := client.Pods(nsQuery.ToRequestParam()).List(options)
        var filteredItems []api.Pod
        for _, item := range list.Items {
            if nsQuery.Matches(item.ObjectMeta.Namespace) {
                filteredItems = append(filteredItems, item)
            }   
        }   
        list.Items = filteredItems
        for i := 0; i < numReads; i++ {
            channel.List <- list
            channel.Error <- err 
        }   
    }() 

    return channel
}

现在主要流程走完了,但是还是不知道在哪去请求kubernetes api server的。所以现在的关键点就在于协程中的client具体传入的是哪个对象,最终执行的是它的Pods().List()方法。

先看一下Pod接口:

type PodsNamespacer interface {
    Pods(namespace string) PodInterface
}

type PodInterface interface {
    List(opts api.ListOptions) (*api.PodList, error)
    Get(name string) (*api.Pod, error)
    Delete(name string, options *api.DeleteOptions) error
    Create(pod *api.Pod) (*api.Pod, error)
    Update(pod *api.Pod) (*api.Pod, error)
    Watch(opts api.ListOptions) (watch.Interface, error)
    Bind(binding *api.Binding) error
    UpdateStatus(pod *api.Pod) (*api.Pod, error)
    GetLogs(name string, opts *api.PodLogOptions) *restclient.Request
}

所以,只要找到具体的client实例,并看它实现的Pods方法即可。

在APIHandler.handleGetPods()函数中我们可以看到传入的client是apiHandler.client,再看APIHanler结构体

type APIHandler struct {
    client         *clientK8s.Client
    heapsterClient client.HeapsterClient
    clientConfig   clientcmd.ClientConfig
    verber         common.ResourceVerber
}

所以,最终的client是clientK8s.Client

type Client struct {
    *restclient.RESTClient
    *AutoscalingClient
    *AuthenticationClient
    *BatchClient
    *ExtensionsClient
    *AppsClient
    *PolicyClient
    *RbacClient
    *discovery.DiscoveryClient
    *CertificatesClient
}

我们猜想Client肯定有一个Pods方法,事实证明确实有:

func (c *Client) Pods(namespace string) PodInterface {                            
    return newPods(c, namespace)
}

再看newPods方法:

type pods struct {
    r  *Client
    ns string
}

func newPods(c *Client, namespace string) *pods {
    return &pods{
        r:  c,                    //http客户端
        ns: namespace,
    }   
}

所以说,最最终调用的是pods结构体的List方法。

func (c *pods) List(opts api.ListOptions) (result *api.PodList, err error) {
    result = &api.PodList{}
    err = c.r.Get().Namespace(c.ns).Resource("pods").VersionedParams(&opts, api.ParameterCodec).Do().Into(result)
    return
}

真相开始浮出水面:

err = c.r.Get()\                                  -->设置了请求的http方法为GET
.Namespace(c.ns).\                                -->设置请求的namespace
Resource("pods").\                                -->设置资源为pods
VersionedParams(&opts, api.ParameterCodec).\      -->添加版本参数
Do().\                                            -->发送http请求
Into(result)                                      -->讲结果写入result

我们再找一下在哪构造的url和发送的http请求,着重看.Do()函数干啥了:

func (r *Request) Do() Result {
    r.tryThrottle()

    var result Result
    err := r.request(func(req *http.Request, resp *http.Response) {
        result = r.transformResponse(resp, req) 
    })   
    //...
    return result
}

//request函数主要逻辑:
func (r *Request) request(fn func(*http.Request, *http.Response)) error {
    //设置http方法等
    //这里有个多次请求的逻辑,一次请求失败了睡眠一下继续请求,请求次数不超过maxRetries次默认为10次
    for {
        url := r.URL().String()    //URL方法根据之前设置的pods namespace等参数构造url
        //其它逻辑忽略,最终将请求发送给api server
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kubernetes DashboardKubernetes 官方提供的一个 Web 界面,用于管理 Kubernetes 集群。以下是部署 Kubernetes Dashboard 的步骤: 1. 下载 Kubernetes Dashboard YAML 文件: ```bash curl -LO https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml ``` 2. 修改 Kubernetes Dashboard Service 类型: 将 recommended.yaml 文件中的 Service 类型从 ClusterIP 修改为 NodePort,这样可以通过 Node 的 IP 地址加端口号访问 Kubernetes Dashboard。 ```yaml apiVersion: v1 kind: Service metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard labels: k8s-app: kubernetes-dashboard spec: type: NodePort # 将类型修改为 NodePort ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard ``` 3. 部署 Kubernetes Dashboard: ```bash kubectl apply -f recommended.yaml ``` 4. 创建 Service Account: ```bash cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard EOF ``` 5. 创建 Cluster Role Binding: ```bash cat <<EOF | kubectl apply -f - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard EOF ``` 6. 获取 Token: ```bash kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') ``` 7. 访问 Kubernetes Dashboard: 使用浏览器访问 Node 的 IP 地址加端口号,输入 Token 登录即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值