前言
从 2021 年开始,K3s 就成为了我独立项目中必不可少的组成部分。大量的长连接爬虫、消息队列消费者都在上面获得了稳定的运行环境,以及弹性扩容的能力。
趁着这次针对部署环境变更导致的重构,也再次详细记录一下。
方案概述
- 搭建
Prometheus+Grafana监控平台 - 搭建
K3s集群- 安装
server节点 - 安装
agent节点
- 安装
- 暴露内置的
kubelet和cAdvisor的指标 - 使用
kube-state-metrics暴露其他K3s的指标 - 配置
Prometheus抓取所有指标- 抓取
kubelet的指标 - 抓取
cadvisor的指标 - 抓取
kube-state-metrics的指标
- 抓取
- 在
Grafana中创建 Dashboard 展示指标
操作步骤
一、搭建 Prometheus + Grafana 监控平台
直接参考我的另一篇文章:搭建 Prometheus + Grafana 监控平台并使用 Node Exporter 监测服务器状态
二、搭建 K3s 集群
虽然我的步骤不会存在错误,但依然请仅将我的步骤作为参考。
我非常推荐您按照官方中文文档一步一步进行搭建:K3s - 轻量级 Kubernetes,以确保能理解每一个参数和每一个可能存在问题的环节,毕竟K3s在后期依然需要不少维护。
我本地的集群配置为:
| 角色 | 主机名 | IP 地址 | 核心数 | 内存 | 系统 |
|---|---|---|---|---|---|
| Server | k3s-server | 192.168.1.100 | 2 | 4GB | Ubuntu 22.04 |
| Agent | k3s-agent-01 | 192.168.1.101 | 6 | 12GB | Ubuntu 22.04 |
| Agent | k3s-agent-02 | 192.168.1.102 | 6 | 12GB | Ubuntu 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-systemapiVersion: 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:

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