Prometheus 持久化安裝
我們prometheus采用nfs掛載方式來存儲數據,同時使用configMap管理配置文件。並且我們將所有的prometheus存儲在kube-system
#建議將所有的prometheus yaml文件存在一塊 mkdir /opt/prometheus -p && cd /opt/prometheus生成配置文件
cat >> prometheus.configmap.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: kube-system
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_timeout: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
EOF配置文件解釋(這里的configmap實際上就是prometheus的配置)
上面包含了3個模塊global、rule_files和scrape_configs
其中global模塊控制Prometheus Server的全局配置
scrape_interval:表示prometheus抓取指標數據的頻率,默認是15s,我們可以覆蓋這個值
evaluation_interval:用來控制評估規則的頻率,prometheus使用規則產生新的時間序列數據或者產生警報rule_files模塊制定了規則所在的位置,prometheus可以根據這個配置加載規則,用於生產新的時間序列數據或者報警信息,當前我們沒有配置任何規則,后期會添加
scrape_configs用於控制prometheus監控哪些資源。由於prometheus通過http的方式來暴露它本身的監控數據,prometheus也能夠監控本身的健康情況。在默認的配置有一個單獨的job,叫做prometheus,它采集prometheus服務本身的時間序列數據。這個job包含了一個單獨的、靜態配置的目標;監聽localhost上的9090端口。
prometheus默認會通過目標的/metrics路徑采集metrics。所以,默認的job通過URL:http://localhost:9090/metrics采集metrics。收集到時間序列包含prometheus服務本身的狀態和性能。如果我們還有其他的資源需要監控,可以直接配置在該模塊下即可
然后創建該資源對象:
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config created
[root@k8s-01 prometheus]# kubectl get configmaps -n kube-system |grep prometheus prometheus-config 1 163m
配置文件創建完成,如果以后我們有新的資源需要被監控,我們只需要將ConfigMap
對象更新即可,現在我們開始創建prometheus的Pod資源
[root@k8s-01 prometheus]# cat > prometheus.deploy.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: prometheus namespace: kube-system labels: app: prometheus spec: selector: matchLabels: app: prometheus template: metadata: labels: app: prometheus spec: serviceAccountName: prometheus containers: - image: prom/prometheus:v2.4.3 name: prometheus command: - "/bin/prometheus" args: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention=30d" - "--web.enable-admin-api" # 控制對admin HTTP API的訪問,其中包括刪除時間序列等功能 - "--web.enable-lifecycle" # 支持熱更新,直接執行localhost:9090/-/reload立即生效 ports: - containerPort: 9090 protocol: TCP name: http volumeMounts: - mountPath: "/prometheus" subPath: prometheus name: data - mountPath: "/etc/prometheus" name: config-volume resources: requests: cpu: 100m memory: 512Mi limits: cpu: 100m memory: 512Mi securityContext: runAsUser: 0 volumes: - name: data persistentVolumeClaim: claimName: prometheus - configMap: name: prometheus-config name: config-volume---
apiVersion: v1
kind: Service
metadata:
namespace: kube-system
name: prometheus
labels:
app: prometheus
spec:
type: NodePort
selector:
app: prometheus
ports:
- name: http
port: 9090EOF
我們在啟動程序的時候,除了指定prometheus.yaml
(configmap)以外,還通過storage.tsdb.path
指定了TSDB數據的存儲路徑、通過storage.tsdb.rentention
設置了保留多長時間的數據,還有下面的web.enable-admin-api參數可以用來開啟對admin api的訪問權限,參數web.enable-lifecyle
用來開啟支持熱更新,有了這個參數之后,prometheus.yaml
(configmap)文件只要更新了,通過執行localhost:9090/-/reload
就會立即生效
我們添加了一行securityContext,,其中runAsUser
設置為0,這是因為prometheus運行過程中使用的用戶是nobody,如果不配置可能會出現權限問題
NFS搭建步驟
for i in k8s-01 k8s-02 k8s-03;do ssh root@$i "yum install nfs-utils rpcbind -y";done 接着我們在任意一台機器上搭建nfs,其他的服務器主要是掛載我這里使用192.168.0.200
NFS服務器操作如下
mkdir -p /home/kvm
systemctl start rpcbind
systemctl enable rpcbind
systemctl enable nfs
echo "/home/kvm *(rw,no_root_squash,sync)" >>/etc/exports其他k8s節點直接啟動rpcbind並且掛載目錄就可以
systemctl start rpcbind
systemctl enable rpcbind
mkdir /data/k8s -p
mount -t nfs 10.4.82.138:/home/kvm /data/k8s
prometheus.yaml文件對應的ConfigMap對象通過volume的形式掛載進Pod,這樣ConfigMap更新后,對應的pod也會熱更新,然后我們在執行上面的reload請求,prometheus配置就生效了。除此之外,對了將時間數據進行持久化,我們將數據目錄和一個pvc對象進行了綁定,所以我們需要提前創建pvc對象
[root@k8s-01 prometheus]# cat >prometheus-volume.yaml <<EOF apiVersion: v1 kind: PersistentVolume metadata: name: prometheus spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: server: 192.168.0.200 path: /home/kvm/k8s-vloume---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: prometheus
namespace: kube-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10GiEOF
nfs
server nfs服務器ip
path 掛載點,提前掛在好,確保可以寫入
這里通過一個簡單的NFS作為存儲后端創建一個pv & pvc
[root@k8s-01 prometheus]# kubectl create -f prometheus-volume.yaml persistentvolume/prometheus created persistentvolumeclaim/prometheus created
我們這里還需要創建rbac認證,因為prometheus需要訪問k8s集群內部的資源
cat >>prometheus-rbac.yaml <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: prometheus namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus rules: - apiGroups: - "" resources: - nodes - services - endpoints - pods - nodes/proxy verbs: - get - list - watch - apiGroups: - "" resources: - configmaps - nodes/metrics verbs: - get - nonResourceURLs: - /metrics verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: prometheus roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus subjects: - kind: ServiceAccount name: prometheus namespace: kube-system EOF
由於我們要獲取的資源,在每一個namespace
下面都有可能存在,所以我們這里使用的是ClusterRole的資源對象,nonResourceURLs是用來對非資源型metrics進行操作的權限聲明
創建rbac文件 [root@k8s-01 prometheus]# kubectl create -f prometheus-rbac.yaml serviceaccount/prometheus created clusterrole.rbac.authorization.k8s.io/prometheus created clusterrolebinding.rbac.authorization.k8s.io/prometheus created
我們將ConfigMap
volume
rbac
創建完畢后,就可以創建prometheus.deploy.yaml了,運行prometheus服務
[root@k8s-01]# kubectl create -f prometheus.deploy.yaml deployment.extensions/prometheus created[root@k8s-01 prometheus]# kubectl get pod -n kube-system |grep prometheus
prometheus-847494df74-zbz9v 1/1 Running 0 148m這里1/1 狀態為Running即可
現在我們prometheus服務狀態是已經正常了,但是我們在瀏覽器是無法訪問prometheus的 webui服務。那么我們還需要創建一個service
cat >>prometeheus-svc.yaml <<EOF apiVersion: v1 kind: Service metadata: namespace: kube-system name: prometheus labels: app: prometheus spec: type: NodePort selector: app: prometheus ports: - name: http port: 9090EOF
[root@k8s-01prometheus]# kubectl create -f prometeheus-svc.yaml service/prometheus created[root@k8s-01 prometheus]# kubectl get svc -n kube-system |grep prometheus
prometheus NodePort 10.1.183.250 <none> 9090:30129/TCP 148m
這里定義的端口為3xxxx,我們直接在瀏覽器上任意節點輸入ip+端口即可
我們可以查看一下當前監控規則
默認prometheus會監控自己
Status-->Targets
我們查看一下數據,是否收集到數據
Prometheus監控Kubernetes 集群節點及應用
對於Kubernetes的集群監控一般我們需要考慮一下幾方面
- Kubernetes節點的監控;比如節點的cpu、load、fdisk、memory等指標
- 內部系統組件的狀態;比如kube-scheduler、kube-controller-manager、kubedns/coredns等組件的運行狀態
- 編排級的metrics;比如Deployment的狀態、資源請求、調度和API延遲等數據指標
監控方案
Kubernetes集群的監控方案主要有以下幾種方案
- Heapster:Herapster是一個集群范圍的監控和數據聚合工具,以Pod的形式運行在集群中
Kubelet/cAdvisor之外,我們還可以向Heapster添加其他指標源數據,比如kube-state-metrics
Heapster已經被廢棄,使用metrics-server代替
- cAvisor:cAdvisor是Google開源的容器資源監控和性能分析工具,它是專門為容器而生,本身也支持Docker容器,Kubernetes中,我們不需要單獨去安裝,cAdvisor作為kubelet內置的一部分程序可以直接使用
- Kube-state-metrics:通過監聽API Server生成有關資源對象的狀態指標,比如Deployment、Node、Pod,需要注意的是kube-state-metrics只是簡單的提供一個metrics數據,並不會存儲這些指標數據,所以我們可以使用Prometheus來抓取這些數據然后存儲
- metrics-server:metrics-server也是一個集群范圍內的資源數據局和工具,是Heapster的代替品,同樣的,metrics-server也只是顯示數據,並不提供數據存儲服務。
不過kube-state-metrics
和metrics-server
之前還有很大不同的,二者主要區別如下
1.kube-state-metrics主要關注的是業務相關的一些元數據,比如Deployment、Pod、副本狀態等 2.metrics-service主要關注的是資源度量API的實現,比如CPU、文件描述符、內存、請求延時等指標
監控集群節點
首先需要我們監控集群的節點,要監控節點其實我們已經有很多非常成熟的方案了,比如Nagios、Zabbix,甚至可以我們自己收集數據,這里我們通過prometheus來采集節點的監控指標,可以通過node_exporter獲取,node_exporter就是抓取用於采集服務器節點的各種運行指標,目前node_exporter幾乎支持所有常見的監控點,比如cpu、distats、loadavg、meminfo、netstat等,詳細的監控列表可以參考github repo
這里使用DeamonSet
控制器來部署該服務,這樣每一個節點都會運行一個Pod,如果我們從集群中刪除或添加節點后,也會進行自動擴展
[root@k8s-01 prometheus]# cat >>prometheus-node-exporter.yaml<<EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: node-exporter namespace: kube-system labels: name: node-exporter k8s-app: node-exporter spec: selector: matchLabels: name: node-exporter template: metadata: labels: name: node-exporter app: node-exporter spec: hostPID: true hostIPC: true hostNetwork: true containers: - name: node-exporter image: prom/node-exporter:v0.16.0 ports: - containerPort: 9100 resources: requests: cpu: 0.15 securityContext: privileged: true args: - --path.procfs - /host/proc - --path.sysfs - /host/sys - --collector.filesystem.ignored-mount-points - '"^/(sys|proc|dev|host|etc)($|/)"' volumeMounts: - name: dev mountPath: /host/dev - name: proc mountPath: /host/proc - name: sys mountPath: /host/sys - name: rootfs mountPath: /rootfs tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" volumes: - name: proc hostPath: path: /proc - name: dev hostPath: path: /dev - name: sys hostPath: path: /sys - name: rootfs hostPath: path: /EOF
創建node-exporter並檢查pod
[root@k8s-01prometheus]# kubectl create -f prometheus-node-exporter.yaml daemonset.extensions/node-exporter created[root@k8s-01 prometheus]# kubectl get pod -n kube-system -o wide|grep node
node-exporter-bsdkl 1/1 Running 0 36m 192.168.122.217 k8s-02 <none> <none>
node-exporter-f8wrt 1/1 Running 0 36m 192.168.122.2 k8s-01 <none> <none>
node-exporter-gjhvz 1/1 Running 0 36m 192.168.122.165 k8s-03 <none> <none>這里我們可以看到,我們有3個節點,在所有的節點上都啟動了一個對應Pod進行獲取數據
node-exporter.yaml文件說明
由於我們要獲取的數據是主機的監控指標數據,而我們的node-exporter是運行在容器中的,所以我們在Pod中需要配置一些Pod的安全策略
hostPID:true hostIPC:true hostNetwork:true這三個配置主要用於主機的PID namespace、IPC namespace以及主機網絡,這里需要注意的是namespace是用於容器隔離的關鍵技術,這里的namespace和集群中的namespace是兩個完全不同的概念
另外我們還需要將主機/dev
、/proc
、/sys
這些目錄掛在到容器中,這些因為我們采集的很多節點數據都是通過這些文件來獲取系統信息
比如我們在執行top命令可以查看當前cpu使用情況,數據就來源於/proc/stat,使用free命令可以查看當前內存使用情況,其數據來源是/proc/meminfo文件
另外如果是使用kubeadm
搭建的,同時需要監控master節點的,則需要添加下方的相應容忍
- key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule
node-exporter容器相關啟動參數
args: - --path.procfs #配置掛載宿主機(node節點)的路徑 - /host/proc - --path.sysfs #配置掛載宿主機(node節點)的路徑 - /host/sys - --collector.filesystem.ignored-mount-points - '"^/(sys|proc|dev|host|etc)($|/)"'
在我們的yaml文件中加入了hostNetwork:true
會直接將我們的宿主機的9100端口映射出來,從而不需要創建service 在我們的宿主機上就會有一個9100的端口
容器的9100--->映射到宿主機9100
hostNetwork: true containers: - name: node-exporter image: prom/node-exporter:v0.16.0 ports: - containerPort: 9100
上面我們檢查了Pod的運行狀態都是正常的,接下來我們要查看一下Pod日志,以及node-exporter中的metrics
使用命令kubectl logs -n 命名空間 node-exporter中Pod名稱
檢查Pod日志是否有額外報錯
[root@k8s-01 prometheus]# kubectl logs -n kube-system node-exporter- node-exporter-bsdkl node-exporter-f8wrt node-exporter-gjhvz [root@k8s-01 prometheus]# kubectl logs -n kube-system node-exporter-bsdkl time="2019-12-05T05:50:42Z" level=info msg="Starting node_exporter (version=0.16.0, branch=HEAD, revision=d42bd70f4363dced6b77d8fc311ea57b63387e4f)" source="node_exporter.go:82" time="2019-12-05T05:50:42Z" level=info msg="Build context (go=go1.9.6, user=root@a67a9bc13a69, date=20180515-15:52:42)" source="node_exporter.go:83" time="2019-12-05T05:50:42Z" level=info msg="Enabled collectors:" source="node_exporter.go:90" time="2019-12-05T05:50:42Z" level=info msg=" - arp" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - bcache" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - bonding" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - conntrack" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - cpu" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - diskstats" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - edac" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - entropy" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - filefd" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - filesystem" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - hwmon" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - infiniband" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - ipvs" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - loadavg" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - mdadm" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - meminfo" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - netdev" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - netstat" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - nfs" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - nfsd" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - sockstat" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - stat" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - textfile" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - time" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - timex" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - uname" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - vmstat" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - wifi" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - xfs" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg=" - zfs" source="node_exporter.go:97" time="2019-12-05T05:50:42Z" level=info msg="Listening on :9100" source="node_exporter.go:111"
#接下來,我們在任意集群節點curl 9100/metrics
[root@k8s-01 prometheus]# curl 127.0.0.1:9100/metrics|head % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0# HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 0.000239179 go_gc_duration_seconds{quantile="0.25"} 0.000322674 go_gc_duration_seconds{quantile="0.5"} 0.000361148 go_gc_duration_seconds{quantile="0.75"} 0.000416324 go_gc_duration_seconds{quantile="1"} 0.000513074 go_gc_duration_seconds_sum 0.006654219 go_gc_duration_seconds_count 18 # HELP go_goroutines Number of goroutines that currently exist. 100 64669 100 64669 0 0 2235k 0 --:--:-- --:--:-- --:--:-- 2339k curl: (23) Failed writing body (135 != 15652)
只要metrics可以獲取到數據說明node-exporter沒有問題
服務發現
我們這里三個節點都運行了node-exporter
程序,如果我們通過一個Server來將數據收集在一起,用靜態的方式配置到prometheus就會顯示一條數據,我們得自己在指標中過濾每個節點的數據,配置比較麻煩。 這里就采用服務發現
在Kubernetes下,Prometheus通過Kubernetes API基礎,目前主要支持5種服務發現,分別是node
、Server
、Pod
、Endpoints
、Ingress
需要我們在Prometheus配置文件中,添加如下三行
- job_name: 'kubernetes-node' kubernetes_sd_configs: - role: node通過制定Kubernetes_sd_config的模式為node,prometheus就會自動從Kubernetes中發現所有的node節點並作為當前job監控的目標實例,發現的節點/metrics接口是默認的kubelet的HTTP接口
接下來我們更新配置文件
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# [root@k8s-01 prometheus]# [root@k8s-01 prometheus]# kubectl get svc -n kube-system |grep prometheus prometheus NodePort 10.1.183.250 <none> 9090:30129/TCP 169m [root@k8s-01 prometheus]# [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload #熱更新刷新配置(需要等待一小會)
接着訪問我們的地址
這個端口要和service對上
現在我們可以看到已經獲取到我們的Node節點的IP,但是由於metrics監聽的端口是10250而並不是我們設置的9100,所以提示我們節點屬於Down的狀態
這里我們就需要使用Prometheus提供的relabel_configs
中的replace
能力了,relabel可以在Prometheus采集數據之前,通過Target實例的Metadata信息,動態重新寫入Label的值。除此之外,我們還能根據Target實例的Metadata信息選擇是否采集或者忽略該Target實例。這里使用__address__
標簽替換10250端口為9100
這里使用正則進行替換端口
- job_name: 'kubernetes-node' kubernetes_sd_configs: - role: node relabel_configs: - source_labels: [__address__] regex: '(.*):10250' replacement: '${1}:9100' target_label: __address__ action: replace
接下來我們更新一下配置
curl的時候可以多更新幾次,順便等待一會
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]#
現在在狀態就正常了
目前狀態已經正常,但是還有一個問題就是我們的采集數據只顯示了IP地址,對於我們監控分組分類不是很方便,這里可以通過labelmap
這個屬性來將Kubernetes的Label標簽添加為Prometheus的指標標簽
- job_name: 'kubernetes-node' kubernetes_sd_configs: - role: node relabel_configs: - source_labels: [__address__] regex: '(.*):10250' replacement: '${1}:9100' target_label: __address__ action: replace - action: labelmap regex: __meta_kubernetes_node_label_(.+)
添加了一個action為labelmap
,正則表達式是__meta_kubernetes_node(.+)
的配置,這里的意思就是表達式中匹配的數據也添加到指標數據的Label標簽中去。
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload
實際上就是獲取我們的標簽
[root@k8s-01 ~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS k8s-01 Ready master 30d v1.16.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-01,kubernetes.io/os=linux,node-role.kubernetes.io/master= k8s-02 Ready <none> 30d v1.16.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-02,kubernetes.io/os=linux k8s-03 Ready <none> 30d v1.16.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-03,kubernetes.io/os=linux [root@k8s-01 ~]#
對於Kubernetes_sd_configs下面可用的元標簽如下
- __meta_kubernetes_node_name: 節點對象的名稱
- _meta_kubernetes_node_label: 節點對象中的每個標簽
- _meta_kubernetes_node_annotation: 來自節點對象的每個注釋
_meta_kubernetes_node_address: 每個節點地址類型的第一個地址(如果存在) 關於kubernetes_sd_configs更多信息可以查看官方文檔: kubernetes_sd_config
#prometheus configmap 監控完整配置如下,可以直接拷貝 root@k8s-01 prometheus]# cat prometheus.configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: kube-system data: prometheus.yml: | global: scrape_interval: 15s scrape_timeout: 15s scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090']</span>- job_name: <span style="color: #800000;">'</span><span style="color: #800000;">kubernetes-node</span><span style="color: #800000;">'</span><span style="color: #000000;"> kubernetes_sd_configs: </span>-<span style="color: #000000;"> role: node relabel_configs: </span>-<span style="color: #000000;"> source_labels: [__address__] regex: </span><span style="color: #800000;">'</span><span style="color: #800000;">(.*):10250</span><span style="color: #800000;">'</span><span style="color: #000000;"> replacement: </span><span style="color: #800000;">'</span><span style="color: #800000;">${1}:9100</span><span style="color: #800000;">'</span><span style="color: #000000;"> target_label: __address__ action: replace </span>-<span style="color: #000000;"> action: labelmap regex: __meta_kubernetes_node_label_(.</span>+<span style="color: #000000;">) </span>- job_name: <span style="color: #800000;">'</span><span style="color: #800000;">kubernetes-cadvisor</span><span style="color: #800000;">'</span><span style="color: #000000;"> kubernetes_sd_configs: </span>-<span style="color: #000000;"> role: node scheme: https tls_config: ca_file: </span>/var/run/secrets/kubernetes.io/serviceaccount/<span style="color: #000000;">ca.crt bearer_token_file: </span>/var/run/secrets/kubernetes.io/serviceaccount/<span style="color: #000000;">token relabel_configs: </span>-<span style="color: #000000;"> action: labelmap regex: __meta_kubernetes_node_label_(.</span>+<span style="color: #000000;">) </span>-<span style="color: #000000;"> target_label: __address__ replacement: kubernetes.default.svc:</span><span style="color: #800080;">443</span> -<span style="color: #000000;"> source_labels: [__meta_kubernetes_node_name] regex: (.</span>+<span style="color: #000000;">) target_label: __metrics_path__ replacement: </span>/api/v1/nodes/${<span style="color: #800080;">1</span>}/proxy/metrics/cadvisor </pre>
我們還可以去Graph
里面看一下數據
我們這里也可以自定義規則
容器監控
cAdvisor是一個容器資源監控工具,包括容器的內存,CPU,網絡IO,資源IO等資源,同時提供了一個Web頁面用於查看容器的實時運行狀態。
cAvisor已經內置在了kubelet組件之中,所以我們不需要單獨去安裝,cAdvisor的數據路徑為/api/v1/nodes//proxy/metrics
action 使用labelkeep或者labeldrop則可以對Target標簽進行過濾,僅保留符合過濾條件的標簽
- job_name: 'kubernetes-cadvisor' kubernetes_sd_configs: - role: node scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - action: labelmap regex: __meta_kubernetes_node_label_(.+) - target_label: __address__ replacement: kubernetes.default.svc:443 - source_labels: [__meta_kubernetes_node_name] regex: (.+) target_label: __metrics_path__ replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
ls_config配置的證書地址是每個Pod連接apiserver所使用的地址,基本上寫死了。並且我們在配置文件添加了一個labelmap標簽。在最下面使用了一個正則替換了cAdvisor的一個metrics地址
證書是我們Pod啟動的時候kubelet給pod注入的一個證書,所有的pod啟動的時候都會有一個ca證書注入進來
如要想要訪問apiserver的信息,還需要配置一個token_file
修改完成之后,我們需要configmap
並且使用curl進行熱更新(過程比較慢,需要等待會)
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload
現在我們可以到Graph
路徑下面查詢容器的相關數據
這里演示查詢集群中所有Pod的CPU使用情況,查詢指標
container_cpu_usage_seconds_total
並且查詢1分鍾之內的數據
這里演示一下使用函數rate
和不使用函數的一個過濾功能
container_cpu_usage_seconds_total{image!=" ",pod_name!=" "} rate(container_cpu_usage_seconds_total{image!=" ",pod_name!=" "}[1m])
執行下方命令,過濾1分鍾內的數據
rate(container_cpu_usage_seconds_total{image!=" ",pod_name!=" "}[1m])
還可以使用sum
函數,pod在1分鍾內的使用率,同時將pod名稱打印出來
sum by (pod)(rate(container_cpu_usage_seconds_total{image!=" ", pod_name!=" "}[1m] ))
Api-Service 監控
apiserver作為Kubernetes最核心的組件,它的監控也是非常有必要的,對於apiserver的監控,我們可以直接通過kubernetes的service來獲取
[root@k8s-01 prometheus]# kubectl get svc --all-namespaces NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 31d ingress-nginx ingress-nginx ClusterIP 10.1.216.99 <none> 80/TCP,443/TCP 24h kube-system kube-dns ClusterIP 10.1.0.10 <none> 53/UDP,53/TCP,9153/TCP 30d kube-system kubelet ClusterIP None <none> 10250/TCP 25h kube-system prometheus NodePort 10.1.183.250 <none> 9090:30129/TCP 4h38m kubernetes-dashboard dashboard-metrics-scraper ClusterIP 10.1.100.76 <none> 8000/TCP 30d kubernetes-dashboard kubernetes-dashboard NodePort 10.1.158.92 <none> 443:30001/TCP 30d
上面的service是我們集群的apiserver內部的service的地址,要自動發現service類型的服務,需要使用role
為Endpoints
的kubernetes_sd_configs (自動發現)
,我們只需要在configmap里面在添加Endpoints類型的服務發現
- job_name: 'kubernetes-apiserver' kubernetes_sd_configs: - role: endpoints
刷新配置文件
[root@k8s-01 prometheus]# kubectl get svc -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.1.0.10 <none> 53/UDP,53/TCP,9153/TCP 30d kubelet ClusterIP None <none> 10250/TCP 25h prometheus NodePort 10.1.183.250 <none> 9090:30129/TCP 4h43m [root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]#
更新完成后,我們可以看到kubernetes-apiserver下面出現了很多實例,這是因為我們這里使用的Endpoints類型的服務發現,所以prometheus把所有的Endpoints服務都抓取過來了,同樣的我們要監控的kubernetes也在列表中。
這里我們使用keep
動作,將符合配置的保留下來,例如我們過濾default命名空間下服務名稱為kubernetes
的元數據,這里可以根據__meta_kubernetes_namespace
和__mate_kubertnetes_service_name
2個元數據進行relabel
- job_name: kubernetes-apiservers kubernetes_sd_configs: - role: endpoints relabel_configs: - action: keep regex: default;kubernetes;https source_labels: - __meta_kubernetes_namespace - __meta_kubernetes_service_name - __meta_kubernetes_endpoint_port_name scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt insecure_skip_verify: true bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
#參數解釋
action: keep #保留哪些標簽
regex: default;kubernetes;https #匹配namespace下的default命名空間下的kubernetes service 最后https協議
可以通過`kubectl describe svc kubernetes`查看到
刷新配置
#這個過程比較慢,可能要等幾分鍾,可以多reload幾次
[root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]#
接下來我們還是前往Greph
上查看采集到的數據
sum(rate(apiserver_request_count[1m]))這里使用的promql里面的rate和sun函數,意思是apiserver在1分鍾內請求的數
如果我們要監控其他系統組件,比如kube-controller-manager、kube-scheduler的話就需要單獨手動創建service,因為apiserver服務默認在default,而其他組件在kube-steam這個namespace下。其中kube-sheduler的指標數據端口為10251
,kube-controller-manager對應端口為10252
Service 監控
apiserver實際上是一種特殊的Service,現在配置一個專門發現普通類型的Service
這里我們對service進行過濾,只有在service配置了prometheus.io/scrape: "true"
過濾出來
- job_name: 'kubernetes-service-endpoints' kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] action: replace target_label: __scheme__ regex: (https?) - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] action: replace target_label: __address__ regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace target_label: kubernetes_name
繼續重復步驟,刷新配置
[root@k8s-01 prometheus]# [root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]#
Serivce自動發現參數說明 (並不是所有創建的service都可以被prometheus發現)
#1.參數解釋 relabel_configs: -source_labels:[__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true 保留標簽 source_labels: [__meta_kubernetes_service_annotation_prometheus_io_cheme]這行配置代表我們只去篩選有__meta_kubernetes_service_annotation_prometheus_io_scrape的service,只有添加了這個聲明才可以自動發現其他service
2.參數解釋
- source_labels: [address, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: address
regex: ([^:]+)(?::\d+)?😭\d+)
replacement: $1😒2指定一個抓取的端口,有的service可能有多個端口(比如之前的redis)。默認使用的是我們添加是使用kubernetes_service端口
3.參數解釋
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: scheme
regex: (https?)這里如果是https證書類型,我們還需要在添加證書和token
我們可以看到這里的服務的core DNS
,為什么那么多service只有coreDNS可以被收集到呢?
上面也說了,我們有過濾條件,只有復合條件的才進行過濾
core DNS serviceYaml 文件包含
true
參數,所以會被匹配到
繼續重復步驟,刷新配置
[root@k8s-01 prometheus]# [root@k8s-01 prometheus]# kubectl apply -f prometheus.configmap.yaml configmap/prometheus-config configured [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]# curl -X POST http://10.1.183.250:9090/-/reload [root@k8s-01 prometheus]#
當我們再次查看,發現狀態完成
Grafana 安裝並監控k8s集群
由於Prometheus自帶的web Ui圖標功能相對較弱,所以一般情況下我們會使用一個第三方的工具來展示這些數據
Grafana介紹
grafana 是一個可視化面包,有着非常漂亮的圖片和布局展示,功能齊全的度量儀表盤和圖形化編輯器,支持Graphite、Zabbix、InfluxDB、Prometheus、OpenTSDB、Elasticasearch等作為數據源,比Prometheus自帶的圖標展示功能強大很多,更加靈活,有豐富的插件
我們這里使用deployment持久化安裝grafana
cat >>grafana_deployment.yaml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: grafana namespace: kube-system labels: app: grafana k8s-app: grafana spec: selector: matchLabels: k8s-app: grafana app: grafana revisionHistoryLimit: 10 template: metadata: labels: app: grafana k8s-app: grafana spec: containers: - name: grafana image: grafana/grafana:5.3.4 imagePullPolicy: IfNotPresent ports: - containerPort: 3000 name: grafana env: - name: GF_SECURITY_ADMIN_USER value: admin - name: GF_SECURITY_ADMIN_PASSWORD value: jiangwenhui readinessProbe: failureThreshold: 10 httpGet: path: /api/health port: 3000 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 30 livenessProbe: failureThreshold: 3 httpGet: path: /api/health port: 3000 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: limits: cpu: 300m memory: 1024Mi requests: cpu: 300m memory: 1024Mi volumeMounts: - mountPath: /var/lib/grafana subPath: grafana name: storage securityContext: fsGroup: 472 runAsUser: 472 volumes: - name: storage persistentVolumeClaim: claimName: grafana EOF
這里使用了grafana 5.3.4
的鏡像,添加了監控檢查、資源聲明,比較重要的變量是GF_SECURITY_ADMIN_USER
和GF_SECURITY_ADMIN_PASSWORD
為grafana的賬號和密碼。
由於grafana將dashboard、插件這些數據保留在/var/lib/grafana
目錄下,所以我們這里需要做持久化,同時要針對這個目錄做掛載聲明,由於5.3.4版本用戶的userid和groupid都有所變化,所以這里添加了一個securityContext
設置用戶ID
現在我們添加一個pv和pvc用於綁定grafana
cat >>grafana_volume.yaml <<EOF apiVersion: v1 kind: PersistentVolume metadata: name: grafana spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: server: 192.168.0.200 path: /home/kvm/k8s-vloume --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: grafana namespace: kube-system spec: accessModes: - ReadWriteOnce resources: requests: storage: 10GiEOF
這里配置依舊使用NFS進行掛載使用
現在我們還需要創建一個service,使用NodePort
cat >>grafana_svc.yaml<<EOF apiVersion: v1 kind: Service metadata: name: grafana namespace: kube-system labels: app: grafana spec: type: NodePort ports: - port: 3000 selector: app: grafana EOF
由於5.1(可以選擇5.1之前的docker鏡像,可以避免此類錯誤)版本后groupid更改,同時我們將/var/lib/grafana
掛載到pvc后,目錄擁有者可能不是grafana用戶,所以我們還需要添加一個Job用於授權目錄
cat > grafana_job.yaml <<EOF apiVersion: batch/v1 kind: Job metadata: name: grafana-chown namespace: kube-system spec: template: spec: restartPolicy: Never containers: - name: grafana-chown command: ["chown", "-R", "472:472", "/var/lib/grafana"] image: busybox imagePullPolicy: IfNotPresent volumeMounts: - name: storage subPath: grafana mountPath: /var/lib/grafana volumes: - name: storage persistentVolumeClaim: claimName: grafana EOF
這里使用一個busybox鏡像將/var/lib/grafana
目錄修改為權限472
#需要先創建pv和pvc (這里是需要安裝順序來創建) [root@k8s-01 prometheus]# kubectl create -f grafana_volume.yaml persistentvolume/grafana created persistentvolumeclaim/grafana created [root@k8s-01 prometheus]# kubectl create -f grafana_job.yaml job.batch/grafana-chown created [root@k8s-01 prometheus]# kubectl apply -f grafana_deployment.yaml deployment.apps/grafana created [root@k8s-01 prometheus]# kubectl create -f grafana_svc.yaml
創建完成后我們打開grafana的dashboard界面
[root@k8s-01 prometheus]# [root@k8s-01 prometheus]# kubectl get pod,svc -n kube-system |grep grafana pod/grafana-59bd6c446d-4jjnf 1/1 Running 0 7m39s pod/grafana-chown-w562v 0/1 Completed 0 14m service/grafana NodePort 10.1.63.182 <none> 3000:30636/TCP 13m [root@k8s-01 prometheus]#
然后我們在任意集群中的節點訪問端口為30636
這里的集群密碼就是上面我們創建deployment里面設置的變量,我這里用戶設置為admin密碼jiangwenhui
登陸到grafana就顯示到了我們的引導界面
登陸到grafana就顯示到了我們的引導界面
第一次創建grafana需要添加數據源
類型選擇prometheus
這里的地址我們填寫下面的url
這里的prometheus代表service名稱
kube-system代表命名空間
數據源添加完畢后,接下來添加New dashboard
這里我們可以自定義模板,或者可以使用別人寫好的模板 (寫好的模板后面是需要我們自己修改的)
grafana提供了很多模板,類似和docker鏡像倉庫一下。導入模板也極其簡單。點擊上方的Dashboard
這里面的模板都是公共的,可以免費使用
點進去任意一個模板后,我們可以看到ID,復制ID然后在返回grafana
我這里添加一個監控Kubernetes集群。顯示整體群集CPU、內存、磁盤使用情況以及單個pod統計信息。
點擊導入模板
在這里我們輸入8588或者url,會自動跳轉到配置頁面
https://grafana.com/grafana/dashboards/8588
選擇好數據源之后,我們在點擊Import
即可
這里就會將模板8588
給我們導入進行
這里就會獲取我們prometheus里面的數據了
現在的模板還沒有進行保存,我們要點擊保存一下
現在就保存下來了
目前我們導入模板之后是無法直接使用滴
這里無法顯示是由於模板定義的標簽,我們prometheus並沒有這個數據元,所以說我們要對模板進行修改!
在修改之前我們先設置一下時區,grafana默認走的是瀏覽器時區,但是prometheus使用的是
UTC
時區
修改默認模板 (我這里使用的是8588模板,下面模板修改請根據我的操作步驟進行操作)
grafana模板修改
前面的步驟必須和我相同,否則這里可能會無法出現值
首先我們進行編輯 Cluster memory usage (集群內存使用率)
計算方式就是(整個集群的內存-(整個集群剩余的內存以及Buffer和Cached))/整
(sum(node_memory_MemTotal_bytes) - sum(node_memory_MemFree_bytes + node_memory_Buffers_bytes+node_memory_Cached_bytes)) / sum(node_memory_MemTotal_bytes) * 100
這里要說明一點,這里填寫的是PromSQL,也就是說是可以在prometheus查詢到的。 如果查詢不到grafana也是會獲取不到數據的
這里在prometheus是可以獲取到的
Cluster memory usage 配置如下 (集群內存使用率)
sum(sum by (container_name)( rate(container_cpu_usage_seconds_total{image!=""}[1m] ) )) / count(node_cpu_seconds_total{mode="system"}) * 100
Cluster filesystem usage 集群文件系統使用率
(sum(node_filesystem_size_bytes{device="tmpfs"}) - sum(node_filesystem_free_bytes{device="tmpfs"}) ) / sum(node_filesystem_size_bytes{device="tmpfs"}) * 100
這里我們就獲取到數據了
接下來我們配置集群中Pod cpu使用率
sum by (pod)(rate(container_cpu_usage_seconds_total{image!=" ", pod_name!=" "}[1m]))
下面顯示的地方配置
{{ pod }}
集群pod 內存使用率
sort_desc(sum (container_memory_usage_bytes{image!=" ", pod_name!=" "}) by(pod))
下面顯示的名稱同樣也是{{ pod }}
最后我們配置一下Pod 網絡監控
1.入口流量 sort_desc(sum by (pod) (rate (container_network_receive_bytes_total{name!=""}[1m]) ))2.出口流量
sort_desc(sum by (pod) (rate (container_network_transmit_bytes_total{name!=""}[1m]) ))監控時間為1分鍾
效果圖如下 記得點擊保存
所有的PromSQL都是可以在prometheus獲取到數據的!