kubelet 的工作流程

作者: shinwing | 来源:发表于2018-05-09 11:41 被阅读0次

    简介

    kubernetes 是一个分布式的集群管理系统,在每个节点(node)上都要运行一个 worker 对容器进行生命周期的管理,这个 worker 程序就是 kubelet。

    简单地说,kubelet 的主要功能就是定时从某个地方获取节点上 pod/container 的期望状态(运行什么容器、运行的副本数量、网络或者存储如何配置等等),并调用对应的容器平台接口达到这个状态。

    kubelet 除了这个最核心的功能之外,还有很多其他特性:

        * 定时汇报当前节点的状态给 apiserver,以供调度的时候使用

        * 镜像和容器的清理工作,保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源

        * 运行 HTTP Server,对外提供节点和 pod 信息,如果在 debug 模式下,还包括调试信息

        * 等等……

    集群状态下,kubelet 会从 master 上读取信息,但其实 kubelet 还可以从其他地方获取节点的 pod 信息。目前 kubelet 支持三种数据源:

        * 本地文件

        * 通过 url 从网络上某个地址来获取信息

        * API Server:从 kubernetes master 节点获取信息

    从管理的对象来说,kubelet 目前支持dockerrkt,默认情况下使用的 docker。

    kubelet 主要功能

    Pod 管理

    在 kubernetes 的设计中,最基本的管理单位是 pod,而不是 container。pod 是 kubernetes 在容器上的一层封装,由一组运行在同一主机的一个或者多个容器组成。如果把容器比喻成传统机器上的一个进程(它可以执行任务,对外提供某种功能),那么 pod 可以类比为传统的主机:它包含了多个容器,为它们提供共享的一些资源。

    之所以费功夫提供这一层封装,主要是因为容器推荐的用法是里面只运行一个进程,而一般情况下某个应用都由多个组件构成的。

    pod 中所有的容器最大的特性也是最大的好处就是共享了很多资源,比如网络空间。pod 下所有容器共享网络和端口空间,也就是它们之间可以通过 localhost 访问和通信,对外的通信方式也是一样的,省去了很多容器通信的麻烦。

    除了网络之外,定义在 pod 里的 volume 也可以 mount 到多个容器里,以实现共享的目的。

    最后,定义在 pod 的资源限制(比如 CPU 和 Memory) 也是所有容器共享的。

    容器健康检查

    创建了容器之后,kubelet 还要查看容器是否正常运行,如果容器运行出错,就要根据设置的重启策略进行处理。检查容器是否健康主要有三种方式:执行命令,http Get,和tcp连接。

    不管用什么方式,如果检测到容器不健康,kubelet 会删除该容器,并根据容器的重启策略进行处理(比如重启,或者什么都不做)。

    容器监控

    kubelet 还有一个重要的责任,就是监控所在节点的资源使用情况,并定时向 master 报告。知道整个集群所有节点的资源情况,对于 pod 的调度和正常运行至关重要。

    kubelet 使用 cAdvisor 进行资源使用率的监控。cAdvisor 是 google 开源的分析容器资源使用和性能特性的工具,在 kubernetes 项目中被集成到 kubelet 里,无需额外配置。默认情况下,你可以在 localhost:4194 地址看到 cAdvisor 的管理界面。

    除了系统使用的 CPU,Memory,存储和网络之外,cAdvisor 还记录了每个容器使用的上述资源情况。

    代码分析

    入口程序

    cmd/kublet/kubelet.go  -->  main 方法

    1. 创建kubeletFlags数据结构(对应kubelet命令行参数);

    2. 创建kubeletConfigration数据结构;

    3. 创建kubeletServer数据结构,此数据结构包括kubeletFlags、kubeletConfigration;

    4. 启动kubelet Configuration controller,此功能开始配置和状态的循环同步;

    // 创建一个配置控制器BootstrapKubeletConfigController(defaultConfig*kubeletconfiginternal.KubeletConfiguration,dynamicConfigDir string) {

         c := dynamickubeletconfig.NewController(defaultConfig, dir)

        // 读取默认配置,并启动一个goroutine来更新

        kc, err := c.Bootstrap()

        return kc, c, nil

    }

    5. 创建kubeletDeps数据结构;

    kubeletDeps 的名字听起来很奇怪,其实它内部保存了 kubelet 各个重要组件的对象,之所以要把它作为参数传递,是为了实现 dependency injection。简单地说,就是把 kubelet 依赖的组件对象作为参数传进来,这样可以控制 kubelet 的行为。比如在测试的时候,只要构建 fake 的组件实现,就能很轻松进行测试。KubeDeps 包含的组件很多,下面列出一些:

    CAdvisorInterface:提供 cAdvisor 接口功能的组件,用来获取监控信息

    DockerClientConfig:docker 客户端,用来和 docker 交互

    KubeClient:apiserver 客户端,用来和 api server 通信

    Mounter:执行 mount 相关操作

    NetworkPlugins:网络插件,执行网络设置工作

    VolumePlugins:volume 插件,执行 volume 设置工作

    TLSOptions:检查或者生成自签名证书和密钥文件。


    启动程序

    cmd/kubelet/app/server.go   -->  Run 方法

    1. 判断kubelet是否以standalone模式运行;

    2. 创建对象kubeClient、evnetClient,用来和 apiserver 通信。 heartbeatClient、externalkubeClient、ContainerManager;并设置OOM。

    3. 调用RunKubelet。 运行 kubelet,这个函数会启动 goroutine 一直运行,是 kubelet 核心功能执行的地方。

    RunKubelet(&s.KubeletFlags, &s.KubeletConfiguration, kubeDeps, s.RunOnce) {

        // 1. 初始化各个对象,比如 eventBroadcaster,这样就能给 apiserver 发送事件了

        makeEventRecorder(kubeDeps, nodeName)

    ……

        // 2. 通过 builder 创建并初始化Kubelet

        builder := kubeDeps.Builder

        if builder == nil {

            builder = CreateAndInitKubelet

        }

        调用builder(......)

        // 3. 根据运行模式,运行 Kubelet

        startKubelet(k, podCfg, kubeCfg, kubeDeps)

    }

    相关文章

      网友评论

        本文标题:kubelet 的工作流程

        本文链接:https://www.haomeiwen.com/subject/jllnrftx.html