由于在该环境中Kubernetes的版本是 1.20.2,我们不使用最新版 kube-prometheus-stack,而采用兼容 1.20 的 Prometheus Operator + Grafana 部署方案,避免兼容性问题。对于 Kubernetes 1.20,官方兼容矩阵建议使用较早的 kube-prometheus release(如 release-0.8)。


15.1 准备环境

15.1.1 确认节点全部正常

在 ECS 上执行:

kubectl get nodes

应该类似:

NAME         STATUS   ROLES
ecs-prod     Ready    control-plane
k8s-node1    Ready
k8s-node2    Ready

如果不是全部 Ready,就先不要继续。

kubectl get pods -A

确保:

CoreDNS
Calico
Ingress

全部 Running。


15.1.2 确认资源充足

执行:

kubectl top nodes

如果没有安装 metrics-server,不要紧,会提示:

Metrics API not available

后续我们也可以补装。


15.1.3 创建监控命名空间

kubectl create namespace monitoring

查看:

kubectl get ns

应该出现:

monitoring

15.2 拉取node-exporter:v1.3.1镜像并推送Harbor

15.2.1 devops机器拉取镜像

你的 devops:

192.168.10.10

执行:

docker pull prom/node-exporter:v1.3.1

如果速度慢,可以使用镜像加速。

15.2.2 登录 Harbor

devops:

docker login 192.168.10.20

输入 Harbor 用户密码。


15.2.3 修改镜像名称

docker tag \
prom/node-exporter:v1.3.1 \
192.168.10.20/hybridblog/node-exporter:v1.3.1

检查:

docker images | grep node-exporter

应该:

192.168.10.20/hybridblog/node-exporter:v1.3.1

15.2.4 推送 Harbor

docker push \
192.168.10.20/hybridblog/node-exporter:v1.3.1

成功:

digest: sha256:xxxx

15.3 准备命名空间并部署node-exporter

15.3.1 创建 monitoring 命名空间

建议和你的:

hybridblog
kube-system
ingress-nginx

分开。

在 ECS master:

mkdir -p /data/k8s/monitoring

cd /data/k8s/monitoring

创建:

vim namespace.yaml

内容:

apiVersion: v1
kind: Namespace

metadata:
  name: monitoring

执行:

kubectl apply -f namespace.yaml

检查:

kubectl get ns

应该:

monitoring Active

15.3.2 创建 Harbor 拉取密钥

因为你的镜像:

192.168.10.20/hybridblog/node-exporter:v1.3.1

不是公网镜像。

所以 Kubernetes 需要 Harbor 登录信息。

执行:

kubectl create secret docker-registry harbor-secret \
--docker-server=192.168.10.20 \
--docker-username=你的Harbor用户名 \
--docker-password=你的密码 \
-n monitoring

查看:

kubectl get secret -n monitoring

应该:

NAME             TYPE
harbor-secret    kubernetes.io/dockerconfigjson

15.3.3 部署 node-exporter

作用:

采集 Linux 主机指标:

例如:

  • CPU
  • 内存
  • 磁盘
  • 网络

Prometheus 不直接读取节点信息。

结构:

Linux节点

 ↓

node-exporter

 ↓

Prometheus

创建:

vim node-exporter.yaml

内容:

apiVersion: apps/v1
kind: DaemonSet

metadata:
  name: node-exporter
  namespace: monitoring


spec:

  selector:
    matchLabels:
      app: node-exporter


  template:

    metadata:

      labels:
        app: node-exporter


    spec:

      imagePullSecrets:
      - name: harbor-secret

      containers:

      - name: node-exporter

        image:
          192.168.10.20/hybridblog/node-exporter:v1.3.1


        ports:

        - containerPort: 9100

          name: metrics


        args:

        - "--path.rootfs=/host"


        volumeMounts:

        - name: root

          mountPath: /host

          readOnly: true


      volumes:

      - name: root

        hostPath:

          path: /

建议增加:

resources:

  requests:

    cpu: 50m

    memory: 64Mi

  limits:

    cpu: 100m

    memory: 128Mi

避免以后监控组件占资源。

部署:

kubectl apply -f node-exporter.yaml

查看:

kubectl get pod -n monitoring -o wide

应该类似:

node-exporter-xxxxx   Running   k8s-node1

node-exporter-yyyyy   Running   k8s-node2

因为 DaemonSet 会:

每个 Node 自动创建一个 Pod


15.3.4 创建 node-exporter Service

Prometheus 需要访问 node-exporter。

创建:

vim node-exporter-service.yaml

内容:

apiVersion: v1
kind: Service

metadata:

  name: node-exporter

  namespace: monitoring


spec:

  selector:

    app: node-exporter


  ports:

  - port: 9100

    targetPort: 9100


  type: ClusterIP

执行:

kubectl apply -f node-exporter-service.yaml

查看:

kubectl get svc -n monitoring

应该:

node-exporter   ClusterIP   10.xx.xx.xx   9100/TCP

15.3.5 验证 node-exporter

进入任意节点:

或者 ECS:

kubectl run test \
--image=busybox \
-n monitoring \
-it --rm \
-- sh

测试:

wget -qO- http://node-exporter:9100/metrics

如果看到:

# HELP node_cpu_seconds_total
node_cpu_seconds_total...

说明成功。


到这里完成第一层监控:

Kubernetes

Node1
 |
 node-exporter
 |
Node2
 |
 node-exporter


        ↓

 Prometheus

15.4 部署Prometheus

15.4.1 准备Prometheus镜像

在devops节点:

进入:

cd /root

拉取官方镜像:

docker pull prom/prometheus:v2.53.0

查看:

docker images | grep prometheus

打tag:

docker tag \
prom/prometheus:v2.53.0 \
192.168.10.20/hybridblog/prometheus:v2.53.0

登录Harbor:

docker login 192.168.10.20

推送:

docker push \
192.168.10.20/hybridblog/prometheus:v2.53.0

15.4.2 创建monitoring目录

在ecs-prod:

mkdir -p /root/monitoring/prometheus
cd /root/monitoring/prometheus

创建:

prometheus/
├── prometheus.yml
├── prometheus-deployment.yaml
├── prometheus-rbac.yaml
└── prometheus-service.yaml

15.4.3 创建 prometheus RBAC

进入:

cd /root/monitoring/prometheus

创建:

vim prometheus-rbac.yaml

内容:

apiVersion: v1
kind: ServiceAccount

metadata:

  name: prometheus

  namespace: monitoring



---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole

metadata:

  name: prometheus



rules:

- apiGroups:

  - ""

  resources:

  - pods

  - nodes

  - services

  verbs:

  - get

  - list

  - watch



---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding

metadata:

  name: prometheus



roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: prometheus



subjects:

- kind: ServiceAccount

  name: prometheus

  namespace: monitoring

应用:

kubectl apply -f prometheus-rbac.yaml

15.4.4 创建Prometheus配置文件

创建:

vim prometheus.yml

内容:

global:
  scrape_interval: 20s


scrape_configs:

- job_name: node-exporter

  kubernetes_sd_configs:

  - role: pod


  relabel_configs:


  - source_labels:
    - __meta_kubernetes_pod_label_app

    action: keep

    regex: node-exporter



  - source_labels:
    - __meta_kubernetes_pod_ip

    regex: (.+)

    target_label: __address__

    replacement: $1:9100



  - source_labels:
    - __meta_kubernetes_pod_node_name

    target_label: node



  - source_labels:
    - __meta_kubernetes_pod_name

    target_label: pod

15.4.5 创建ConfigMap

kubectl create configmap prometheus-config \
-n monitoring \
--from-file=prometheus.yml

检查:

kubectl get configmap -n monitoring

应该:

prometheus-config

15.4.6 部署Prometheus Deployment

创建:

vim prometheus-deployment.yaml

内容:

apiVersion: apps/v1
kind: Deployment

metadata:
  name: prometheus
  namespace: monitoring


spec:

  replicas: 1


  selector:
    matchLabels:
      app: prometheus


  template:

    metadata:

      labels:
        app: prometheus


    spec:

      nodeSelector:

        kubernetes.io/hostname: k8s-node1

      imagePullSecrets:

      - name: harbor-secret

      serviceAccountName: prometheus

      containers:


      - name: prometheus


        image: 192.168.10.20/hybridblog/prometheus:v2.53.0


        args:

        - "--config.file=/etc/prometheus/prometheus.yml"



        ports:

        - containerPort: 9090



        volumeMounts:

        - name: config

          mountPath: /etc/prometheus




      volumes:


      - name: config


        configMap:

          name: prometheus-config

15.4.7 创建Service

vim prometheus-service.yaml

内容:

apiVersion: v1
kind: Service

metadata:

  name: prometheus

  namespace: monitoring


spec:


  selector:

    app: prometheus


  ports:

  - port: 9090

    targetPort:9090


  type: NodePort

部署:

kubectl apply -f prometheus-deployment.yaml

kubectl apply -f prometheus-service.yaml

查看:

kubectl get pod -n monitoring

应该:

NAME
node-exporter-xxxxx
node-exporter-yyyyy
prometheus-xxxxx

15.4.8 确认Prometheus采集成功

查看service:

kubectl get svc -n monitoring

例如:

prometheus NodePort

9090:30090

访问:

http://192.168.10.40:30090

进入:

Status
 ↓
Targets

应该看到:

node-exporter

UP

10.244.xx.xx:9100
10.244.xx.xx:9100

完成这里之后,再部署:

Prometheus
       |
       |
       v
Grafana
       |
       |
Dashboard
       |
       |
