总体设计思想

  1. 总体设计架构图Kubernetes monitoring architecture

  2. 设计介绍

    监控分成两个部分

    • 核心指标流程 包括的组件有 kubelet、resource estimator、metrics-server、API server。这些指标被kubernetes的核心组件使用:kubectl、sheduler、HPA。指标数据流转如上图中黑色部分所示,具体过程如下:

      1. kubelet运行在所有node节点上,通过内置的cAdvisor收集节点上所有的容器资源使用信息,然后通过kubelet合并成pod级别的指标信息,之后以API的形式对外暴露出来,供其他组件调用。详细的kubeletAPI可参考kubelet-api,在kubelet安装完成后可以通过如下命令尝试调用

        root@master:/etc/kubernetes/cert# curl -s --cacert ./ca.pem --cert ./admin.pem --key ./admin-key.pem https://192.168.0.107:10250/metrics | head
        # HELP apiserver_audit_event_total [ALPHA] Counter of audit events generated and sent to the audit backend.
        # TYPE apiserver_audit_event_total counter
        apiserver_audit_event_total 0
        # HELP apiserver_audit_requests_rejected_total [ALPHA] Counter of apiserver requests rejected due to an error in audit logging backend.
        # TYPE apiserver_audit_requests_rejected_total counter
        apiserver_audit_requests_rejected_total 0
        # HELP apiserver_client_certificate_expiration_seconds [ALPHA] Distribution of the remaining lifetime on the certificate used to authenticate a request.
        # TYPE apiserver_client_certificate_expiration_seconds histogram
        apiserver_client_certificate_expiration_seconds_bucket{le="0"} 0
        apiserver_client_certificate_expiration_seconds_bucket{le="1800"} 0
        • cacert 是授信kubelet证书的证书
        • cert 和 key 是具有访问kubelete权限的并且通过cacert指定的证书签名过的证书和私钥对
        • 10250是kubelet服务的端口
      2. metrics-server 组件通过调用kubelet的接口将信息汇总起来,虽然kubelet通过cAdvisor收集了很多信息,metrics-server只会取其中的一部分给用户。如果通过k8s提供的安装脚本kube-up.sh来安装集群,默认会直接安装metrics-server,如果是自己安装集群需要自己手动安装,参考metrics-server安装

      3. metrics-server 组件收集好需要的指标信息后不会直接面向用户提供可用的API,而是通过 [Kubernetes aggregator](#Kubernetes aggregator)机制,将API注册到k8s的API server中,之后用户可以像操作通用API一样 来获取这些信息。

      4. metrics-server中只会保留最近一次的指标汇集数据,不会存储获取过的信息,所以k8s早期计划再开发一个基础存储组件,把metrics-server收集到的信息传递给存储组件,供dashboard、vertical autoscaling 等组件使用

    • 通用监控流程 用来收集各种各样的指标并暴露给用户,部分指标通过adapter适配后提供给HPA(Horizontal Pod Autoscaler)使用。这些指标也可以通过一个API adapter转换后存入到基础存储组件中给其他需要历史轨迹的组件使用。一般通用监控组件会在节点上都安装一个代理,然后会有一个集群级别的收集组件。指标数据流转参考架构图中的蓝色部分,具体流程如下

      • 各个节点上运行的agent收集节点上的指标信息,这些信息可包含以下信息类型的子集或全集(取决于监控组件的设计)

        • 核心系统指标(影响对一等资源进行隔离和使用的指标,如CPU、Memory、Disk)
        • 非核心系统指标
        • 用户应用程序中暴露的服务指标
        • Kubernetes 基础组件中的服务指标(Kubernetes基础组件无论是容器启动还是服务启动,都会暴露这些指标信息,因为格式都是Prometheus format)
      • 集群级别的收集组件把这些信息收集起来

      • 通过adapter转换成满足存储组件需要的格式存储起来

      • 对于用户自定义的HPA指标,通过adapter转换成HPA识别的形式参与HPA

      • 可选的技术方案

        • cAdvisor + collectd + Heapster
        • cAdvisor + Prometheus
        • snapd + Heapster
        • snapd + SNAP cluster-level agent
        • Sysdig

      这些都是刚开始设计时的想法,现在prometheus采用的是在节点上安装一个nodereporter来收集节点信息,汇报给Prometheus

配置Kubernetes aggregator

原理简介

kubernetes 引入Aggregation Layer机制,可以让用户方便的在核心API之外对k8s集群进行扩展。安装配置好集群后aggregation会运行在kube-apiserver进程里面,用户通过在集群中创建一个APIService对象,在其中设定对应的URL(路径 /apis/{group}/{version}/...),之后访问这个路径,API server会将请求转发到具体的后端服务,一般情况下,通过extension-apiserver服务实现,这个服务会作为一个pod运行在k8s集群中。

  1. 用户访问extension-apiserver的过程如下

    • 用户访问API server,提供需要的认证凭证
    • API server通过请求后(认证和鉴权),把请求代理到extension-apiserver服务
    • Extension-apiserver从API server处获取必要的信息,并对过来的请求进行认证
    • Extension apiserver对发起请求的用户进行鉴权
    • Extension apiserver开始执行相应的方法
  2. API server通过以下配置项向extension-apiserver提供访问的证书以及用户信息

    • --proxy-client-key-file 访问extension-apiserver的证书对应的私钥
    • --proxy-client-cert-file 访问extension-apiserver的证书
    • --requestheader-username-headers 请求头中标记用户名称的key
    • -requestheader-group-headers 请求头中标记用户组的key
    • --requestheader-extra-headers-prefix 请求头中标记其他额外信息的key
    • --requestheader-client-ca-file 用来签名proxy-client-cert-file对应证书的ca,这个ca会被API server会放到一个特定的configmap中,供Extension apiserver使用
    • --requestheader-allowed-names 有效的Common Name值(CNs),如果设置了这个值,则proxy-client-cert-file中设置的CN值要在--requestheader-allowed-names设定的列表中,这个值为空,代表接受任意cn值

    当API server有以上配置项时,API server会在kube-system命名空间下生成一个configmap:extension-apiserver-authentication,里面包含--requestheader* 相关的配置信息。Extension-apiserver要想对API server的请求认证,需要先拿到这个configmap中的信息,可以通过给Extension-apiserver使用的serviceAccount赋予kube-system:extension-apiserver-authentication-reader这个角色来实现。

    目前API server没有以上配置项时也会产生这个configmap,对应的内容如下

    root@master:/opt/k8s/work# kubectl get configmaps -n kube-system extension-apiserver-authentication  -o yaml
    apiVersion: v1
    data:
    client-ca-file: |
    -----BEGIN CERTIFICATE-----
    MIIDmjCCAoKgAwIBAgIUMgmbH118p4mkwRHqgFl3bltHX1MwDQYJKoZIhvcNAQEL
    BQAwZTELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB05hbkppbmcxEDAOBgNVBAcTB05h
    bkppbmcxDDAKBgNVBAoTA2s4czEPMA0GA1UECxMGc3lzdGVtMRMwEQYDVQQDEwpr
    NQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
    HQ4EFgQUcyfeeyf0LulhElMz7x4YXC7FBXIwDQYJKoZIhvcNAQELBQADggEBAHvN
    18jceQ9BthnxFNoCZ5yjiQGQViVcaw76gEm/OrmxKGFUXJyDmZghP+gjJ8ZOADZ9
    Brw+F66ULWMBfFQrESUf3nnnaScFdrZ9TcoKDPPhzibOfEqGMf6RNFTjlWk11ZUl
    qPTPmkJlGqMGvRgPMPm2xwucE5+o762C94iLFBfmqaS/FHGsoR7hfGSEAn0q9by5
    SotQpHpAt5tzE8N7KEXFIDOr8LlbXOd/lLn1+G84NY8lWWcARFgvAuOFgKQqfenm
    ezrX/nv45OvuKBYVf7o+8CXfoTK7vc7RTtqWHA+zNbjly7IaYeaPyDxQqWSY6cBZ
    Fzh51DLVlbmTyeagMXo=
    -----END CERTIFICATE-----
    kind: ConfigMap
    metadata:
    creationTimestamp: "2020-02-09T12:04:05Z"
    name: extension-apiserver-authentication
    namespace: kube-system
    resourceVersion: "21"
    selfLink: /api/v1/namespaces/kube-system/configmaps/extension-apiserver-authentication
    uid: 6cb1a94e-78e5-49c9-8f5a-ae8183f8de96
    • 里面只包含一个ca证书

    Extension-apiserver 要对请求的user进行鉴权,需要先发送一个SubjectAccessReview请求到API server,为了能够发送这个请求还需要给xtension-apiserver使用的serviceAccount赋予system:auth-delegator这个角色

配置API server启用aggregator功能

启用aggregation功能需要在kube-apiserver配置项中追加如下信息

--requestheader-client-ca-file=<path to aggregator CA cert>
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=<path to aggregator proxy cert>
--proxy-client-key-file=<path to aggregator proxy key>

如果运行API server的机器上没有运行kube-proxy进程,还需要追加如下一个配置项

--enable-aggregator-routing=true

CA 冲突问题

启用了aggregation功能后,API server会有两个配置

  • --client-ca-file
  • --requestheader-client-ca-file

如果配置不好,会造成CA冲突

  • client-ca-file:当一个请求到达API server时,用这个CA对请求携带的证书进行认证如kubectl、controller-manager、kubelet等组件请求API server。如果请求携带的证书是被这个CA签发的就被当作合法请求,之后证书中CN对应的值作为请求的用户,证书中的O对应的值作为请求的用户组。
  • requestheader-client-ca-file 正常情况下这个证书只是让扩展的API服务来对API server的身份进行认证的,不应该用到别的地方。但是如果这个值配置的话,当一个请求到达API server时,API server也会检查请求携带的证书是否是否是被这个CA签名的,如果是被这个签名的会再判断证书中的CN是否在requestheader-allowed-names指定的名称列表中,如果在里面,请求才会被允许通过,否则请求被拒绝。

当两者都配置后,API server会先检查证书是否被requestheader-client-ca-file签名,不是时才会用client-ca-file来判断。所以一般情况下这两个ca要不一致,如果两个配置的一样,可能会造成原来能正常访问API server的证书在API server启用aggregator不能再访问了,因为有可能原来正常访问的证书中的CN不在requestheader-allowed-names这个列表中,(官方文档说法,实际使用时测试了下,用同一个ca,没有报错,不知道是什么原因)

  1. 生成 client ca,要安装cfssl工具集cfssl

    1. 签名配置文件

      cd /opt/k8s/work
      cat > client-ca-config.json <<EOF
      {
      "signing": {
      "default": {
      "expiry": "87600h"
      },
      "profiles": {
      "kubernetes": {
      "usages": [
      "signing",
      "key encipherment",
      "server auth",
      "client auth"
      ],
      "expiry": "87600h"
      }
      }
      }
      }
      EOF
    2. 证书请求文件

      cd /opt/k8s/work
      cat > client-ca-csr.json <<EOF
      {
      "CN": "kubernetes",
      "key": {
      "algo": "rsa",
      "size": 2048
      },
      "names": [
      {
      "C": "CN",
      "ST": "NanJing",
      "L": "NanJing",
      "O": "k8s",
      "OU": "system"
      }
      ],
      "ca": {
      "expiry": "87600h"
      }
      }
      EOF
    3. 生成客户端根证书

      cd /opt/k8s/work
      cfssl gencert -initca client-ca-csr.json | cfssljson -bare client-ca
      ls client-ca*.pem
    4. 将证书放到k8s证书目录(多个API server节点时,其他节点也要分发)

      cd /opt/k8s/work
      
      cp client-ca*.pem client-ca-config.json /etc/kubernetes/cert/
      
      
  2. 生成proxy用证书

    1. 证书请求文件

      cd /opt/k8s/work
      cat > proxy-client-csr.json <<EOF
      {
      "CN": "front-proxy-client",
      "hosts": [],
      "key": {
      "algo": "rsa",
      "size": 2048
      },
      "names": [
      {
      "C": "CN",
      "ST": "NanJing",
      "L": "NanJing",
      "O": "k8s",
      "OU": "system"
      }
      ]
      }
      EOF
      • 证书中的CN要和API server中配置的--requestheader-allowed-names参数中
    2. 生成证书


      cfssl gencert -ca=/etc/kubernetes/cert/client-ca.pem \
      -ca-key=/etc/kubernetes/cert/client-ca-key.pem \
      -config=/etc/kubernetes/cert/client-ca-config.json \
      -profile=kubernetes proxy-client-csr.json | cfssljson -bare proxy-client
      ls proxy-client*.pem
    3. 将证书放到k8s证书目录(多个API server节点时,其他节点也要分发)

      cd /opt/k8s/work
      
      cp proxy-client*.pem /etc/kubernetes/cert/
      
      
  3. 配置API server追加如下配置项

    --requestheader-client-ca-file=/etc/kubernetes/cert/client-ca.pem
    --requestheader-allowed-names=front-proxy-client
    --requestheader-extra-headers-prefix=X-Remote-Extra-
    --requestheader-group-headers=X-Remote-Group
    --requestheader-username-headers=X-Remote-User
    --proxy-client-cert-file=/etc/kubernetes/cert/proxy-client.pem
    --proxy-client-key-file=/etc/kubernetes/cert/proxy-client-key.pem

    重启API server

    systemctl daemon-reload
    systemctl restart kube-apiserver

    对应的extension-apiserver-authentication中的内容

    root@master:/opt/k8s/work# kubectl get configmaps -n kube-system extension-apiserver-authentication  -o yaml
    apiVersion: v1
    data:
    client-ca-file: |
    -----BEGIN CERTIFICATE-----
    MIIDmjCCAoKgAwIBAgIUMgmbH118p4mkwRHqgFl3bltHX1MwDQYJKoZIhvcNAQEL
    BQAwZTELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB05hbkppbmcxEDAOBgNVBAcTB05h
    ...
    Fzh51DLVlbmTyeagMXo=
    -----END CERTIFICATE-----
    requestheader-allowed-names: '["front-proxy-client"]'
    requestheader-client-ca-file: |
    -----BEGIN CERTIFICATE-----
    MIIDmjCCAoKgAwIBAgIULBdSC4QJy1MBYwGDb0b9g7YMDH0wDQYJKoZIhvcNAQEL
    ...
    QKHtdMypc3mPUO6sBcY=
    -----END CERTIFICATE-----
    requestheader-extra-headers-prefix: '["X-Remote-Extra-"]'
    requestheader-group-headers: '["X-Remote-Group"]'
    requestheader-username-headers: '["X-Remote-User"]'
    kind: ConfigMap
    metadata:
    creationTimestamp: "2020-02-09T12:04:05Z"
    name: extension-apiserver-authentication
    namespace: kube-system
    resourceVersion: "2930987"
    selfLink: /api/v1/namespaces/kube-system/configmaps/extension-apiserver-authentication
    uid: 6cb1a94e-78e5-49c9-8f5a-ae8183f8de96
    • 追加了requestheader*相关的一些信息

metrics-server 安装

在安装metrics-server之前,虽然kubelet收集了系统信息,但是这些信息只能通过kubelet的接口进行访问,调用kubectl top nodes会报如下错误

$ kubectl top nodes
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
  1. 下载metrics-server对应的镜像,上传到自己的私有镜像库中

    docker pull gcr.azk8s.cn/google_containers/metrics-server-amd64:v0.3.6
    
    docker tag gcr.azk8s.cn/google_containers/metrics-server-amd64:v0.3.6 192.168.0.107/k8s/metrics-server-amd64:v0.3.6
    
    docker push 192.168.0.107/k8s/metrics-server-amd64:v0.3.6
    
    
  2. 下载metrics-server启动文件

    $ cd /opt/k8s/work/
    $ wget https://github.com/kubernetes-sigs/metrics-server/archive/master.zip $ unzip master.zip
    $ cd metrics-server-master/deploy/kubernetes
  3. 修改 metrics-server-deployment.yaml 文件,为 metrics-server 添加两个命令行参数,并修改镜像名称,指向自己的私有仓库

    $ diff metrics-server-deployment.yaml metrics-server-deployment.yaml.bak
    32c32
    < image: 192.168.0.107/k8s/metrics-server-amd64:v0.3.6
    ---
    > image: k8s.gcr.io/metrics-server-amd64:v0.3.6
    36,37d35
    < - --metric-resolution=30s
    < - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
    • kubelet-preferred-address:优先选择用IP访问kubelet,否则会用主机的hostname来访问,默认安装的coreDns不支持hostname的解析,也可通过修改coreDNS的配置文件,追加 hosts配置

      ...
      Corefile: |
      .:53 {
      errors
      health hosts {
      192.168.0.107 master
      192.168.0.114 slave
      fallthrough
      }
      ...
  4. 启动metrics-server

    $ cd /opt/k8s/work/metrics-server-master/deploy/kubernetes
    
    $ kubectl create -f .
    clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
    clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
    rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
    apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
    serviceaccount/metrics-server created
    deployment.apps/metrics-server created
    service/metrics-server created
    clusterrole.rbac.authorization.k8s.io/system:metrics-server created
    clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
  5. 查看运行情况

    $ kubectl -n kube-system get all -l k8s-app=metrics-server
    NAME READY STATUS RESTARTS AGE
    pod/metrics-server-857d7c4878-swpvk 1/1 Running 0 72s NAME READY UP-TO-DATE AVAILABLE AGE
    deployment.apps/metrics-server 1/1 1 1 72s NAME DESIRED CURRENT READY AGE
    replicaset.apps/metrics-server-857d7c4878 1 1 1 72s
  6. 查看 metrics-server 输出的 metrics

    $ kubectl get --raw https://192.168.0.107:6443/apis/metrics.k8s.io/v1beta1/nodes | jq .
    {
    "kind": "NodeMetricsList",
    "apiVersion": "metrics.k8s.io/v1beta1",
    "metadata": {
    "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"
    },
    "items": [
    {
    "metadata": {
    "name": "master",
    "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/master",
    "creationTimestamp": "2020-02-27T09:30:12Z"
    },
    "timestamp": "2020-02-27T09:29:35Z",
    "window": "30s",
    "usage": {
    "cpu": "414650216n",
    "memory": "6069004Ki"
    }
    },
    {
    "metadata": {
    "name": "slave",
    "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/slave",
    "creationTimestamp": "2020-02-27T09:30:12Z"
    },
    "timestamp": "2020-02-27T09:29:35Z",
    "window": "30s",
    "usage": {
    "cpu": "80942639n",
    "memory": "2393408Ki"
    }
    }
    ]
    }
    $ kubectl top nodes
    NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
    master 427m 10% 5928Mi 76%
    slave 92m 2% 2335Mi 62%

遇到问题

启动完后,服务都正常,获取不到指标信息

$ kubectl top nodes
Error from server (ServiceUnavailable): the server is currently unable to handle the request (get nodes.metrics.k8s.io)

kube-apiserver 服务中一直出现下面的错

E0227 16:52:50.472445   19192 available_controller.go:419] v1beta1.metrics.k8s.io failed with: failing or missing response from https://10.0.0.96:443/apis/metrics.k8s.io/v1beta1: bad status from https://10.0.0.96:443/apis/metrics.k8s.io/v1beta1: 403 

按照这个错,应该是kube-apiserver访问metrics-server时权限不足,可我们明明提供了proxy*相关的参数,最后再一次检查kube-apiserver的启动文件,发现--proxy-client-cert-file参数后面少了个分行符

  • 错误

    --proxy-client-cert-file=/etc/kubernetes/cert/proxy-client.pem
    --proxy-client-key-file=/etc/kubernetes/cert/proxy-client-key.pem \
  • 正确

    --proxy-client-cert-file=/etc/kubernetes/cert/proxy-client.pem \
    --proxy-client-key-file=/etc/kubernetes/cert/proxy-client-key.pem \

最新文章

  1. Object obj=new Object()的内存引用
  2. [BZOJ4199][NOI2015]品酒大会
  3. Mango Weekly Training Round #6 解题报告
  4. 20145105 《Java程序设计》第2周学习总结
  5. HDU 1432 Lining Up (POJ 1118)
  6. 如何让sql自动定时执行某个存储过程
  7. EFcore与动态模型(二)
  8. 每天一个Linux命令(03)--pwd
  9. Ext JS 6学习文档–第1章–ExtJS入门指南
  10. Java是如何解析xml文件的(DOM)
  11. FatMouse and Cheese
  12. 基于etcd的Rabbitmq队列订阅负载均衡
  13. Codeforces278E Tourists
  14. C++ otlv4 连接 sql server 数据库小记
  15. 2015年上海现场赛重现 (A几何, K暴力搜索)
  16. Java之ArrayList自定义排序,通过实现comparator比较器接口
  17. 永久有效的 webstorm license server 20180808
  18. linux 正则表达式
  19. 图形图像的绘制 GandyDraw
  20. Android Hook框架Xposed详解

热门文章

  1. Dappy如何防止DNS黑客入侵
  2. 移除sitemap中的entity
  3. laravel5.5的服务容器分析
  4. android开发实战-记账本APP(一)
  5. SSM 配置文件 分析
  6. BeautifulSoup标签定位方法总结
  7. 【WPF学习】第三十五章 资源字典
  8. 【动手学pytorch】softmax回归
  9. Huffman编码和解码
  10. 从免费的物联网防火墙hihttps谈机器学习之生成对抗规则