1. 程式人生 > 程式設計 >k8s 監控(二)監控叢集元件和 pod

k8s 監控(二)監控叢集元件和 pod

在上一篇文章中,我們已經在 k8s 中安裝了 Prometheus,並且收集了它自身的監控指標。而在這篇文章,我們將收集 k8s 所有元件和 pod 的監控指標。

在這之前需要先修改下之前監控 Prometheus 自身使用的一個配置,因為它來源於 prometheus-operator,更多的是我對它使用這個配置的理解。而我們自己直接使用的話,沒有必要搞這麼麻煩,下面是修改後的內容。

- job_name: prometheus
  honor_labels: false
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
names: - monitoring scrape_interval: 30s relabel_configs: - action: keep source_labels: - __meta_kubernetes_service_label_prometheus regex: k8s - source_labels: - __meta_kubernetes_namespace target_label: namespace - source_labels: -
__meta_kubernetes_service_name target_label: service - source_labels: - __meta_kubernetes_pod_name target_label: pod - target_label: endpoint replacement: web 複製程式碼

這一看就懂,我也就不多做解釋了。下面我們開始進入正題,首先監控 etcd。

監控 etcd

之前我們通過 curl 命令訪問到了 etcd 監控指標所在的 URL,知道了它的監控指標有哪些,現在我們要配置 Prometheus,讓其收集這些監控資料。

之前也提到過,k8s 中 Prometheus 的監控是通過發現 endpoint 的方式進行,而 endpoint 又是 service 建立的,所以我們需要先建立一個 etcd 的 service。

我們新建一個名為 kube-etcd-service.yml 的檔案,內容如下:

apiVersion: v1
kind: Service
metadata:
  name: kube-etcd
  labels:
    k8s-app: kube-etcd
  namespace: kube-system
spec:
  clusterIP: None
  ports:
    - name: http-metrics
      port: 2379
      protocol: TCP
      targetPort: 2379
  selector:
    component: etcd
  type: ClusterIP
複製程式碼

說明:

  • 由於 etcd 處於 kube-system 名稱空間,所以這裡的 namespace 也應該是 kube-system;
  • 因為 etcd pod 本身會存在 component=etcd 這個標籤,所以這裡的選擇器使用的就是這個。
kubectl apply -f kube-etcd-service.yml
複製程式碼

建立成功後,可以通過如下命令檢視它建立的 endpoint:

kubectl -n kube-system get endpoints kube-etcd
複製程式碼

現在通過這個 endpoint 就能夠訪問到後面三臺 etcd,現在只需要在 Prometheus 中新增對應的配置即可,配置內容如下。

- job_name: kube-etcd
  honor_labels: false
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - kube-system
  scheme: https
  tls_config:
    insecure_skip_verify: false
    ca_file: /etc/prometheus/secrets/etcd-client-cert/ca.crt
    cert_file: /etc/prometheus/secrets/etcd-client-cert/healthcheck-client.crt
    key_file: /etc/prometheus/secrets/etcd-client-cert/healthcheck-client.key
  relabel_configs:
    - action: keep
      source_labels:
        - __meta_kubernetes_service_label_k8s_app
      regex: kube-etcd
    - source_labels:
        - __meta_kubernetes_namespace
      target_label: namespace
    - source_labels:
        - __meta_kubernetes_service_name
      target_label: service
    - source_labels:
        - __meta_kubernetes_pod_name
      target_label: pod
    - target_label: endpoint
      replacement: http-metrics
  metric_relabel_configs:
    - action: drop
      regex: (etcd_debugging|etcd_disk|etcd_request|etcd_server|grpc_server).*
      source_labels:
        - __name__
複製程式碼

因為訪問 etcd 需要驗證客戶端證書,所以這裡需要提供證書和私鑰檔案。這三個檔案之前都已掛載到 Prometheus 容器中,直接拿來用就行。