CPU
Memory
Disk
Network

你的最终监控架构:

                    Grafana
                       |
                       |
                 Prometheus
                       |
        ------------------------------
        |                            |
 node-exporter                  node-exporter
        |                            |
   k8s-node1                  k8s-node2


镜像来源:

Harbor
 |
 |
Prometheus镜像
Node-exporter镜像

15.5 部署 Grafana

15.5.1 Grafana 部署目标

最终:

浏览器
 |
 |
Grafana
 |
 |
Prometheus
 |
 |
node-exporter
 |
 |
k8s-node1
k8s-node2

15.5.2 准备 Grafana 镜像

因为你的网络结构:

ecs-prod
 |
VPN
 |
k8s-node1
k8s-node2
 |
Harbor

所以继续使用 Harbor。

在 devops 节点:

docker pull grafana/grafana:11.1.0

查看:

docker images | grep grafana

应该:

grafana/grafana   11.1.0

打标签:

docker tag \
grafana/grafana:11.1.0 \
192.168.10.20/hybridblog/grafana:11.1.0

登录:

docker login 192.168.10.20

推送:

docker push \
192.168.10.20/hybridblog/grafana:11.1.0

确认 Harbor:

应该看到:

hybridblog

 └── grafana

      └── 11.1.0

15.5.4 创建 Grafana namespace

你的 Prometheus 已经在:

monitoring

所以继续:

kubectl get ns

如果存在:

monitoring

不用创建。


15.5.5 创建持久化环境

在ecs-prod:

kubectl label node k8s-node1 grafana=true

登录 k8s-node1:

ssh k8s-node1

创建目录:

mkdir -p /data/grafana

修改权限:

Grafana 官方镜像默认 uid 为 472

chown -R 472:472 /data/grafana
chmod -R 755 /data/grafana

15.5.5 创建 Grafana Deployment

创建目录:

mkdir -p /root/monitoring/grafana

cd /root/monitoring/grafana

创建:

vim grafana-deployment.yaml

内容:

apiVersion: apps/v1
kind: Deployment

metadata:
  name: grafana
  namespace: monitoring

spec:
  replicas: 1

  selector:
    matchLabels:
      app: grafana

  template:
    metadata:
      labels:
        app: grafana

    spec:
      nodeSelector:
        grafana: "true"

      imagePullSecrets:
      - name: harbor-secret

      containers:
      - name: grafana

        image: 192.168.10.20/hybridblog/grafana:11.1.0

        ports:
        - containerPort: 3000

        env:
        - name: GF_SECURITY_ADMIN_USER
          value: "admin"

        - name: GF_SECURITY_ADMIN_PASSWORD
          value: "admin"

        volumeMounts:
        - name: grafana-storage
          mountPath: /var/lib/grafana

      volumes:
      - name: grafana-storage
        hostPath:
          path: /data/grafana
          type: DirectoryOrCreate

部署:

kubectl apply -f grafana-deployment.yaml

查看:

kubectl get pod -n monitoring -o wide

预计:

grafana-xxxxx    Running

15.5.6 创建 Grafana Service

创建:

vim grafana-service.yaml

内容:

apiVersion: v1
kind: Service

metadata:
  name: grafana
  namespace: monitoring


spec:

  selector:

    app: grafana


  ports:

  - port: 3000

    targetPort: 3000

    nodePort: 30030


  type: NodePort

应用:

kubectl apply -f grafana-service.yaml

查看:

kubectl get svc -n monitoring

例如:

grafana   NodePort   10.96.xx.xx   3000:30030/TCP

访问:

http://k8s-node1_IP:30030

登录:

用户名:
admin

密码:
admin

15.5.7 添加 Prometheus 数据源

进入 Grafana 首页:

左侧菜单:

Connections
    ↓
Data sources

点击:

Add data source

选择:

Prometheus

配置 Prometheus URL

重点是这里。

你的 Prometheus 在:

monitoring namespace

Service 名字:

应该是:

kubectl get svc -n monitoring

类似:

NAME          TYPE
prometheus    ClusterIP
grafana       NodePort

假设:

prometheus

那么 Kubernetes DNS:

prometheus.monitoring.svc.cluster.local

端口:

9090

所以 URL 填:

http://prometheus.monitoring.svc.cluster.local:9090

如下:

URL:

http://prometheus.monitoring.svc.cluster.local:9090

其他保持默认:

Access:
Server

不要选择 Browser。

点击:

Save & Test

成功应该显示:

Successfully queried the Prometheus API.

15.5.8 导入 Node Exporter Full Dashboard

左侧:

Dashboards
      ↓
New
      ↓
Import

看到:

Import dashboard

输入:

1860

也就是:

Node Exporter Full

点击:

Load

15.5.9选择数据源

下一页会让你选择:

Prometheus

选择刚才创建的数据源:

例如:

Prometheus

然后:

Import