kubelet_kubelet反复重启 - CSDN
精华内容
参与话题
  • kubernetes 简介: kubelet 组件功能

    万次阅读 2017-03-15 15:53:16
    kubernetes 是一个分布式的集群管理系统,在每个节点(node)上都要运行一个 worker 对容器进行生命周期的管理,这个 worker 程序就是 kubelet。 简单地说,kubelet 的主要功能就是定时从某个地方获取节点上 ...

    http://cizixs.com/2016/10/25/kubernetes-intro-kubelet

    简介

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

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

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

    kubelet architecture

    1. 本地文件
    2. 通过 url 从网络上某个地址来获取信息
    3. API Server:从 kubernetes master 节点获取信息

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

    kubelet 主要功能

    pod 管理

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

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

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

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

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

    容器健康检查

    创建了容器之后,kubelet 还要查看容器是否正常运行,如果容器运行出错,就要根据设置的重启策略进行处理。检查容器是否健康主要有两种方式:在容器中执行命令和通过 HTTP 访问预定义的 endpoint。

    先来说说执行命令的方式,简单来说就是在容器中执行某个 shell 命令,根据它的 exit code 来判断容器是否正常工作:

    livenessProbe:
          exec:
            command:
            - cat
            - /tmp/health
          initialDelaySeconds: 15
          timeoutSeconds: 1
    

    另外一种就是 HTTP 的方式,通过向某个 url 路径发送 HTTP GET 请求,根据 response code 判断容器是否正常工作:

    livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
            httpHeaders:
              - name: X-Custom-Header
                value: Awesome
          initialDelaySeconds: 15
          timeoutSeconds: 1 可以看到,你也可以自定义发送的 HTTP 请求的头部。
    

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

    容器监控

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

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

    Analyzes resource usage and performance characteristics of running containers.

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

    运行和验证 kubelet

    参数介绍

    对于 kubelet 的配置,基本上都可以通过命令行启动时候的参数进行控制。因为 kubernetes 处于快速开发过程中,参数也可能会发生变化,这里给出 1.4 版本一些重要的参数含义:

    参数 解释 默认值
    –address kubelet 服务监听的地址 0.0.0.0
    –port kubelet 服务监听的端口 10250
    –read-only-port 只读端口,可以不用验证和授权机制,直接访问 10255
    –allow-privileged 是否允许容器运行在 privileged 模式 false
    –api-servers 以逗号分割的 API Server 地址,用于和集群中数据交互 []
    –cadvisor-port 当前节点 cadvisor 运行的端口 4194
    –config 本地 manifest 文件的路径或者目录 ””
    –file-check-frequency 轮询本地 manifest 文件的时间间隔 20s
    –container-runtime 后端容器 runtime,支持 docker 和 rkt docker
    –enable-server 是否启动 kubelet HTTP server true
    –healthz-bind-address 健康检查服务绑定的地址,设置成 0.0.0.0 可以监听在所有网络接口 127.0.0.1
    –healthz-port 健康检查服务的端口 10248
    –hostname-override 指定 hostname,如果非空会使用这个值作为节点在集群中的标识 ””
    –log-dir 日志文件,如果非空,会把 log 写到该文件 ””
    –logtostderr 是否打印 log 到终端 true
    –max-open-files 允许 kubelet 打开文件的最大值 1000000
    –max-pods 允许 kubelet 运行 pod 的最大值 110
    –pod-infra-container-image 基础镜像地址,每个 pod 最先启动的容器,会配置共享的网络 gcr.io/google_containers/pause-amd64:3.0
    –root-dir kubelet 保存数据的目录 /var/lib/kubelet
    –runonce 从本地 manifest 或者 URL 指定的 manifest 读取并运行结束就退出,和 --api-servers 、--enable-server 参数不兼容  
    –v 日志 level 0

    启动 kubelet

    在这篇教程中,我们会单独运行 kubelet,选择从本地目录中读取 pod manifest 信息去启动 pod。

    [Unit]
    Description=Kubelet Service
    Documentation=http://kubernetes.com
    After=network.target
    Wants=network.target
    
    [Service]
    Type=simple
    EnvironmentFile=-/etc/sysconfig/kubelet
    ExecStartPre=/usr/bin/mkdir -p /etc/kubernetes/manifests
    ExecStart=/usr/bin/kubelet \
        --allow-privileged=true \
        --config=/etc/kubernetes/manifests \
        --pod-infra-container-image=172.16.1.41:5000/google_containers/pause:0.8.0 \
        --hostname-override=192.168.8.100
    TimeoutStartSec=0
    Restart=on-abnormal
    
    [Install]
    WantedBy=multi-user.target
    

    在这篇文章的例子中,我们会运行一个 pod,这个 pod 有两个容器:nginx 和 busybox。 nginx 不做任何修改,只是提供简单的 HTTP 服务;busybox 运行命令,在终端打印出 nginx 的访问日志。为了实现两个容器之间共享数据,我们使用 kubernetes 提供的 Volume 功能,

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-server
    spec:
      containers:
      - name: nginx-server
        image: 172.16.1.41:5000/nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /var/log/nginx
          name: nginx-logs
      - name: log-output
        image: 172.16.1.41:5000/busybox
        command:
        - bin/sh
        args: [-c, 'tail -f /logdir/access.log']
        volumeMounts:
        - mountPath: /logdir
          name: nginx-logs
      volumes:
      - name: nginx-logs
        emptyDir: {}
    

    把这个配置文件放到指定的目录,等待一段时间,我们就能 docker ps 看到有容器在运行了:

    [root@localhost vagrant]# docker ps
    CONTAINER ID        IMAGE                                            COMMAND                  CREATED             STATUS              PORTS               NAMES
    66474b8cc336        172.16.1.41:5000/busybox                         "bin/sh -c 'tail -f /"   6 days ago          Up 6 days                               k8s_log-output.b93a0be3_nginx-server-192.168.8.100_default_dae69c6f50364bf8fcf20bc67f42a416_22c30949
    90ab8ef86868        172.16.1.41:5000/nginx                           "nginx"                  6 days ago          Up 6 days                               k8s_nginx-server.b88325ae_nginx-server-192.168.8.100_default_dae69c6f50364bf8fcf20bc67f42a416_e152bb97
    db27cfa9f58f        172.16.1.41:5000/google_containers/pause:0.8.0   "/pause"                 6 days ago          Up 6 days                               k8s_POD.b66e0279_nginx-server-192.168.8.100_default_dae69c6f50364bf8fcf20bc67f42a416_2236d469
    

    我们可以看到三个容器:pause、nginx 和 busybox,容器的名字是 kubelet 自动生成的。通过 docker inspect 可以看到 nginx 和 busybox 的网络模式:

    [root@localhost vagrant]# docker inspect -f '' 90ab
    container:db27cfa9f58f7b1047fb230da951453ca15e0961ca36ee7999ab3ed8ba5da814
    
    [root@localhost vagrant]# docker inspect -f '' 6647
    container:db27cfa9f58f7b1047fb230da951453ca15e0961ca36ee7999ab3ed8ba5da814
    

    使用的是 container 模式,对应的 id 就是 pause 容器的。通过查看各个容器的网络配置也能验证这一点,所有的容器网络都是一样的:

    [root@localhost vagrant]# docker exec 90ab ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    9: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.2/16 scope global eth0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:acff:fe11:2/64 scope link tentative dadfailed
           valid_lft forever preferred_lft forever
    

    而 nginx 和 busybox 的配置信息中并没有 ip 地址,pause 容器中有:

    [root@localhost vagrant]# docker inspect -f '' 6647
    
    [root@localhost vagrant]# docker inspect -f '' 90ab
    
    [root@localhost vagrant]# docker inspect -f '' db27
    172.17.0.2
    

    好了,分析就这么多。我们看测试一下启动的容器是否正常,先通过 curl 访问几次 nginx:

    [root@localhost vagrant]# curl -s http://172.17.0.2 | head -n 5
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx on Debian!</title>
    <style>
    

    然后通过 busybox 容器查看访问日志:

    [root@localhost vagrant]# docker logs -f 6647
    172.17.0.1 - - [08/Sep/2016:03:29:47 +0000] "GET / HTTP/1.1" 200 867 "-" "curl/7.29.0"
    172.17.0.1 - - [08/Sep/2016:03:49:57 +0000] "GET / HTTP/1.1" 200 867 "-" "curl/7.29.0"
    172.17.0.1 - - [08/Sep/2016:03:50:18 +0000] "GET / HTTP/1.1" 200 867 "-" "curl/7.29.0"
    172.17.0.1 - - [08/Sep/2016:03:50:23 +0000] "GET / HTTP/1.1" 200 867 "-" "curl/7.29.0"
    

    随着请求的发送,可以看到日志都打印出来了。

    API 接口

    前面也提到了,kubelet 自身提供了几个 HTTP API 接口,供用户查看信息。 最简单的就是 10248 的健康检查

    [root@localhost vagrant]# curl http://127.0.0.1:10248/healthz
    ok
    

    而 10255 端口比较重要,提供了 pod 和机器的信息:

    ➜  ~ http http://192.168.8.100:10255/pods
    HTTP/1.1 200 OK
    Content-Length: 1345
    Content-Type: application/json
    Date: Thu, 08 Sep 2016 04:03:38 GMT
    
    {
        "apiVersion": "v1",
        "items": [
            {
                "metadata": {
                    "annotations": {
                        "kubernetes.io/config.hash": "bf570970380d322fa28f20a8fe4b61bc",
                        "kubernetes.io/config.seen": "2016-09-01T09:50:16.379538472+02:00",
                        "kubernetes.io/config.source": "file"
                    },
                    "creationTimestamp": null,
                    "name": "nginx-server-192.168.8.100",
                    "namespace": "default",
                    "selfLink": "/api/v1/pods/namespaces/nginx-server-192.168.8.100/default",
                    "uid": "dae69c6f50364bf8fcf20bc67f42a416"
                },
                "spec": {
                    "containers": [
                        {
                            "image": "172.16.1.41:5000/nginx",
                            "imagePullPolicy": "Always",
                            "name": "nginx-server",
                            "ports": [
                                {
                                    "containerPort": 80,
                                    "protocol": "TCP"
                                }
                            ],
                            "resources": {},
                            "terminationMessagePath": "/dev/termination-log",
                            "volumeMounts": [
                                {
                                    "mountPath": "/var/log/nginx",
                                    "name": "nginx-logs"
                                }
                            ]
                        },
                        {
                            "args": [
                                "-c",
                                "tail -f /logdir/access.log"
                            ],
                            "command": [
                                "bin/sh"
                            ],
                            "image": "172.16.1.41:5000/busybox",
                            "imagePullPolicy": "Always",
                            "name": "log-output",
                            "resources": {},
                            "terminationMessagePath": "/dev/termination-log",
                            "volumeMounts": [
                                {
                                    "mountPath": "/logdir",
                                    "name": "nginx-logs"
                                }
                            ]
                        }
                    ],
                    "dnsPolicy": "ClusterFirst",
                    "nodeName": "192.168.8.100",
                    "restartPolicy": "Always",
                    "securityContext": {},
                    "terminationGracePeriodSeconds": 30,
                    "volumes": [
                        {
                            "emptyDir": {},
                            "name": "nginx-logs"
                        }
                    ]
                },
                "status": {
                    "conditions": [
                        {
                            "lastProbeTime": null,
                            "lastTransitionTime": "2016-09-01T07:52:36Z",
                            "status": "True",
                            "type": "PodScheduled"
                        }
                    ],
                    "phase": "Pending"
                }
            }
        ],
        "kind": "PodList",
        "metadata": {}
    }
    

    pods 列出了节点上运行的 pod 信息,包括里面有多少容器、pod 的状态、一些 metadata 等。 /spec/ 路径返回节点的信息:

    ➜  ~ http http://192.168.8.100:10255/spec/
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Thu, 08 Sep 2016 04:06:53 GMT
    Transfer-Encoding: chunked
    
    {
        "boot_id": "48955926-11dd-4ad3-8bb0-2585b1c9215d",
        "cloud_provider": "Unknown",
        "cpu_frequency_khz": 2194976,
        "disk_map": {
            "253:0": {
                "major": 253,
                "minor": 0,
                "name": "dm-0",
                "scheduler": "none",
                "size": 1107296256
            },
           ...
            "8:0": {
                "major": 8,
                "minor": 0,
                "name": "sda",
                "scheduler": "cfq",
                "size": 42949672960
            },
            "8:16": {
                "major": 8,
                "minor": 16,
                "name": "sdb",
                "scheduler": "cfq",
                "size": 21474836480
            },
         ...
        },
        "filesystems": [
            {
                "capacity": 41293721600,
                "device": "/dev/mapper/centos-root",
                "inodes": 40345600,
                "type": "vfs"
            },
            {
                "capacity": 520794112,
                "device": "/dev/sda1",
                "inodes": 512000,
                "type": "vfs"
            },
            {
                "capacity": 21464350720,
                "device": "/dev/sdb",
                "inodes": 20971520,
                "type": "vfs"
            },
           ...
        ],
        "instance_id": "None",
        "instance_type": "Unknown",
        "machine_id": "b9597c4ae5f24494833d35e806e00b29",
        "memory_capacity": 514215936,
        "network_devices": [
            {
                "mac_address": "08:00:27:c0:9e:5b",
                "mtu": 1500,
                "name": "enp0s3",
                "speed": 1000
            },
            {
                "mac_address": "08:00:27:9b:5c:b5",
                "mtu": 1500,
                "name": "enp0s8",
                "speed": 1000
            }
        ],
        "num_cores": 1,
        "system_uuid": "823EB67A-057E-4EFF-AE7F-A758140CD2F7",
        "topology": [
            {
                "caches": [
                    {
                        "level": 3,
                        "size": 3145728,
                        "type": "Unified"
                    }
                ],
                "cores": [
                    {
                        "caches": [
                            {
                                "level": 1,
                                "size": 32768,
                                "type": "Data"
                            },
                            {
                                "level": 1,
                                "size": 32768,
                                "type": "Instruction"
                            },
                            {
                                "level": 2,
                                "size": 262144,
                                "type": "Unified"
                            }
                        ],
                        "core_id": 0,
                        "thread_ids": [
                            0
                        ]
                    }
                ],
                "memory": 536403968,
                "node_id": 0
            }
        ]
    }
    

    磁盘、网络、CPU、内存等信息,这些东西是 kubernetes 集群调度的重要依据,在集群模式中会更新到 master 节点。

    清理工作

    如果删除 manifests/ 路径下的文件,等一段时间就会发现,kubelet 已经清空了所有的容器。

    $ curl -s http://localhost:10255/pods
    {"kind":"PodList","apiVersion":"v1","metadata":{},"items":null}
    

    参考链接


    展开全文
  • 1. 操作系统系统和kubelet版本信息查看 [root@master001 ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd...

    1. 查看 OS 和 kubelet 版本信息

    [root@master001 ~]# lsb_release -a
    LSB Version:    :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
    Distributor ID: CentOS
    Description:    CentOS Linux release 7.6.1810 (Core)
    Release:        7.6.1810
    Codename:       Core
    [root@master001 ~]# kubelet --version
    Kubernetes v1.16.3
    

    2. CentOS7 主机 systemctl 与 kubelet 关系

    systemd 的配置文件主要放在/usr/lib/systemd/system目录,也可能在/etc/systemd/system目录。
    如果kubelet是通过systemctl管理的,应该可以在systemctl管理目录中找到其配置文件。

    2.1 验证 kubelet 是否通过 systemctl 管理

    # systemctl status kubelet
    ● kubelet.service - kubelet: The Kubernetes Node Agent
       Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
      Drop-In: /usr/lib/systemd/system/kubelet.service.d
               └─10-kubeadm.conf
       Active: active (running) since Wed 2020-01-08 13:48:29 CST; 1 months 17 days ago
         Docs: https://kubernetes.io/docs/
     Main PID: 54019 (kubelet)
        Tasks: 29
       Memory: 71.8M
       CGroup: /system.slice/kubelet.service
               └─54019 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var...
    

    2.2 (方法一) 查找 kubelet 配置文件

    如下参数说明

    • Environment=“KUBELET_CONFIG_ARGS=–config=/var/lib/kubelet/config.yaml” 配置文件位置
    $ cd /usr/lib/systemd/system	# Centos系统 systemctl 管理目录
    $ ls -lrt | grep kubelet		# kubelet 部分文件
    -rw-r--r--. 1 root root  222 Nov 14 04:22 kubelet.service
    drwxr-xr-x. 2 root root   29 Dec 30 16:46 kubelet.service.d
    $ cd kubelet.service.d/
    $ ls -lrt						# kubelet 初始配置文件
    total 4
    -rw-r--r--. 1 root root 900 Nov 14 04:22 10-kubeadm.conf
    $ cat 10-kubeadm.conf			# 查看和修改 kubelet 配置文件
    # Note: This dropin only works with kubeadm and kubelet v1.11+
    [Service]
    Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
    Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
    # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
    EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
    # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
    # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
    EnvironmentFile=-/etc/sysconfig/kubelet
    ExecStart=
    ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
    [root@master001 kubelet.service.d]#
    

    2.3 修改 kubelet 启动参数文件

    • /var/lib/kubelet/config.yaml
    $ cd /var/lib/kubelet
    $ ls -lrt
    total 16
    -rw-r--r--.  1 root root  146 Dec 30 19:09 kubeadm-flags.env
    -rw-------.  1 root root   62 Dec 30 19:09 cpu_manager_state
    drwx------.  2 root root    6 Dec 30 19:09 plugin-containers
    drwxr-x---.  2 root root    6 Dec 30 19:09 plugins_registry
    drwxr-x---.  2 root root    6 Dec 30 19:09 plugins
    drwxr-xr-x.  2 root root  170 Dec 30 19:10 pki
    -rw-r--r--.  1 root root 1774 Dec 31 15:32 config.yaml
    drwxr-x---.  2 root root   26 Jan  8 13:48 pod-resources
    drwxr-xr-x.  2 root root   80 Jan  8 14:12 device-plugins
    drwxr-x---. 12 root root 4096 Jan  8 14:12 pods
    $ vi /var/lib/kubelet/config.yaml
    

    3. (方法二) 查找 kubelet 的启动配置文件

    参数说明

    • –config=/var/lib/kubelet/config.yaml # 启动时的配置参数
    • –network-plugin=cni # 使用的网络插件
    $ ps -ef | grep kubelet                  查看全部的 kubelet 启动时设置的参数
    $ ps -ef | grep kubelet | grep config	 查看 kubelet 的配置文件位置
    
    root      54019      1  2 Jan08 ?        1-07:36:24 /usr/bin/kubelet 
    --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf 
    --kubeconfig=/etc/kubernetes/kubelet.conf 
    --config=/var/lib/kubelet/config.yaml 		
    --cgroup-driver=systemd 
    --network-plugin=cni 
    --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.1
    
    

    4. 使对 kubelet 的修改生效

    
    启动kubelet :systemctl start kubelet
    
    停止kubelet:systemctl stop kubelet
    
    重新载入systemd:systemctl daemon-reload
    
    

    5. 再次查看kubelet启动参数

    $ ps -ef | grep kubelet 
    
    root      12372 126673  0 10:54 pts/0    00:00:00 grep --color=auto kubelet
    root      20407  20372  2 Jan06 ?        1-03:24:04 kube-apiserver --advertise-address=164.52.43.131 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-plugins=NodeRestriction --enable-bootstrap-token-auth=true --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=6443 --service-account-key-file=/etc/kubernetes/pki/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    
    root      54019      1  2 Jan08 ?        1-07:34:58 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.1
    
    展开全文
  • 7.2 kubelet

    2018-12-04 14:17:08
    1.创建及分发 kubelet bootstrap kubeconfig for node_name in ${NODE_NAMES[@]} do echo &quot;&amp;gt;&amp;gt;&amp;gt; ${node_name}&quot; export BOOTSTRAP_TOKEN=$(kubeadm token ...

    1.创建及分发 kubelet bootstrap kubeconfig

    for node_name in ${NODE_NAMES[@]}
      do
        echo ">>> ${node_name}"
    
        export BOOTSTRAP_TOKEN=$(kubeadm token create \
          --description kubelet-bootstrap-token \
          --groups system:bootstrappers:${node_name} \
          --kubeconfig ~/.kube/config)
    
        kubectl config set-cluster kubernetes \
          --certificate-authority=/etc/kubernetes/cert/ca.pem \
          --embed-certs=true \
          --server=${KUBE_APISERVER} \
          --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
    
        kubectl config set-credentials kubelet-bootstrap \
          --token=${BOOTSTRAP_TOKEN} \
          --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
    
        kubectl config set-context default \
          --cluster=kubernetes \
          --user=kubelet-bootstrap \
          --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
    
        kubectl config use-context default --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
      done
    

    查看 kubeadm 为各节点创建的 token:

    kubeadm token list --kubeconfig ~/.kube/config
    

    分发

    for node_name in ${NODE_NAMES[@]}
      do
        echo ">>> ${node_name}"
        scp kubelet-bootstrap-${node_name}.kubeconfig root@${node_name}:/etc/kubernetes/kubelet-bootstrap.kubeconfig
      done
    

    2.创建和分发 kubelet 参数配置文件

    cat > kubelet.config.json.template <<EOF
    {
      "kind": "KubeletConfiguration",
      "apiVersion": "kubelet.config.k8s.io/v1beta1",
      "authentication": {
        "x509": {
          "clientCAFile": "/etc/kubernetes/cert/ca.pem"
        },
        "webhook": {
          "enabled": true,
          "cacheTTL": "2m0s"
        },
        "anonymous": {
          "enabled": false
        }
      },
      "authorization": {
        "mode": "Webhook",
        "webhook": {
          "cacheAuthorizedTTL": "5m0s",
          "cacheUnauthorizedTTL": "30s"
        }
      },
      "address": "##NODE_IP##",
      "port": 10250,
      "readOnlyPort": 0,
      "cgroupDriver": "cgroupfs",
      "hairpinMode": "promiscuous-bridge",
      "serializeImagePulls": false,
      "featureGates": {
        "RotateKubeletClientCertificate": true,
        "RotateKubeletServerCertificate": true
      },
      "clusterDomain": "${CLUSTER_DNS_DOMAIN}",
      "clusterDNS": ["${CLUSTER_DNS_SVC_IP}"]
    }
    EOF
    

    分发

    for node_ip in ${NODE_IPS[@]}
      do 
        echo ">>> ${node_ip}"
        sed -e "s/##NODE_IP##/${node_ip}/" kubelet.config.json.template > kubelet.config-${node_ip}.json
        scp kubelet.config-${node_ip}.json root@${node_ip}:/etc/kubernetes/kubelet.config.json
      done
    

    创建kubelet.service模板

    cat > kubelet.service.template <<EOF
    [Unit]
    Description=Kubernetes Kubelet
    Documentation=https://github.com/GoogleCloudPlatform/kubernetes
    After=docker.service
    Requires=docker.service
    
    [Service]
    WorkingDirectory=/var/lib/kubelet
    ExecStart=/opt/k8s/bin/kubelet \\
      --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \\
      --cert-dir=/etc/kubernetes/cert \\
      --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
      --config=/etc/kubernetes/kubelet.config.json \\
      --hostname-override=##NODE_NAME## \\
      --pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest \\
      --allow-privileged=true \\
      --alsologtostderr=true \\
      --logtostderr=false \\
      --log-dir=/var/log/kubernetes \\
      --v=2
    Restart=on-failure
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target
    EOF
    

    分发模板for node_name in ${NODE_NAMES[@]}

    for node_name in ${NODE_NAMES[@]}
      do 
        echo ">>> ${node_name}"
        sed -e "s/##NODE_NAME##/${node_name}/" kubelet.service.template > kubelet-${node_name}.service
        scp kubelet-${node_name}.service root@${node_name}:/etc/systemd/system/kubelet.service
      done
    

    主机执行

    $ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers
    

    启动服务

    for node_ip in ${NODE_IPS[@]}
      do
        echo ">>> ${node_ip}"
        ssh root@${node_ip} "mkdir -p /var/lib/kubelet"
        ssh root@${node_ip} "/usr/sbin/swapoff -a"
        ssh root@${node_ip} "mkdir -p /var/log/kubernetes && chown -R k8s /var/log/kubernetes"
        ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet"
      done
    

    验证服务

    kubectl get csr
    

    3.approve csr
    a.手动

    kubectl certificate approve node-csr-QzuuQiuUfcSdp3j5W4B2UOuvQ_n9aTNHAlrLzVFiqrk
    

    查看

    kubectl get csr
    
    NAME                                                   AGE       REQUESTOR                 CONDITION
    csr-h8nxp                                              3s        system:node:kube-node3    Pending
    node-csr-Kn--o2M2F3DlJ9Wqz7GHn8839aUsKJlOB0C4l182rIc   1m        system:bootstrap:qpzg63   Approved,Issued
    node-csr-W7RWJK9DxJ2xj846Fp-tPuQFZvmc4Rm50LzAPch7fRE   1m        system:bootstrap:xnsgd6   Pending
    node-csr-oh_Q0GIU-CwlUoV_N2Byq6wuF3jxlZEmVyacDq3fsEw   1m        system:bootstrap:jwpybp   Pending
    

    查看信息

    kubectl describe csr node-csr-Kn--o2M2F3DlJ9Wqz7GHn8839aUsKJlOB0C4l182rIc
    

    b.自动 approve CSR 请求(推荐使用这种方式,如果用手动方式heapster插件可能由于证书问题获取不到cpu和内存信息)

    cat > csr-crb.yaml <<EOF
     # Approve all CSRs for the group "system:bootstrappers"
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: auto-approve-csrs-for-group
     subjects:
     - kind: Group
       name: system:bootstrappers
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
       apiGroup: rbac.authorization.k8s.io
    ---
     # To let a node of the group "system:nodes" renew its own credentials
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: node-client-cert-renewal
     subjects:
     - kind: Group
       name: system:nodes
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
       apiGroup: rbac.authorization.k8s.io
    ---
    # A ClusterRole which instructs the CSR approver to approve a node requesting a
    # serving cert matching its client cert.
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: approve-node-server-renewal-csr
    rules:
    - apiGroups: ["certificates.k8s.io"]
      resources: ["certificatesigningrequests/selfnodeserver"]
      verbs: ["create"]
    ---
     # To let a node of the group "system:nodes" renew its own server credentials
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: node-server-cert-renewal
     subjects:
     - kind: Group
       name: system:nodes
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: approve-node-server-renewal-csr
       apiGroup: rbac.authorization.k8s.io
    EOF
    

    使配置生效

    kubectl apply -f csr-crb.yaml
    

    4.查看 kublet 的情况
    查看证书

    kubectl get csr
    
    NAME                                                   AGE       REQUESTOR                 CONDITION
    csr-94pmx                                              5s        system:node:kube-node3    Approved,Issued
    csr-9h4xb                                              5s        system:node:kube-node2    Approved,Issued
    csr-9v4qf                                              6s        system:node:kube-node1    Approved,Issued
    node-csr-BAMgq0axCp7_pS7PmxXTPGHzdg-aO0JnvMmmj7fYdEg   4d        system:bootstrap:jwxbug   Approved,Issued
    node-csr-Q0eLietYfEqyvgBSYCfG_7bZh22hNHoOlNfL4AdwmIc   4d        system:bootstrap:xciclh   Approved,Issued
    node-csr-dYdAEGk5llHdicInTX4uDj_4dmodwpxOrqvalbDFqG8   4d        system:bootstrap:881igu   Approved,Issued
    

    查看节点

    kubectl get nodes
    
    NAME         STATUS    ROLES     AGE       VERSION
    kube-node1   Ready     <none>    12s       v1.10.7
    kube-node2   Ready     <none>    11s       v1.10.7
    kube-node3   Ready     <none>    11s       v1.10.7
    

    5.kubelet 提供的 API 接口

    sudo netstat -lnpt|grep kubelet
    

    6.使用证书访问

    curl -s --cacert /etc/kubernetes/cert/ca.pem --cert ./admin.pem --key ./admin-key.pem 
    

    https://172.17.13.204:10250/metrics|head
    网址.访问
    http://node1公网IP:4194/containers/

    展开全文
  • Kubernetes之Kubelet组件解析

    千次阅读 2018-08-21 11:16:49
    Kubelet组件运行在Node节点上,维持运行中的Pods以及提供kuberntes运行时环境,主要完成以下使命:  1.监视分配给该Node节点的pods  2.挂载pod所需要的volumes  3.下载pod的secret  4.通过docker/rkt来...

    概述

    这里写图片描述

    Kubelet组件运行在Node节点上,维持运行中的Pods以及提供kuberntes运行时环境,主要完成以下使命: 
    1.监视分配给该Node节点的pods 
    2.挂载pod所需要的volumes 
    3.下载pod的secret 
    4.通过docker/rkt来运行pod中的容器 
    5.周期的执行pod中为容器定义的liveness探针 
    6.上报pod的状态给系统的其他组件 
    7.上报Node的状态 
    这里写图片描述
    整个kubelet可以按照上图所示的模块进行划分,模块之间相互配合完成Kubelet的所有功能.下面对上图中的模块进行简要的介绍. 
    Kubelet对外暴露的端口,通过该端口可以获取到kubelet的状态

    10250 kubelet API –kublet暴露出来的端口,通过该端口可以访问获取node资源以及状态,另外可以配合kubelet的启动参数contention-profiling enable-debugging-handlers来提供了用于调试和profiling的api

    4194 cAdvisor –kublet通过该端口可以获取到本node节点的环境信息以及node上运行的容器的状态等内容

    10255 readonly API –kubelet暴露出来的只读端口,访问该端口不需要认证和鉴权,该http server提供查询资源以及状态的能力.注册的消息处理函数定义src/k8s.io/kubernetes/pkg/kubelet/server/server.go:149

    10248 /healthz –kubelet健康检查,通过访问该url可以判断Kubelet是否正常work, 通过kubelet的启动参数–healthz-port –healthz-bind-address来指定监听的地址和端口.默认值定义在pkg/kubelet/apis/kubeletconfig/v1alpha1/defaults.go 
    这里写图片描述

    核心功能模块

    • PLEG 
      这里写图片描述
      PLEG全称为PodLifecycleEvent,PLEG会一直调用container runtime获取本节点的pods,之后比较本模块中之前缓存的pods信息,比较最新的pods中的容器的状态是否发生改变,当状态发生切换的时候,生成一个eventRecord事件,输出到eventChannel中. syncPod模块会接收到eventChannel中的event事件,来触发pod同步处理过程,调用contaiener runtime来重建pod,保证pod工作正常.

    • cAdvisor 
      cAdvisor集成在kubelet中,起到收集本Node的节点和启动的容器的监控的信息,启动一个Http Server服务器,对外接收rest api请求.cAvisor模块对外提供了interface接口,可以通过interface接口获取到node节点信息,本地文件系统的状态等信息,该接口被imageManager,OOMWatcher,containerManager等所使用 
      cAdvisor相关的内容详细可参考github.com/google/cadvisor

    • GPUManager 
      对于Node上可使用的GPU的管理,当前版本需要在kubelet启动参数中指定feature-gates中添加Accelerators=true,并且需要才用runtime=Docker的情况下才能支持使用GPU,并且当前只支持NvidiaGPU,GPUManager主要需要实现interface定义的Start()/Capacity()/AllocateGPU()三个函数

    • OOMWatcher 
      系统OOM的监听器,将会与cadvisor模块之间建立SystemOOM,通过Watch方式从cadvisor那里收到的OOM信号,并发生相关事件

    • ProbeManager 
      探针管理,依赖于statusManager,livenessManager,containerRefManager,实现Pod的健康检查的功能.当前支持两种类型的探针:LivenessProbe和ReadinessProbe, 
      LivenessProbe:用于判断容器是否存活,如果探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理 
      ReadinessProbe: 用于判断容器是否启动完成 
      探针有三种实现方式 
      execprobe:在容器内部执行一个命令,如果命令返回码为0,则表明容器健康 
      tcprobe:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康 
      httprobe:通过容器的IP地址,端口号以及路径调用http Get方法,如果响应status>=200 && status<=400的时候,则认为容器状态健康

    • StatusManager 
      该模块负责pod里面的容器的状态,接受从其它模块发送过来的pod状态改变的事件,进行处理,并更新到kube-apiserver中.

    • Container/RefManager 
      容器引用的管理,相对简单的Manager,通过定义map来实现了containerID与v1.ObjectReferece容器引用的映射.

    • EvictionManager 
      evictManager当node的节点资源不足的时候,达到了配置的evict的策略,将会从node上驱赶pod,来保证node节点的稳定性.可以通过kubelet启动参数来决定evict的策略.另外当node的内存以及disk资源达到evict的策略的时候会生成对应的node状态记录.

    • ImageGC 
      imageGC负责Node节点的镜像回收,当本地的存放镜像的本地磁盘空间达到某阈值的时候,会触发镜像的回收,删除掉不被pod所使用的镜像.回收镜像的阈值可以通过kubelet的启动参数来设置.

    • ContainerGC 
      containerGC负责NOde节点上的dead状态的container,自动清理掉node上残留的容器.具体的GC操作由runtime来实现.

    • ImageManager 
      调用kubecontainer.ImageService提供的PullImage/GetImageRef/ListImages/RemoveImage/ImageStates的方法来保证pod运行所需要的镜像,主要是为了kubelet支持cni.

    • VolumeManager 
      负责node节点上pod所使用的volume的管理.主要涉及如下功能 
      Volume状态的同步,模块中会启动gorountine去获取当前node上volume的状态信息以及期望的volume的状态信息,会去周期性的sync volume的状态,另外volume与pod的生命周期关联,pod的创建删除过程中volume的attach/detach流程.更重要的是kubernetes支持多种存储的插件,kubelet如何调用这些存储插件提供的interface.涉及的内容较多,更加详细的信息可以看kubernetes中volume相关的代码和文档.

    • containerManager 
      负责node节点上运行的容器的cgroup配置信息,kubelet启动参数如果指定–cgroupPerQos的时候,kubelet会启动gorountie来周期性的更新pod的cgroup信息,维持其正确.实现了pod的Guaranteed/BestEffort/Burstable三种级别的Qos,通过配置kubelet可以有效的保证了当有大量pod在node上运行时,保证node节点的稳定性.该模块中涉及的struct主要包括 
      这里写图片描述

    • runtimeManager 
      containerRuntime负责kubelet与不同的runtime实现进行对接,实现对于底层container的操作,初始化之后得到的runtime实例将会被之前描述的组件所使用. 
      当前可以通过kubelet的启动参数–container-runtime来定义是使用docker还是rkt.runtime需要实现的接口定义在src/k8s.io/kubernetes/pkg/kubelet/apis/cri/services.go文件里面

    • podManager 
      podManager提供了接口来存储和访问pod的信息,维持static pod和mirror pods的关系,提供的接口如下所示 
      这里写图片描述 
      跟其他Manager之间的关系,podManager会被statusManager/volumeManager/runtimeManager所调用,并且podManager的接口处理流程里面同样会调用secretManager以及configMapManager. 
      这里写图片描述 
      上面所说的模块可能只是kubelet所有模块中的一部分,更多的需要大家一起看探索.

    深入分析

    下面进一步的深入分析kubelet的代码 
    Kubelet负责pod的创建,pod的来源kubelet当前支持三种类型的podSource 
    - FileSource: 通过kubelet的启动参数–pod-manifest-path来指定pod manifest文件所在的路径或者文件都可以.Kubelet会读取文件里面定义的pod进行创建.常常我们使用来定义kubelet管理的static pod 
    - HTTPSource: 通过kubelet的启动参数–manifest-url –manifest-url-header来定义manifest url. 通过http Get该manifest url获取到pod的定义 
    - ApiserverSource: 通过定义跟kube-apiserver进行通过的kubeclient, 从kube-apiserver中获取需要本节点创建的pod的信息.

    Kubelet如何同时处理这三种podSource里面定义的pod进行处理的.在src/k8s.io/kubernetes/pkg/kubelet/kubelet.go:254的makePodSourceConfig中分别是处理三种podSource的启动参数. 
    这里写图片描述 
    三种source的实现类似,分别启动goroutinue,周期性的查看是否有新的数据来源,如果发现获取到新的数据,生成PodUpdate对象,输出到对应的channel里面.

    会针对每种类型创建对应的Channel.

    cfg.Channel(kubetypes.FileSource)
    cfg.Channel(kubetypes.HTTPSource)
    cfg.Channel(kubetypes.ApiserverSource)
    • 1
    • 2
    • 3

    Channel存储在PodConfig.mux.sources里面 
    其中channel中传递的对象定义如下

    type PodUpdate struct {
        Pods   []*v1.Pod
        Op     PodOperation
        Source string
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    Op为kubetypes.SET  Source表示pod的来源,可能的值为HTTPSource|FileSource|ApiserverSource, 
    进一步的分析代码,发现定义chanel的时候,同时也定义gorountine用来watch该channel的变化 
    go wait.Until(func() { m.listen(source, newChannel) }, 0, wait.NeverStop)

    func (m *Mux) listen(source string, listenChannel <-chan interface{}) {
        for update := range listenChannel {
            m.merger.Merge(source, update)
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    原来是将3个channel的对象merge到podConfig.updates中.这个地方merge会对podUpdate进行预处理,处理流程可以仔细看podStorage.merge().会将事件中包含的pods与本地内存中存储pods信息进行分析,将podUpdate分成adds.updates,deletes,removes,reconsiles五类,并分别更新kubetypes.PodUpdate.Op的操作. 
    对于podSource中生成的podUpdate,如果初次进入该流程,一开始podUpdate.Op=kubetypes.SET, 将会podSource中定义的pod将会addPods里面,podUpdate.Op=kubetype.ADD.

    定义的podConfig保存在kubeDeps.PodConfig中.

    进一步跟进kubelet源码,自然想到的是谁会从channel中获取PodUpdate进行处理,进行pod同步. 
    Kubelet的主流程里面会启动gorountiue执行如下代码

    func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) {
        glog.Info("Starting kubelet main sync loop.")
        // The resyncTicker wakes up kubelet to checks if there are any pod workers
        // that need to be sync'd. A one-second period is sufficient because the
        // sync interval is defaulted to 10s.
        syncTicker := time.NewTicker(time.Second)
        defer syncTicker.Stop()
        housekeepingTicker := time.NewTicker(housekeepingPeriod)
        defer housekeepingTicker.Stop()
        plegCh := kl.pleg.Watch()
        for {
            if rs := kl.runtimeState.runtimeErrors(); len(rs) != 0 {
                glog.Infof("skipping pod synchronization - %v", rs)
                time.Sleep(5 * time.Second)
                continue
            }
    
            kl.syncLoopMonitor.Store(kl.clock.Now())
            if !kl.syncLoopIteration(updates, handler, syncTicker.C, housekeepingTicker.C, plegCh) {
                break
            }
            kl.syncLoopMonitor.Store(kl.clock.Now())
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    其中updates就是podConfig.updates中定义的channel. 同时kl.pleg.Watch()是pleg模块定义的事件channel, 
    SyncHandler定义

    type SyncHandler interface {
        HandlePodAdditions(pods []*v1.Pod)
        HandlePodUpdates(pods []*v1.Pod)
        HandlePodRemoves(pods []*v1.Pod)
        HandlePodReconcile(pods []*v1.Pod)
        HandlePodSyncs(pods []*v1.Pod)
        HandlePodCleanups() error
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    syncLoopIteration方法是一个channel中事件处理中心,处理从跟pod生命周期创建相关的channel中获取事件,之后进行转发到对应的处理函数中.这个对于理解kubelet对于pod的管理至关重要. 
    触发同步的事件channel主要包括 
    1.configCh pod的配置改变 
    2.PLEG模块中状态更新事件 
    3.1s为周期的同步时钟 syncPod 
    4.2s为周期的执行全局清理任务的始终 CleanupPod

    启动了goroutinue循环调用PodCfg.Updates()中的Channel中获取PodUpdate.进入消息中专分支流程. 
    1.<-configCh && u.Op=kubetype.ADD 
    a)执行handler.HandlePodAdditions, handler.HandlePodAdditions()的实现在kubelt.HandlePodAdditions(pods []*v1.Pod)

    在Kubelt.HandlePodAdditions中再一次分发podUpdate并将kl.probeManager(AddPod(pod)),执行dispatchWork. 之后将updatePodOption初始化,添加到podWorkers.podUpdates的channel中.

    dispatchWork中将updatePodOptions定义成如下结构体

    type UpdatePodOptions struct {
        // pod to update
        Pod *v1.Pod
        // the mirror pod for the pod to update, if it is a static pod
        MirrorPod *v1.Pod
        // the type of update (create, update, sync, kill)
        UpdateType kubetypes.SyncPodType
        // optional callback function when operation completes
        // this callback is not guaranteed to be completed since a pod worker may
        // drop update requests if it was fulfilling a previous request.  this is
        // only guaranteed to be invoked in response to a kill pod request which is
        // always delivered.
        OnCompleteFunc OnCompleteFunc
        // if update type is kill, use the specified options to kill the pod.
        KillPodOptions *KillPodOptions
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    同时启动goroutinue用于处理managePodLoop,在managePodLoop将会依次处理channel中的podUpdate.最终将会调用kubelet中定义的func (kl *Kubelet) syncPod(o syncPodOptions).在kubelet的syncPod中实现了调用底层其他模块来完成pod状态的同步.

    1.kubelet.syncPod记录podWorkerStartLatency监控指标,该指标用来统计pod被node所创建延迟的时间 
    2.执行kubelet中定义的podSyncHandler.ShouldEvict(),当前podSyncHandler定义有activeDeadlineHandler,该handler对应pod的spec.activeDeadlineSeconds定义进行处理,如果pod中定义该字段,则要求pod在该字段定义的时间内完成创建过程. 
    3.generateAPIPodStatus根据pod的信息来生成PodStatus结构体 
    4.kubelet.canRunPod检查是否本节点可以运行该pod,检查通过softAdmitHandler进行定义,另外对于pod是否具有allowPrivileged的权限.其中softAdmitHandler的定义在kubelet的启动流程中,分别为

    lifecycle.NewPredicateAdmitHandler
    lifecycle.NewAppArmorAdmitHandler
    lifecycle.NewNoNewPrivsAdmitHandler
    • 1
    • 2
    • 3

    5.statusManager.SetPodStatus更新缓存pod的状态信息,触发状态更新 
    6.触发kl.containerManager.updateQOSCgroups()更新pod的cgroup设置.其中kl.containerManager的定义为cm.NewContainerManager()中创建的type containerManagerImpl struct实现的interface. 继续分析代码最终调用的函数是qosContainerManagerImpl.UpdateCgroups(),配置顶层的QosCgroup的相关内容. 
    7.调用kl.containerManager.NewPodContainerManager().EnsureExists(),配置pod的cgroup的信息. 只有在kubelet的启动参数–cgroups-per-qos为true的时候,会执行podContainerManagerImpl.EnsureExists()来创建将pod中设置对于资源的限制去对应的cgroup.详细的创建是由cgroupManager来完成. 
    8.创建pod所使用的podDir,podVolumesDir以及podPluginDir目录 
    9.volumeManager.WaitForAttachAndMount(pod) volumeManager将会把volume挂载到pod运行的宿主机上面. 
    10.调用kl.getPullSecretsForPod(),如果pod中定义了spec.ImagePullSecrets,则获取资源对象中定义的内容. 
    11.最后调用kl.containerRuntime.SyncPod(),kl.containerRuntime的定义可以参考kubelet的启动流程.如果runtime是docker,那么SyncPod()的定义为kubeGenericRuntimeManager, src/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go:568,在该流程中分别是创建sandbox,之后创建create init/containers.

    Node资源管理

    Node节点运行运用的pod以及系统基础组件,这里的资源主要指的是node节点上的cpu,memory,storage. 用户的pod存在资源使用随着时间变大的情况,可能会影响到其他正常工作的pod以及node节点上的其他系统组件等,如何在该场景下提高node节点的稳定性是一个需要探索的问题. 
    首先,先Kubernetes中相关的概念

    Cgroups

    Cgroups是control groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。 
    跟容器相关的功能主要涉及以下 
    · 限制进程组可以使用的资源数量(Resource limiting )。比如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。 
    · 进程组的优先级控制(Prioritization )。比如:可以使用cpu子系统为某个进程组分配特定cpu share。 
    · 记录进程组使用的资源数量(Accounting )。比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间。 
    · 进程组隔离(Isolation)。比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。

    Limits/request

    Request: 容器使用的最小资源需求,作为容器调度时资源分配的判断依赖。只有当节点上可分配资源量>=容器资源请求数时才允许将容器调度到该节点。但Request参数不限制容器的最大可使用资源。 
    Limit: 容器能使用资源的资源的最大值,设置为0表示使用资源无上限。 
    当前可以设置的有memory/cpu, kubernetes版本增加了localStorage在1.8版本中的策略.

    Pod Qos

    Qos服务质量分成三个级别 
    BestEffort:POD中的所有容器都没有指定CPU和内存的requests和limits,默认为0,不限制资源的使用量,那么这个POD的QoS就是BestEffort级别 
    Burstable:POD中只要有一个容器,这个容器requests和limits的设置同其他容器设置的不一致,requests < limits, 那么这个POD的QoS就是Burstable级别 
    Guaranteed:POD中所有容器都必须统一设置了limits,并且设置参数都一致,如果有一个容器要设置requests,那么所有容器都要设置,并设置参数同limits一致,requests = limits. 那么这个POD的QoS就是Guaranteed级别. 
    Kuberntes管理的node资源中cpu为可压缩资源,当node上运行的pod cpu负载较高的时候,出现资源抢占,会根据设置的limit值来分配时间片. 
    Kubernetes管理的node资源memory/disk是不可压缩资源,当出现资源抢占的时候,会killer方式来释放pod所占用的内存以及disk资源. 
    当非可压缩资源出现不足的时候,kill掉pods的Qos优先级比较低的pods.通过OOM score来实现,Guaranteed pod,OOM_ADJ设置为-998, BestEffort 设置的OOM_ADJ为1000, Burstable级别的POD设置为2-999.

    Evict策略

    当系统资源不足的时候,kubelet会通过evict策略来驱逐本节点的pod来使得node节点的负载不是很高, 保证系统组件的稳定性. 
    当前支持的驱逐信号Eviction Signal为 
    memory.available 
    nodefs.available 
    nodefs.inodesFree 
    imagefs.available 
    imagefs.inodesFree

    kubelet将支持软硬驱逐门槛, 操作管理员通过设置Kubelet的启动参数–eviction-soft –eviction-hard 来指定, 硬驱逐阈值没有宽限期,如果观察到,kubelet将立即采取行动来回收相关的饥饿资源。 如果满足硬驱逐阈值,那么kubelet会立即杀死pods,没有优雅的终止。软驱逐阈值将驱逐阈值与所需的管理员指定的宽限期配对。kubelet不采取任何措施来回收与驱逐信号相关的资源,直到超过宽限期。

    以内存导致驱逐的场景来详细说明 
    让我们假设操作员使用以下命令启动kubelet: 
    –eviction-hard=”memory.available<100Mi” 
    –eviction-soft=”memory.available<300Mi” 
    –eviction-soft-grace-period=”memory.available=30s” 
    kubelet将运行一个同步循环,通过计算(capacity-workingSet)从cAdvisor报告,查看节点上的可用内存。 如果观察到可用内存降至100Mi以下,那么kubelet将立即启动驱逐。 如果观察到可用内存低于300Mi,则会在高速缓存中内部观察到该信号时记录。 如果在下一次同步时,该条件不再满足,则该信号将清除缓存。 如果该信号被视为满足长于指定时间段,则kubelet将启动驱逐以尝试回收已满足其逐出阈值的资源。 
    Pods的驱逐策略 
    如果已经达到逐出阈值,那么kubelet将启动逐出pods的过程,直到观察到信号已经低于其定义的阈值。

    驱逐顺序如下: 
    1. 对于每个监测间隔,如果已经达到逐出阈值 
    2. 找候选pod 
    3. 失败pod 
    4. 阻止直到pod在节点上终止 
    kubelet将实施围绕pod质量服务类定义的默认驱逐策略。

    它将针对相对于其调度请求的饥饿计算资源的最大消费者的pod。它按照以下顺序对服务质量等级进行排序。

    1. 消费最多的饥饿资源的BestEffort pods首先失败。
    2. 消耗最大数量的饥饿资源相对于他们对该资源的请求的Burstable pod首先被杀死。如果没有pod超出其要求,该策略将针对饥饿资源的最大消费者。
    3. 相对于他们的请求消费最多的饥饿资源的Guaranteed pod首先被杀死。如果没有pod超出其要求,该策略将针对饥饿资源的最大消费者。

    关于imagefs/nodefs导致的资源的驱逐详细参考https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/kubelet-eviction.md#enforce-node-allocatable

    实践经验

    • 将系统资源进行划分, 预留资源 
      Node Capacity - 已经作为NodeStatus.Capacity提供,这是从节点实例读取的总容量,并假定为常量。 
      System-Reserved(提议) - 为未由Kubernetes管理的流程预留计算资源。目前,这涵盖了/系统原始容器中集中的所有进程。 
      Kubelet Allocatable - 计算可用于调度的资源(包括计划和非计划资源)。这个价值是这个提案的重点。请参阅下面的更多细节。 
      Kube-Reserved(提出) - 为诸如docker守护进程,kubelet,kube代理等的Kubernetes组件预留的计算资源。 
      可分配的资源数据将由Kubelet计算并报告给API服务器。它被定义为:

      [Allocatable] = [Node Capacity] - [Kube-Reserved] – [System-Reserved] – [Hard-Eviction-Threshold] 
      调度pod时,调度程序将使用Allocatable代替Capacity,Kubelet将在执行准入检查Admission checks时使用它。

      这里写图片描述

    • 一个kubelet从来不希望驱逐从DaemonSet导出的pod,因为pod将立即重新创建并重新安排回到同一个节点。此时,kubelet无法区分从DaemonSet创建的pod与任何其他对象。 如果/当该信息可用时,kubelet可以主动地从提供给驱逐策略的候选pod集合中过滤这些pod。一般来说,强烈建议DaemonSet不要创建BestEffort pod,以避免被识别为候选pods被驱逐。 相反,DaemonSet应该理想地包括仅Guaranteed pod。

    • 静态static pod 
      静态POD直接由某个节点上的kubelet程序进行管理,不需要api server介入,静态POD也不需要关联任何RC,完全是由kubelet程序来监控,当kubelet发现静态POD停止掉的时候,重新启动静态POD。 
      EvictManager模块在系统资源紧张的时候, 根据pod的Qos以及pod使用的资源会选择本节点的pod killer,来释放资源, 但是静态pod被killer之后,并不会发生重启的现象, 设置pod的yaml中定义加入如下内容,并且kubelet的启动参数打开feature gateway(–feature-gates=ExperimentalCriticalPodAnnotation=true).

        annotations:
          scheduler.alpha.kubernetes.io/critical-pod: ''
      • 1
      • 2

    参考 
    https://speakerdeck.com/luxas/kubernetes-architecture-fundamentals 
    https://kubernetes.io/docs

    展开全文
  • Kubelet组件解析

    万次阅读 2017-12-26 18:57:14
    kubernetes中Kubelet介绍
  • kubelet启动失败-报错解决

    千次阅读 2020-10-20 21:03:33
    kubelet 启动失败 配置完daemon.json,重启docker后kubelet起不来 [root@node1/etc/docker]# vim daemon.json { "registry-mirrors": ["https://ig2l319y.mirror.aliyuncs.com"], "exec-opts": ["native....
  • Kubernetes核心原理(四)之Kubelet

    万次阅读 2019-04-23 10:24:47
    1. kubelet简介在kubernetes集群中,每个Node节点都会启动kubelet进程,用来处理Master节点下发到本节点的任务,管理Pod和其中的容器。kubelet会在API Server上注册节点信息,定期向Master汇报节点资源使用情况,并...
  • Kubelet 源码剖析

    千次阅读 2018-01-16 12:54:38
    本篇文章主要介绍了 kubelet 服务启动和创建 pod 的流程,给想要阅读 kubelet 源码的同学一个参考。本文最先发布于 opsdev,转载已获取作者授权。PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,...
  • 部署kubelet

    千次阅读 2018-05-17 14:18:00
    nohup /home/taas/k8s/bin/kubelet \ --address=192.168.111.141 \ --hostname-override=192.168.111.141 \ --pod-infra-container-image=10.1.8.16:5000/lhcalibur/pause-amd64:latest \ --experimental-bo...
  • 修改 K8s kubelet启动参数

    万次阅读 2016-12-01 18:05:30
    我想创建静态Pod,那么就需要更改kubelet的启动参数。相关环境信息如下: role OS IP module Master Centos7.2 10.1.2.182 kube-apiserver kube-controller-manager kube-scheduler Node1 Centos7.2
  • kubelet启动失败

    万次阅读 2018-07-14 11:47:26
    报错详情: $ systemctl status ...● kubelet.service - Kubernetes Kubelet Server Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled) Active: failed (Result: sta...
  • OS为Ubuntu 16.04,该版本默认提供了systemctl工具,kubelet就通过该工具来管理。 root@ubuntu2:/etc/# systemctl --version systemd 229 +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +...
  • kubelet服务启动失败,错误代码255

    万次阅读 2018-07-01 18:25:40
    在用kubeadm的方法,安装kubelet后,运行systemctl status kubelet 发现kubelet服务启动失败,错误代码255。 kubelet.service: main process exited, code=exited, status=255/n/a 检查了Swap已经关闭,SELinux...
  • K8s kubelet & kubeadm & kubectl 介绍

    千次阅读 2018-06-02 20:03:03
    kubelet:运行在cluster所有节点上,负责启动POD和容器 kubeadm:用于初始化cluster kubectl:kubectl是kubenetes命令行工具,通过kubectl可以部署和管理应用,查看各种资源,创建,删除和更新组件...
  • kubelet启动常见问题

    千次阅读 2019-03-05 07:44:06
    kubelet无法启动,最常见的问题之一在于cgroup-driver的设定不正确,以下列出问题示例和对应方法。
  • 手动安装k8s,但kubelet.service 启动失败

    万次阅读 2018-08-09 16:37:58
    k8s的kubelet.service 启动失败 #systemctl status kubelet.service ● kubelet.service - Kubernetes API Server Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)...
  • 修改Docker及kubelet的Cgroup Driver

    万次阅读 2018-12-18 12:08:58
    failed to create kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd" 原因是docker的Cgroup Driver和kubelet的Cgroup Driv.....
  • 查看kubelet状态 systemctl status kubelet 若k8s中的kubelet无法启动,在ubuntu系统中的启动配置文件/etc/systemd/system/kubelet.service.d/10-kubeadm.conf的内容应该如下: # Note: This dropin only works ...
  • kubeadm 部署kubernetes 1.11.0 的问题记录

    万次阅读 2018-07-29 17:43:11
    系统环境 [root@kubeadm ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) 关闭selinux [root@kubeadm ~]# cat /etc/selinux/config # This file controls the state of SELinux on the ...
  • 一般的是在node上安装部署k8s的时候。 检查下,docker服务是否已经安装。
1 2 3 4 5 ... 20
收藏数 17,721
精华内容 7,088
关键字:

kubelet