下面的 relabel_configs 就不多提了,和前面監控 Prometheus 自身的配置差不多,最主要的還是 metric_relabel_configs,它是用來刪除我們不需要的監控指標的。

這裡將以 etcd_debugging|etcd_disk|etcd_request|etcd_server|grpc_server 這些開頭的監控指標都刪掉了,你們不要學我,最好搞清楚它的作用來決定是不是將其刪掉,我純粹是看不懂所以才刪的。

最後將上面的內容貼上進 prometheus-config.yml。當你 apply 配置檔案後,不要急著 reload,因為 Prometheus 中可能沒有立即更新,你可以通過 kubectl exec -it 連線到 Prometheus 的 pod 中驗證下配置檔案是否已經更新。

如果更新了,就直接通過下面命令讓其 reload:

curl -XPOST PROMETHEUS_IP:9090/-/reload
複製程式碼

然後訪問 Prometheus 的 web 頁面,就可以在 targets 中看到 etcd 了。

監控 apiserver

apiserver 的監控方式更簡單,因為它的 service 已經自動建立了。但你需要注意的是,它的 service 建立在 default 名稱空間,名為 kubernetes

沒什麼好說的,直接放出 Prometheus 監控 apiserver 的配置。

- job_name: kube-apiserver
  honor_labels: false
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - default
  scrape_interval: 30s
  scheme: https
  tls_config:
    insecure_skip_verify: false
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    server_name: kubernetes
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    - action: keep
      source_labels:
        - __meta_kubernetes_service_label_component
      regex: apiserver
  metric_relabel_configs:
    - source_labels:
        - __name__
      action: drop
      regex: (apiserver_storage_data_key_generation_latencies_microseconds_bucket|apiserver_admission_controller_admission_latencies_milliseconds_bucket|apiserver_admission_step_admission_latencies_milliseconds_bucket|apiserver_admission_step_admission_latencies_milliseconds_summary|apiserver_request_latencies_bucket|apiserver_request_latencies_summary|apiserver_storage_data_key_generation_latencies_microseconds_bucket|rest_client_request_latency_seconds_bucket)
複製程式碼

這裡因為 insecure_skip_verify 設為了 false,也就是校驗服務端證書,所以這裡提供了 ca 檔案和 server_name。同樣,這個證書事先已經掛載到了容器中,所以直接指定就行。

因為我不想關注的指標太多,所以刪了一批。先宣告,我是瞎刪的,並不懂它們的確切意義,只是覺得沒啥用,所以就刪了,你們別學我!

最後你看著 reload 吧。

監控 pod

pod 的監控指標是 kubelet 提供的,前面也已經使用 curl 命令看到了,因此這裡也是直接幹。

我不知道是我之前手動建立的還是怎樣,我這裡已經存在了 kubelet 的 service,並且 service 只暴露了 10250 這一個埠,但是在其對應的 endpoint 上,卻有以下三個埠。

ports:
  - name: http-metrics
    port: 10255
    protocol: TCP
  - name: cadvisor
    port: 4194
    protocol: TCP
  - name: https-metrics
    port: 10250
    protocol: TCP
複製程式碼

如果你們不是這種情況,那就自己建立一個 service。如果也是這種情況,那在 relabel_configs 中,不僅要對 service 標籤進行過濾,還得對埠進行過濾,因為我們只需要 10250 埠。

它的配置如下:

- job_name: pods
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - kube-system
  scrape_interval: 30s
  metrics_path: /metrics/cadvisor
  scheme: https
  tls_config:
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    - action: keep
      source_labels:
        - __meta_kubernetes_service_label_k8s_app
      regex: kubelet
    - action: keep
      source_labels:
        - __meta_kubernetes_endpoint_port_name
      regex: https-metrics
    - source_labels:
        - __meta_kubernetes_namespace
      target_label: namespace
    - source_labels:
        - __meta_kubernetes_service_name
      target_label: service
    - source_labels:
        - __meta_kubernetes_pod_name
      target_label: pod
    - target_label: endpoint
      replacement: https-metrics
  metric_relabel_configs:
    - source_labels:
        - __name__
      regex: container_(cpu_cfs_periods_total|fs_inodes_total|fs_sector_reads_total|fs_sector_writes_total|last_seen|memory_mapped_file|memory_working_set_bytes|spec_memory_reservation_limit_bytes|spec_memory_swap_limit_bytes|tasks_state)
      action: drop
    - source_labels:
        - container
      regex: ""
      action: drop
    - action: labeldrop
      regex: (id|name|pod_name|image)
複製程式碼

上面通過下面這個配置從三個埠中篩選出我們所需要的 10250 埠,因為它的名稱為 https-metrics:

- action: keep
  source_labels:
    - __meta_kubernetes_endpoint_port_name
  regex: https-metrics
複製程式碼

後面的 metric_relabel_configs 中,除了刪除了一些我認為沒用的監控指標外,還刪除了所有 container 標籤為空的監控指標,就像這些:

container_memory_cache{container="",container_name="",id="/",image="",name="",namespace="",pod="",pod_name=""} 2.144395264e+09 1565777155746
container_memory_cache{container="",id="/kubepods.slice",pod_name=""} 7.14027008e+08 1565777155757
container_memory_cache{container="",id="/kubepods.slice/kubepods-besteffort.slice",pod_name=""} 3.5053568e+08 1565777145294
container_memory_cache{container="",id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-poda213e57700fd1325c59a70dd70f1a07d.slice",namespace="kube-system",pod="etcd-ops.k8s.master.01.sit",pod_name="etcd-ops.k8s.master.01.sit"} 3.09784576e+08 1565777149076
container_memory_cache{container="",id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podcfdbebf5_8211_11e9_8699_005056a7c0c5.slice",pod="kube-proxy-xw8sw",pod_name="kube-proxy-xw8sw"} 4.0767488e+07 1565777147425
複製程式碼

實在不知道這些是幹啥的,而且數量非常多,乾脆直接刪掉。同時還刪除了一些標籤,比如下面這種的:

container_fs_io_current{container="coredns",container_name="coredns",device="/dev/mapper/centos-root",endpoint="https-metrics",id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-poda9693624_85e3_11e9_80cb_005056a7c0c5.slice/docker-9b95ca870a0e7a8fde7ce116b07fc696bd91bea75f6bc61478f3ecc98f36f131.scope",image="sha256:eb516548c180f8a6e0235034ccee2428027896af16a509786da13022fe95fe8c",instance="10.99.100.2:10250",job="pods",name="k8s_coredns_coredns-fb8b8dccf-9dvh7_kube-system_a9693624-85e3-11e9-80cb-005056a7c0c5_2",pod="coredns-fb8b8dccf-9dvh7",pod_name="coredns-fb8b8dccf-9dvh7",service="kubelet"}
複製程式碼

可以看到 id、name 和 image 這些標籤的值非常長,不好看不說,還浪費記憶體和儲存資源,我就都刪了。它貌似會造成一個 pod 中如果有多個容器,你可能無法知道這個容器是監控指標中是哪一個,因為 image 這個標籤被刪了。

反正我刪了,你看著辦。刪除之後就是這樣:

container_fs_io_current{container="coredns",service="kubelet"}
複製程式碼

當然很多標籤是我們自己建立,如果你不需要,可以在上面的 relabel_configs 中刪除對應標籤的配置。或許你還想刪其他的標籤,那你往上面的配置中加就行。

最後記得 reload。

安裝 kube-state-metrics

k8s 的其他元件我就不繼續監控了,包括 kubelet、controller manager、coredns 等,它們監控的手段和之前的幾個元件都差不多,相信你們自己弄起來也是輕輕鬆鬆。

下面我們會安裝 kube-state-metrics,這個東西會連線 apiserver,然後將叢集裡的各種資源的指標都暴露出來,比如 configMap、ingress、secret、pod、deployment、statefulset 等,這是對 pod 指標的一大補充,非常有用。

RBAC 許可權

因為它要訪問叢集內的所有資源,才能將它們的資訊提供出去,因此部署它之前,先為它建立一些許可權。這些許可權都會繫結到一個 serviceAccount 上,然後我們用這個 sa 執行 kube-state-metrics 就行。

kube-state-metrics-clusterRole.yml:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kube-state-metrics
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - secrets
      - nodes
      - pods
      - services
      - resourcequotas
      - replicationcontrollers
      - limitranges
      - persistentvolumeclaims
      - persistentvolumes
      - namespaces
      - endpoints
    verbs:
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - daemonsets
      - deployments
      - replicasets
      - ingresses
    verbs:
      - list
      - watch
  - apiGroups:
      - apps
    resources:
      - statefulsets
      - daemonsets
      - deployments
      - replicasets
    verbs:
      - list
      - watch
  - apiGroups:
      - batch
    resources:
      - cronjobs
      - jobs
    verbs:
      - list
      - watch
  - apiGroups:
      - autoscaling
    resources:
      - horizontalpodautoscalers
    verbs:
      - list
      - watch
  - apiGroups:
      - authentication.k8s.io
    resources:
      - tokenreviews
    verbs:
      - create
  - apiGroups:
      - authorization.k8s.io
    resources:
      - subjectaccessreviews
    verbs:
      - create
  - apiGroups:
      - policy
    resources:
      - poddisruptionbudgets
    verbs:
      - list
      - watch
  - apiGroups:
      - certificates.k8s.io
    resources:
      - certificatesigningrequests
    verbs:
      - list
      - watch
複製程式碼

kube-state-metrics-clusterRoleBinding.yml:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kube-state-metrics
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kube-state-metrics
subjects:
  - kind: ServiceAccount
    name: kube-state-metrics
    namespace: monitoring
複製程式碼

kube-state-metrics-role.yml:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: kube-state-metrics
  namespace: monitoring
rules:
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
  - apiGroups:
      - extensions
    resourceNames:
      - kube-state-metrics
    resources:
      - deployments
    verbs:
      - get
      - update
  - apiGroups:
      - apps
    resourceNames:
      - kube-state-metrics
    resources:
      - deployments
    verbs:
      - get
      - update
複製程式碼

kube-state-metrics-roleBinding.yml:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kube-state-metrics
  namespace: monitoring
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kube-state-metrics
subjects:
  - kind: ServiceAccount
    name: kube-state-metrics
複製程式碼

kube-state-metrics-serviceAccount.yml:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube-state-metrics
  namespace: monitoring
複製程式碼

deployment 和 service

kube-state-metrics 會提供兩個指標頁面,一個是暴露叢集內資源的,另一個是它自身的,它自身的可以選擇性的關注。

先建立 kube-state-metrics-deployment.yml:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: kube-state-metrics
  name: kube-state-metrics
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kube-state-metrics
  template:
    metadata:
      labels:
        app: kube-state-metrics
    spec:
      containers:
        - args:
            - --port=10000
            - --telemetry-port=10001
          image: quay.io/coreos/kube-state-metrics:v1.6.0
          name: kube-state-metrics
          resources:
            limits:
              cpu: 100m
              memory: 150Mi
            requests:
              cpu: 100m
              memory: 150Mi
        - command:
            - /pod_nanny
            - --container=kube-state-metrics
            - --cpu=100m
            - --extra-cpu=2m
            - --memory=150Mi
            - --extra-memory=30Mi
            - --threshold=5
            - --deployment=kube-state-metrics
          env:
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.name
            - name: MY_POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
          image: k8s.gcr.io/addon-resizer:1.8.4
          name: addon-resizer
          resources:
            limits:
              cpu: 50m
              memory: 30Mi
            requests:
              cpu: 10m
              memory: 30Mi
      nodeSelector:
        kubernetes.io/os: linux
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534
      serviceAccountName: kube-state-metrics
複製程式碼

指定了兩個啟動引數,也就是兩個埠,其中 10000 是暴露叢集資源指標的埠,10001 就是它自身了。除了 kube-state-metrics 之外,還啟動了 addon-resizer 這個容器,我不知道它是幹啥的,反正官方怎麼搞我們怎麼弄就是了。

最後是 service 檔案 kube-state-metrics-service.yml:

apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: kube-state-metrics
  name: kube-state-metrics
  namespace: monitoring
spec:
  clusterIP: None
  ports:
    - name: http-main
      port: 10000
      targetPort: 10000
    - name: http-self
      port: 10001
      targetPort: 10001
  selector:
    app: kube-state-metrics
複製程式碼

兩個埠都暴露出來,你可以都收集或者只收集 10000 埠。如果只收集 10000,你可以只暴露一個埠,也可以兩個都暴露,然後在 Prometheus 配置中過濾掉一個埠即可。

收集監控資料

將上面所有的檔案都 apply 之後,就可以直接配置 Prometheus 進行收集了。在此之前,你可以使用 curl 命令訪問它的指標頁面,看看裡面都有啥:

curl IP:10000/metrics
curl IP:10001/metrics
複製程式碼

這個 ip 地址不用我說怎麼拿吧,然後你就可以看到叢集資源的指標非常非常非常的多,我覺得你最好對其進行過濾,將不需要的統統拒絕掉,不然對 Prometheus 造成的壓力很大。

然後下面就是 Prometheus 的配置:

- job_name: kube-state-metrics
  honor_labels: true
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - monitoring
  scrape_interval: 30s
  scrape_timeout: 30s
  tls_config:
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    - action: keep
      source_labels:
        - __meta_kubernetes_service_label_k8s_app
      regex: kube-state-metrics
    - action: keep
      source_labels:
        - __meta_kubernetes_endpoint_port_name
      regex: http-main
  metric_relabel_configs:
    - source_labels:
        - __name__
      regex: (kube_daemonset_status_number_ready|kube_daemonset_status_number_unavailable|kube_deployment_status_replicas_unavailable|kube_deployment_spec_paused|kube_deployment_spec_strategy_rollingupdate_max_surge|kube_deployment_spec_strategy_rollingupdate_max_unavailable|kube_endpoint_address_available|kube_endpoint_address_not_ready|kube_node_info|kube_node_spec_unschedulable|kube_node_status_condition|kube_node_status_capacity|kube_node_status_capacity|kube_node_status_allocatable|kube_persistentvolumeclaim_info|kube_persistentvolumeclaim_status_phase|kube_persistentvolumeclaim_resource_requests_storage_bytes|kube_persistentvolume_status_phase|kube_persistentvolume_info|kube_persistentvolume_capacity_bytes|kube_pod_info|kube_pod_status_phase|kube_pod_status_ready|kube_pod_container_info|kube_pod_container_status_waiting|kube_pod_container_status_waiting_reason|kube_pod_container_status_running|kube_pod_container_status_terminated_reason|kube_pod_container_status_last_terminated_reason|kube_pod_container_status_restarts_total|kube_pod_container_resource_limits|kube_service_info|kube_statefulset_status_replicas_current|kube_statefulset_status_replicas_ready)
      action: keep
複製程式碼

配置的內容就無需我多提了,和前面監控的配置都差不多。

主要是這裡刪除了一大批我不關注的指標,注意我這裡做的是白名單,只收集我指定的,因為不需要的實在太多,寫不過來。雖然正則表示式這麼長,但是由於指標名稱短,且 regex 預設錨定了行首和行尾,所以匹配效率還是很高的。

最後記得 reload。

ok,本文到此為止,下一篇會提到如何使用 grafana 和 alertmanager,謝謝!