如何在 k8s 上 部署 prometheus + grafana ...
依照慣例,來刷一下存在感 XD
今天來介紹如何在 k8s 上 部署 prometheus + grafana ...
1. 先拉取 prometheus 、 grafana 、 node-exporter 的 docker image
2. 匯出 prometheus 、 grafana 、 node-exporter 的 docker image
3. 利用 scp 把資料丟到遠端伺服器上
4. 因為這個 node-exporter image tag 版本我 tag 為 latest ,所以在匯入 kind local registry 之前必須要改 tag ,把 latest 改成 v1.3.1
因為
kind 的 local registry 不吃 latest !!!
kind 的 local registry 不吃 latest !!!
kind 的 local registry 不吃 latest !!!
指令如下:
auxo@auxo-virtual-machine:~/tmp/docker-imgs$ docker tag prom/node-exporter:latest prom/node-exporter:v1.3.1
4.1. 把 prometheus 、 grafana 、 node-exporter 的 docker image load 到 k8s (kind) 的 local registry
auxo@auxo-virtual-machine:~/tmp/docker-imgs$ kind load docker-image grafana/grafana:8.5.5 --name test-cluster
Image: "grafana/grafana:8.5.5" with ID "sha256:a04af134d9fccb02a8fd584c38b1fc3c38393b851f05ce5740758c468e3a38c1" not yet present on node "test-cluster-worker2", loading...
Image: "grafana/grafana:8.5.5" with ID "sha256:a04af134d9fccb02a8fd584c38b1fc3c38393b851f05ce5740758c468e3a38c1" not yet present on node "test-cluster-worker", loading...
Image: "grafana/grafana:8.5.5" with ID "sha256:a04af134d9fccb02a8fd584c38b1fc3c38393b851f05ce5740758c468e3a38c1" not yet present on node "test-cluster-control-plane", loading...
Image: "grafana/grafana:8.5.5" with ID "sha256:a04af134d9fccb02a8fd584c38b1fc3c38393b851f05ce5740758c468e3a38c1" not yet present on node "test-cluster-worker3", loading...
auxo@auxo-virtual-machine:~/tmp/docker-imgs$ kind load docker-image prom/node-exporter:v1.3.1 --name test-cluster
Image: "prom/node-exporter:v1.3.1" with ID "sha256:1dbe0e931976487e20e5cfb272087e08a9779c88fd5e9617ed7042dd9751ec26" not yet present on node "test-cluster-worker2", loading...
Image: "prom/node-exporter:v1.3.1" with ID "sha256:1dbe0e931976487e20e5cfb272087e08a9779c88fd5e9617ed7042dd9751ec26" not yet present on node "test-cluster-worker", loading...
Image: "prom/node-exporter:v1.3.1" with ID "sha256:1dbe0e931976487e20e5cfb272087e08a9779c88fd5e9617ed7042dd9751ec26" not yet present on node "test-cluster-control-plane", loading...
Image: "prom/node-exporter:v1.3.1" with ID "sha256:1dbe0e931976487e20e5cfb272087e08a9779c88fd5e9617ed7042dd9751ec26" not yet present on node "test-cluster-worker3", loading...
...
5. 在 k8s 中利用建立 DaemonSet 的方式安裝 node-exporter
首先來看一下 DaemonSet 的 yaml 寫法:
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
name: node-exporter
namespace: kube-ops
spec:
selector:
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
template:
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
spec:
containers:
- args:
- --path.sysfs=/host/sys
- --path.rootfs=/host/root
- --no-collector.wifi
- --no-collector.hwmon
- --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/)
- --collector.netclass.ignored-devices=^(veth.*)$
name: node-exporter
image: prom/node-exporter:v1.3.1
ports:
- containerPort: 9100
protocol: TCP
resources:
limits:
cpu: 250m
memory: 180Mi
requests:
cpu: 102m
memory: 180Mi
volumeMounts:
- mountPath: /host/sys
mountPropagation: HostToContainer
name: sys
readOnly: true
- mountPath: /host/root
mountPropagation: HostToContainer
name: root
readOnly: true
volumes:
- hostPath:
path: /sys
name: sys
- hostPath:
path: /
name: root
5.1 建立一個給 node-exporter 使用的 service
kind: Service
apiVersion: v1
metadata:
name: node-exporter-svc
namespace: kube-ops
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '9100'
spec:
selector:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
ports:
- name: node-exporter
protocol: TCP
port: 9100
targetPort: 9100
注意這個
spec:
selector:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
這個跟 node-exporter 的 DaemonSet 裡面的
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: node-exporter
是一致的。
所以它會為每個被 select 到的 pod 套用 service
如果你 describe 這個 svc 來看,就會看到有三個 endpoints
Endpoints: 10.244.1.13:9100,10.244.2.17:9100,10.244.3.12:9100
( DaemonSet 會為每個 node 建立一個 node-exporter 的 pod 。)
5.2 安裝 kube-state-metrics
5.2.1. 因為會用到 registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0 ,先 docker pull 回來。
docker pull registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0
5.2.2. load 到 kind 中。
auxo@auxo-virtual-machine:~/tmp/docker-imgs$ kind load docker-image registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0 --name test-cluster
Image: "registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0" with ID "sha256:b781b8478c274a77dde24bf15b78795d1d564a08a1bdea43b6f38e1f366e15dd" not yet present on node "test-cluster-worker2", loading...
Image: "registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0" with ID "sha256:b781b8478c274a77dde24bf15b78795d1d564a08a1bdea43b6f38e1f366e15dd" not yet present on node "test-cluster-worker", loading...
Image: "registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0" with ID "sha256:b781b8478c274a77dde24bf15b78795d1d564a08a1bdea43b6f38e1f366e15dd" not yet present on node "test-cluster-control-plane", loading...
Image: "registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0" with ID "sha256:b781b8478c274a77dde24bf15b78795d1d564a08a1bdea43b6f38e1f366e15dd" not yet present on node "test-cluster-worker3", loading...
5.2.3. 先前往 https://github.com/kubernetes/kube-state-metrics
5.2.4. 先 clone 這個專案回來。
git clone https://github.com/kubernetes/kube-state-metrics.git
5.2.5. 找到 kube-state-metrics/examples/standard/ , apply 這目錄中的所有 yamls
auxo@auxo-virtual-machine:~/tmp/kind/yaml/misc/kube-state-metrics-example$ kubectl apply -f ./standard/
clusterrolebinding.rbac.authorization.k8s.io/kube-state-metrics created
clusterrole.rbac.authorization.k8s.io/kube-state-metrics created
deployment.apps/kube-state-metrics created
serviceaccount/kube-state-metrics created
service/kube-state-metrics created
這個動作做完以後,會把 kube-state-metrics 裝在 ns/kube-system 下面。
6. 在 k8s 中安裝 prometheus
6.1. 首先建立一個 ConfigMap 設定檔。這個設定檔會變成 volume mount 在 pod 上,告訴 prometheus 去哪裡撈 metrics 的資料。也就是說 prometheus 要做的工作都設定在這裡。所以如果要在 prometheus 上新增工作或是刪除工作都要在這裡做設定。
6.2. 透過 RBAC 建立 prometheus 的使用者跟相關的角色權限配置。
6.2.1. 建立 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: kube-ops
6.2.2. 建立一個 ClusterRole ,這個 Role 裡面會配置 ServiceAccount 的權限。配置錯誤的話有些 metrics 就可能會讀不到。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
- nonResourceURLs:
- /metrics
verbs:
- get
- apiGroups:
- ""
resources:
- secrets
- resourcequotas
- replicationcontrollers
- limitranges
- persistentvolumeclaims
- persistentvolumes
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
- pods
- services
- endpoints
- nodes/proxy
- configmaps
verbs:
- get
- 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
- subjectaccessreviews
verbs:
- create
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- list
- watch
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- list
- watch
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
- volumeattachments
verbs:
- list
- watch
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- networkpolicies
- ingresses
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
如果重複對同一個 apiGroups 底下的資源定義了不同的 Verb ,會自動運算做 Verbs 的"聯集"。
如果我要更新這個 ClusterRole ( 或是 Role ) 的權限配置,可以在運行的 k8s 上直接 kubectl apply 就可以更新權限。
6.2.3. 建立 ClusterRoleBinding ,把這個 ServiceAccount 跟 ClusterRole 綁在一起。
6.3. 為 prometheus 配置 deployment 。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: prometheus
name: prometheus
namespace: kube-ops
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
serviceAccountName: prometheus
containers:
- image: prom/prometheus:v2.36.0
name: prometheus
command:
- "/bin/prometheus"
# 注意這裡的 prometheus.yml 會透過 ConfigMap mount 到 /etc/prometheus 下面。
args:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=7d"
- "--web.enable-lifecycle"
ports:
- containerPort: 9090
protocol: TCP
name: http
volumeMounts:
- mountPath: "/prometheus"
# subPath: prometheus
name: prometheus-2-36-pvc
- mountPath: "/etc/prometheus"
name: config-volume
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
cpu: 100m
memory: 512Mi
securityContext:
runAsUser: 0
# 做好準備給容器 mount 使用
volumes:
- name: prometheus-2-36-pvc
persistentVolumeClaim:
claimName: prometheus-pvc
- configMap:
name: prometheus-config
name: config-volume
7. 在 k8s 上安裝 grafana
7.1. 去 grafana 網站上下載 yaml 配置檔範例
https://grafana.com/docs/grafana/latest/installation/kubernetes/
7.2 修改 image 的版本和 namespace。
看你剛剛塞進 kind 的 image 是哪個版本,就改成那個版本 (這裡以 8.5.5 為範例)。
看想裝在哪個 namespace 記得也要改 namespace ( 這裡以 kube-ops 為範例 )。
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: grafana-pvc
# 我改了這裡。
namespace: kube-ops
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: grafana
name: grafana
# 我改了這裡。
namespace: kube-ops
spec:
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
securityContext:
fsGroup: 472
supplementalGroups:
- 0
containers:
- name: grafana
# 我改了這裡。
image: grafana/grafana:8.5.5
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
# 因為這裡有定義 port 3000 為 http-grafana 所以下面的 svc 才能直接用
name: http-grafana
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /robots.txt
port: 3000
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 2
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 3000
timeoutSeconds: 1
resources:
limits:
memory: 750Mi
cpu: 250m
requests:
cpu: 250m
memory: 750Mi
volumeMounts:
- mountPath: /var/lib/grafana
name: grafana-pv
volumes:
- name: grafana-pv
persistentVolumeClaim:
claimName: grafana-pvc
---
apiVersion: v1
kind: Service
metadata:
name: grafana
# 我改了這裡。
namespace: kube-ops
spec:
ports:
- port: 3000
protocol: TCP
# 見上面 port 的相關定義。
targetPort: http-grafana
selector:
app: grafana
sessionAffinity: None
type: LoadBalancer
8. 設定使用 grafana
8.1. 打開 grafana 的 GUI 。
如果是 kind 那種 lightweight k8s 要做 port-forward 才能存取。
auxo@auxo-virtual-machine:~/tmp/kind/yaml$ kubectl port-forward svc/grafana --address=0.0.0.0 33000:3000 -n kube-ops 1>/dev/null 2>/dev/null&
8.2. 登入 grafana ,帳密預設是 admin/admin ,第一次登入以後會要求改密碼。
8.3. 打開 grafana 安裝 data source ,指向 prometheus service 的 endpoint
查詢 endpoint 的方法:
auxo@auxo-virtual-machine:~/tmp/kind/yaml$ kubectl describe svc/prometheus | grep -i endpoint
Endpoints: 10.244.3.6:9090
所以 endpoint 就是 http://10.244.3.6:9090
注意這裡使用的是 cluster ip 。
9. import dashboard
在 grafana 網站上有一堆人家定義好的 dashboard 可以套,可以參考一下。
https://grafana.com/grafana/dashboards/
9.1. 找到喜歡的 dashboard 以後,下載它 ( 以 json 的格式) ,然後在 grafana 的 GUI 上 import 就可以了。
9.1.1. 以 kubernetes cluster 這個 dashboard 為例,先找到這個網頁
https://grafana.com/grafana/dashboards/7249
9.1.2. 注意頁面右邊有個 Download JSON
https://grafana.com/api/dashboards/7249/revisions/1/download
9.1.3. 在 grafana 的 GUI 上 import 這個 json 就可以了。
留言