總體設計思想
-
設計介紹
監控分成兩個部分
-
核心指標流程 包括的組件有 kubelet、resource estimator、metrics-server、API server。這些指標被kubernetes的核心組件使用:kubectl、sheduler、HPA。指標數據流轉如上圖中黑色部分所示,具體過程如下:
-
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服務的端口
-
metrics-server 組件通過調用kubelet的接口將信息匯總起來,雖然kubelet通過cAdvisor收集了很多信息,metrics-server只會取其中的一部分給用戶。如果通過k8s提供的安裝腳本kube-up.sh來安裝集群,默認會直接安裝metrics-server,如果是自己安裝集群需要自己手動安裝,參考metrics-server安裝。
-
metrics-server 組件收集好需要的指標信息后不會直接面向用戶提供可用的API,而是通過 [Kubernetes aggregator](#Kubernetes aggregator)機制,將API注冊到k8s的API server中,之后用戶可以像操作通用API一樣 來獲取這些信息。
-
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集群中。
-
用戶訪問extension-apiserver的過程如下

- 用戶訪問API server,提供需要的認證憑證
- API server通過請求后(認證和鑒權),把請求代理到extension-apiserver服務
- Extension-apiserver從API server處獲取必要的信息,並對過來的請求進行認證
- Extension apiserver對發起請求的用戶進行鑒權
- Extension apiserver開始執行相應的方法
-
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,沒有報錯,不知道是什么原因)
-
生成 client ca,要安裝cfssl工具集cfssl
-
簽名配置文件
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 -
證書請求文件
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 -
生成客戶端根證書
cd /opt/k8s/work cfssl gencert -initca client-ca-csr.json | cfssljson -bare client-ca ls client-ca*.pem -
將證書放到k8s證書目錄(多個API server節點時,其他節點也要分發)
cd /opt/k8s/work cp client-ca*.pem client-ca-config.json /etc/kubernetes/cert/
-
-
生成proxy用證書
-
證書請求文件
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參數中
-
生成證書
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 -
將證書放到k8s證書目錄(多個API server節點時,其他節點也要分發)
cd /opt/k8s/work cp proxy-client*.pem /etc/kubernetes/cert/
-
-
配置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:)
-
下載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 -
下載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 -
修改 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 } ...
-
-
啟動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 -
查看運行情況
$ 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 -
查看 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 \

