背景
監控是保障系統穩定性的重要組成部分,在Kubernetes開源生態中,資源類的監控工具與元件監控百花齊放。
- cAdvisor:kubelet內建的cAdvisor,監控容器資源,如容器cpu、記憶體;
- Kube-state-metrics:kube-state-metrics通過監聽 API Server 生成有關資源物件的狀態指標,主要關注後設資料,比如 Deployment、Pod、副本狀態等;
- metrics-server:metrics-server 也是一個叢集範圍內的資源資料聚合工具,是 Heapster 的替代品,k8s的HPA元件就會從metrics-server中獲取資料;
- 還有node-exporter、各個官方、非官方的exporter,使用 Prometheus 來抓取這些資料然後儲存,告警,視覺化。但這些還遠遠不夠。
監控的實時性與準確性不足
大部分資源監控都是基於推或者拉的模式進行資料離線,因此通常資料是每隔一段時間採集一次,如果在時間間隔內出現一些毛刺或者異常,而在下一個採集點到達時恢復,大部分的採集系統會吞掉這個異常。而針對毛刺的場景,階段的採集會自動削峰,從而造成準確性的降低。
監控的場景覆蓋範圍不足
部分監控場景是無法通過資源表述的,比如Pod的啟動停止,是無法簡單的用資源的利用率來計量的,因為當資源為0的時候,我們是不能區分這個狀態產生的真實原因。
基於上述兩個問題,Kubernetes是怎麼解決的呢?
事件監控
在Kubernetes中,事件分為兩種,一種是Warning事件,表示產生這個事件的狀態轉換是在非預期的狀態之間產生的;另外一種是Normal事件,表示期望到達的狀態,和目前達到的狀態是一致的。我們用一個Pod的生命週期進行舉例,當建立一個Pod的時候,首先Pod會進入Pending的狀態,等待映象的拉取,當映象錄取完畢並通過健康檢查的時候,Pod的狀態就變為Running。此時會生成Normal的事件。而如果在執行中,由於OOM或者其他原因造成Pod宕掉,進入Failed的狀態,而這種狀態是非預期的,那麼此時會在Kubernetes中產生Warning的事件。那麼針對這種場景而言,如果我們能夠通過監控事件的產生就可以非常及時的檢視到一些容易被資源監控忽略的問題。
一個標準的Kubernetes事件有如下幾個重要的屬性,通過這些屬性可以更好地診斷和告警問題。
Namespace:產生事件的物件所在的名稱空間。
Kind:繫結事件的物件的型別,例如:Node、Pod、Namespace、Componenet等等。
Timestamp:事件產生的時間等等。
Reason:產生這個事件的原因。
Message: 事件的具體描述。
[root@master work]# kubectl get event --all-namespaces LAST SEEN TYPE REASON OBJECT MESSAGE default 14m Normal Created pod/busybox2 Created container busybox default 14m Normal Started pod/busybox2 Started container busybox default 24m Warning Failed pod/litemall-all-584bfdcd99-q6wd2 Error: ErrImagePull default 4m47s Warning Failed pod/litemall-all-584bfdcd99-q6wd2 Error: ImagePullBackOff
ali kube-eventer
針對Kubernetes的事件監控場景,Kuernetes社群在Heapter中提供了簡單的事件離線能力,後來隨著Heapster的廢棄,相關的能力也一起被歸檔了。為了彌補事件監控場景的缺失,阿里雲容器服務釋出並開源了kubernetes事件離線工具kube-eventer。支援離線kubernetes事件到釘釘機器人、SLS日誌服務、Kafka開源訊息佇列、InfluxDB時序資料庫等等。
GitHub地址:https://github.com/AliyunContainerService/kube-eventer
下面是以企業微信機器人告警傳送為例:
[root@node1 monitoring]# cat kube-eventer.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: name: kube-eventer name: kube-eventer namespace: kube-system spec: replicas: 1 selector: matchLabels: app: kube-eventer template: metadata: labels: app: kube-eventer annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: dnsPolicy: ClusterFirstWithHostNet serviceAccount: kube-eventer containers: - image: registry.aliyuncs.com/acs/kube-eventer-amd64:v1.2.0-484d9cd-aliyun name: kube-eventer command: - "/kube-eventer" - "--source=kubernetes:https://kubernetes.default" ## .e.g,dingtalk sink demo #- --sink=dingtalk:[your_webhook_url]&label=[your_cluster_id]&level=[Normal or Warning(default)] #- --sink=webhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=07055f32-a04e-4ad7-9cb1-d22352769e1c&level=Warning&label=oa-k8s - --sink=webhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=07055f32-a04e-4ad7-9cb1-d223&level=Warning&header=Content-Type=application/json&custom_body_configmap=custom-webhook-body&custom_body_configmap_namespace=kube-system&method=POST env: # If TZ is assigned, set the TZ value as the time zone - name: TZ value: "Asia/Shanghai" volumeMounts: - name: localtime mountPath: /etc/localtime readOnly: true - name: zoneinfo mountPath: /usr/share/zoneinfo readOnly: true resources: requests: cpu: 100m memory: 100Mi limits: cpu: 500m memory: 250Mi volumes: - name: localtime hostPath: path: /etc/localtime - name: zoneinfo hostPath: path: /usr/share/zoneinfo --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-eventer rules: - apiGroups: - "" resources: - events - configmaps verbs: - get - list - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-eventer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kube-eventer subjects: - kind: ServiceAccount name: kube-eventer namespace: kube-system --- apiVersion: v1 kind: ServiceAccount metadata: name: kube-eventer namespace: kube-system --- apiVersion: v1 data: content: >- {"msgtype": "text","text": {"content": "EventType:{{ .Type }}\nEventNamespace:{{ .InvolvedObject.Namespace }}\nEventKind:{{ .InvolvedObject.Kind }}\nEventObject:{{ .InvolvedObject.Name }}\nEventReason:{{ .Reason }}\nEventTime:{{ .LastTimestamp }}\nEventMessage:{{ .Message }}"}} kind: ConfigMap metadata: name: custom-webhook-body namespace: kube-system
效果: