Skip to content
Go back

从零开始部署本地 K3s 集群并结合 Prometheus 和 Grafana 进行监控

| 0 Views Edit page

前言

2021 年开始,K3s 就成为了我独立项目中必不可少的组成部分。大量的长连接爬虫、消息队列消费者都在上面获得了稳定的运行环境,以及弹性扩容的能力。
趁着这次针对部署环境变更导致的重构,也再次详细记录一下。


方案概述

  1. 搭建 Prometheus + Grafana 监控平台
  2. 搭建 K3s 集群
    1. 安装 server 节点
    2. 安装 agent 节点
  3. 暴露内置的 kubeletcAdvisor 的指标
  4. 使用 kube-state-metrics 暴露其他 K3s 的指标
  5. 配置 Prometheus 抓取所有指标
    1. 抓取 kubelet 的指标
    2. 抓取 cadvisor 的指标
    3. 抓取 kube-state-metrics 的指标
  6. Grafana 中创建 Dashboard 展示指标

操作步骤

一、搭建 Prometheus + Grafana 监控平台

直接参考我的另一篇文章:搭建 Prometheus + Grafana 监控平台并使用 Node Exporter 监测服务器状态

二、搭建 K3s 集群

虽然我的步骤不会存在错误,但依然请仅将我的步骤作为参考。
我非常推荐您按照官方中文文档一步一步进行搭建:K3s - 轻量级 Kubernetes,以确保能理解每一个参数和每一个可能存在问题的环节,毕竟 K3s 在后期依然需要不少维护。

我本地的集群配置为:

角色主机名IP 地址核心数内存系统
Serverk3s-server192.168.1.10024GBUbuntu 22.04
Agentk3s-agent-01192.168.1.101612GBUbuntu 22.04
Agentk3s-agent-02192.168.1.102612GBUbuntu 22.04

由于我不涉及复杂的调度,主要的 Server 上也不会启动需要大量资源的容器,所以这里仅分配了 2 核心和 4GB 内存。
Agent 则是业务容器的实际承载者,因此分配了 6 核心和 12GB 内存。

1、安装 server 节点

按照官方推荐的,使用中国境内的资源加速安装:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
    INSTALL_K3S_MIRROR=cn \
    INSTALL_K3S_REGISTRIES=registry.example.com \
    sh -s - \
    --system-default-registry=registry.example.com

这里的 INSTALL_K3S_REGISTRIES--system-default-registry 参数是可选的,如果你不想使用自建的镜像仓库,可以去掉。

  • INSTALL_K3S_REGISTRIES 是解决 K3s 在启动后,你需要新建的容器无法从官方 Docker 仓库拉取镜像的问题;
  • --system-default-registry 则是解决在 kubectl run 或是 K3s 集群自身初始化的时候,无法访问官方 Docker 仓库的问题。

这里我使用了自建的镜像仓库以解决无法访问 Docker 的问题,如果你也想自建的话可以参考:使用 Docker 启动 Registry 镜像加速服务并使用 Caddy 进行 TLS 证书管理

针对 Docker 镜像的下载地址,保险起见将配置文件中的也作修改:

nano /etc/rancher/k3s/registries.yaml
文件内容:
```yaml
mirrors:
  "docker.io":
    endpoint:
      - "https://registry.example.com"

重启 K3s 服务:

systemctl restart k3s

都完成后确认下集群状态:

kubectl get nodes

有准备完成的节点,说明 server 节点就已经准备就绪了。

如果你和我一样通过 Tailscale 构建私网的话,可以顺便配置一下 DNS 分流:

kubectl edit configmap coredns -n kube-system
apiVersion: v1
data:
  Corefile: |
    .:53 {
        # ... 这里是原有的默认配置,不要修改 ...
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
        }
        forward . /etc/resolv.conf  
        # ... 略 ...
    }
    
    # ======= 新增下面的独立块 =======
    ts.net:53 {
        errors
        cache 30
        # 强制将所有该域名的解析转发给已在宿主机上打通的 MagicDNS
        forward . 100.100.100.100
    }
    # ==============================
kubectl rollout restart deployment coredns -n kube-system

这样之后 Pod 中的应用就可以解析 hostname.ts.net 这类私网域名了。

2、安装 agent 节点

安装前,需要先去 server 节点上获取 node-token

cat /var/lib/rancher/k3s/server/node-token

获取到后,再去 agent 所在的服务器上进行安装:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
    INSTALL_K3S_MIRROR=cn \
    K3S_URL=https://192.168.1.100:6443 \
    K3S_TOKEN=<node-token> \
    sh -

注意这里 K3S_URL 要使用 HTTPS 协议,由于我是内网部署,因此直接使用 IP 地址作为 K3S_URL 了。

完成后在 agent 节点先确认下集群状态:

sudo systemctl status k3s-agent

没问题的话,再去 server 节点上确认下集群状态:

kubectl get nodes

就能看到准备好的 agent 节点了。
注意:agent 节点一定需要设置 Docker 镜像的下载地址,否则默认从 docker.io 进行拉取!

nano /etc/rancher/k3s/registries.yaml
```yaml
mirrors:
  "docker.io":
    endpoint:
      - "https://registry.example.com"
systemctl restart k3s-agent

三、暴露内置的 kubelet 和 cAdvisor 的指标

这里推荐一个 Bilibili 的视频:【kubernetes】30分钟上手Prometheus监控k8s集群,打通云原生核心技术栈! k8s教程/k8s集群管理

kubectl 将指标暴露在了所有节点的 10250 端口上,但是如果你直接访问的话:

curl -k https://localhost:10250/metrics
# 使用 /metrics/cadvisor 来获取内置的 cAdvisor 的指标
# curl -k https://localhost:10250/metrics/cadvisor

会看到如下错误:

Unauthorized

我们需要先生成一个认证用的长效密钥:

# 使用 namespace + 服务名作为目录名
mkdir -vp /root/k3s/kube-system/kubelet/
nano /root/k3s/kube-system/kubelet/prometheus-kubelet-rbac.yaml
---
# 创建 prometheus 服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: kube-system
---
# 创建一个只读的集群角色,用于抓取 kubelet/cAdvisor 指标
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-kubelet-readonly
rules:
  - apiGroups: [""]
    resources: ["nodes", "nodes/metrics", "nodes/proxy", "pods", "services", "endpoints"]
    verbs: ["get", "list", "watch"] # 仅限只读操作
---
# 将上面的只读角色绑定到 prometheus 服务账号
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-kubelet-readonly-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus-kubelet-readonly
subjects:
  - kind: ServiceAccount
    name: prometheus
    namespace: kube-system
---
# 创建一个 Secret 来生成并永久保存 prometheus 账号的长效 Token
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
  name: prometheus-token-secret
  namespace: kube-system
  annotations:
    kubernetes.io/service-account.name: "prometheus"

保存后,启动部署:

kubectl apply -f /root/k3s/kube-system/kubelet/prometheus-kubelet-rbac.yaml

没问题的话,你会和我一样看到如下输出:
角色创建成功
然后获取 prometheus 服务账号的长效密钥:

kubectl get secret -n kube-system prometheus-token-secret -o jsonpath='{.data.token}' | base64 -d

复制上面的密钥并保存好,你可以现在就用这个 Token 来访问 kubelet 的指标试一下:

curl -k -H "Authorization: Bearer <token>" https://localhost:10250/metrics
# 使用 /metrics/cadvisor 来获取内置的 cAdvisor 的指标
# curl -k -H "Authorization: Bearer <token>" https://localhost:10250/metrics/cadvisor

如果能看到大量 kube_pod_info 格式的文本数据,说明指标已经成功暴露!

四、使用 kube-state-metrics 暴露其他 K3s 的指标

官方仓库:kube-state-metrics
这里我不使用 helm 而是直接写 yaml 文件来安装:

# 使用 namespace + 服务名作为目录名
mkdir -vp /root/k3s/kube-system/kube-state-metrics/
nano /root/k3s/kube-system/kube-state-metrics/kube-state-metrics.yaml
---
# 创建 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kube-state-metrics
  # 考虑到这个监控的职责重大,因此直接使用 kube-system 系统自带的命名空间
  namespace: kube-system
---
# 创建 ClusterRole 用于授权
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kube-state-metrics
rules:
  # 截取了官方仓库例子 https://raw.githubusercontent.com/kubernetes/kube-state-metrics/refs/heads/main/examples/standard/cluster-role.yaml 中的大部分
  - apiGroups: [""]
    resources: ["configmaps", "secrets", "nodes", "pods", "services", "resourcequotas", "replicationcontrollers", "limitranges", "persistentvolumeclaims", "persistentvolumes", "namespaces", "endpoints"]
    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: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["list", "watch"]
  - apiGroups: ["networking.k8s.io"]
    resources: ["ingresses", "networkpolicies"]
    verbs: ["list", "watch"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "volumeattachments"]
    verbs: ["list", "watch"]
---
# 创建 ClusterRoleBinding 用于绑定 ClusterRole 到 ServiceAccount
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: kube-system
---
# 实际的 Deployment 配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-state-metrics
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kube-state-metrics
  template:
    metadata:
      labels:
        app: kube-state-metrics
    spec:
      serviceAccountName: kube-state-metrics
      containers:
        - name: kube-state-metrics
          # 由于 Docker Hub 的相关镜像源近期不稳定,我写文章的这个时间点,bitnami/kube-state-metrics 镜像的所有 Tag 都被官方删除了
          # 因此这里改为使用 Amazon ECR 上 bitnami 的镜像
          image: public.ecr.aws/bitnami/kube-state-metrics:2.17.0
          ports:
            - containerPort: 8080
              name: http-metrics
---
# 创建 Service 来暴露端口
apiVersion: v1
kind: Service
metadata:
  name: kube-state-metrics
  namespace: kube-system
spec:
  type: NodePort
  ports:
    - name: http-metrics
      port: 8080
      targetPort: http-metrics
      nodePort: 30808  # 暴露给外部 Prometheus 的端口
  selector:
    app: kube-state-metrics

然后启动部署:

kubectl apply -f /root/k3s/kube-system/kube-state-metrics/kube-state-metrics.yaml

没问题的话,你会和我一样看到如下输出:
输出

看下 kube-state-metrics 的 Pod 状态:

kubectl get pods -n kube-system -l app=kube-state-metrics

有准备完成的 Pod,说明 kube-state-metrics 就已经准备就绪了。
使用 curl 来测试下是否能访问到 kube-state-metrics 的指标:

curl http://192.168.1.100:30808/metrics

如果能看到大量 kube_pod_info 格式的文本数据,说明指标已经成功暴露!

五、配置 Prometheus 抓取所有指标

注意,在进行配置之前,请先确定好你所要使用的 Grafana Dashboard!
不同 Dashboard 对数据结构的要求可能会有不同,错误的数据标签会导致在面板上部分数据无法展示!
我的所有配置都是为了兼容 Kubernetes / Views / Pods (ID: 15760) 这个 Dashboard 的。

1、抓取 kubelet 的指标

nano /opt/prometheus/prometheus.yml
  - job_name: 'k3s-kubelet-my-k3s-cluster'
    scheme: https
    tls_config:
      insecure_skip_verify: true
    bearer_token: '<kubelet-prometheus-token>'
    kubernetes_sd_configs:
      - role: node
        # 这里填你 K3s Server 的地址
        api_server: 'https://192.168.1.100:6443'
        tls_config:
          insecure_skip_verify: true
        bearer_token: '<kubelet-prometheus-token>'
    relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
    # 保险起见这里手动打个 cluster 标签
    metric_relabel_configs:
      - target_label: cluster
        replacement: my-k3s-cluster
curl -X POST http://localhost:9090/-/reload

2、抓取 cadvisor 的指标

nano /opt/prometheus/prometheus.yml
  - job_name: 'k3s-cadvisor-my-k3s-cluster'
    scheme: https
    tls_config:
      insecure_skip_verify: true
    bearer_token: '<kubelet-prometheus-token>'
    metrics_path: '/metrics/cadvisor'
    kubernetes_sd_configs:
      - role: node
        api_server: 'https://192.168.1.100:6443'
        tls_config:
          insecure_skip_verify: true
        bearer_token: '<kubelet-prometheus-token>'
    relabel_configs:
      - action: labelmap
        regex: __meta_kubernetes_node_label_(.+)
    metric_relabel_configs:
      - target_label: cluster
        replacement: my-k3s-cluster
curl -X POST http://localhost:9090/-/reload

3、抓取 kube-state-metrics 的指标

nano /opt/prometheus/prometheus.yml
  - job_name: 'k3s-kube-state-metrics-my-k3s-cluster'
    scheme: http
    static_configs:
      - targets:
        - '192.168.1.100:30808'
    metric_relabel_configs:
      - target_label: cluster
        replacement: my-k3s-cluster
curl -X POST http://localhost:9090/-/reload

六、在 Grafana 中创建 Dashboard 展示指标

Dashboards > Import dashboard 中直接导入我上述提到的 Kubernetes / Views / Pods (ID: 15760) 这个 Dashboard:
Dashboard

数据看起来都正常,暂时结束。
后续实际使用中,如果有问题会再次进行补充说明。


Edit page