最近在K8S集群中部署了node-exporter + prometheus + grafana,具体过程可以参考我的Github项目kubernetes-prometheus-grafana。这个博客用来记录下过程中的一些知识点,主要有这些:
主题 | 详述 |
---|---|
K8S的RBAC | 全称是基于角色的访问控制,K8S权限机制的基础 |
在Pod中访问ApiServer | Prometheus是运行在k8s集群中的一个pod,访问k8s的apiserver时需要一些鉴权机制 |
Prometheus Service Discovery | Prometheus是pull模型,需要自动地发现k8s集群中有哪些endpoing、node、service等,并watch其变更 |
Prometheus relabel_configs | 在prometheus的抓取job中过滤、转换target的label |
prometheus manifest简析
prometheus部署的manifest主要有如下几个部分
- ClusterRole、 ClusterRoleBinding:RBAC权限控制部分,给namespace monitoring下的default serviceaccount赋予了对相关资源的get、list、watch权限。
- ConfigMap: Prometheus 配置文件部分,创建了alert manager告警规则和prometheus抓取规则,其中包括各种k8s服务发现和relabel configs。
- Prometheus的Deployment和Service
具体的yaml文件参见我的Github项目kubernetes-prometheus-grafana。第三部分我已经很熟悉了,新知识点主要在第一二部分。
K8S RBAC访问控制
像我们部署kubernetes-dashboard和prometheus时都需要创建ServiceAccount、ClusterRoleBinding等,这些就是RBAC机制的组成部分。kubernetes-dashboard和prometheus用他们来访问ApiServer。
RBAC是一个权限控制的常见方案,由三个部分组成:ClusterRole、ServiceAccount和ClusterRoleBinding。ClusterRole定义了对一系列资源的访问权限。而ClusterRoleBinding则将ClusterRole赋予给ServiceAccount,也就将角色的权限赋予了账号。这部分可以详见参考文档1,写的很详细了。
在进入下一节介绍pod访问apiserver前,我摘录一些RBAC重要的信息:
- 每一个namespace下都有一个default的ServiceAccount。
- 每一个pod都有一个ServiceAccount,没有特别指定的话,pod的ServiceAccount将会是其namespace的default ServiceAccount。
- 在pod的文件系统中,有个神秘目录:
/var/run/secrets/kubernetes.io/serviceaccount/
这个神秘目录下有三个文件,其内容分别是:
- token: 该pod的ServiceAccount的token。
- ca.cert: k8s集群签发ssl证书的ca证书。信任此证书才能访问集群内的https服务,例如apiserver的6443端口。
- namespace: 该pod的namespace。
后文还将提到这个神秘目录。
pod访问ApiServer
官方文档directly-accessing-the-rest-api有介绍了具体方案。简单说可以分为
- 创建ClusterRoleBinding,赋予某ServiceAccount一定的访问权限
- 创建该ServiceAccount的临时token。
- 创建一个curl的pod,并在pod中执行curl访问ApiServer。注意我们携带了token,并且通过
-k
跳过了证书验证。
PS:如果需要长期存在的可以参考:manually-create-a-long-lived-api-token-for-a-serviceaccount。也可以按照文末附录的#创建长期存在的token流程实验一下。
接下来我们会实施一下,我们直接使用了cluster-admin的角色,免得创建细粒度的ClusterRole,当然这在生产中是不推荐的。我们在最后也清理掉了这个ServiceAccount。shell脚本如下:
# 创建具有cluster-admin角色的test-admin-user
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-admin-user
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: test-admin-user
namespace: default
EOF
# 创建test-admin-user的token
token=`kubectl -n default create token test-admin-user`
echo $token
# 创建一个curl pod,并使用token访问apiserver的prometheus exporter
kubectl run curl --image=redhat/ubi9-minimal:9.2-717 --attach --rm --command --restart=Never -- \
curl https://kubernetes.default:443/metrics -k \
-H "Authorization: Bearer $token"
# 清理
kubectl delete ServiceAccount test-admin-user
kubectl delete ClusterRoleBinding test-admin-user
上面只是一个实验,那我们的kubernetes-dashboard和prometheus又是如何访问ApiServer的呢?其实也分为三部分:
- 创建ServiceAccount、ClusterRole、ClusterRoleBinding。
- 信任pod“神秘目录”下的ca.cert,并发起http请求
- http请求中携带pod“神秘目录”下的token,作为Authorization请求头。
Prometheus进行k8s服务发现时就遵循上面的流程。
Service Discovery和Relabel configs
不做追述,给两个Prometheus的官方文档给大家指路。
Github项目kubernetes-prometheus-grafana中 prometheus.yaml
的 ConfigMap
是 kubernetes_sd_config 和 relabel_config 的实际例子,可以对照查看。
PS: Prometheus部署在K8S集群外也可以监控K8S集群,此时需要指定apiserver地址,token和ca_cert(或设置不验证证书)。参考文档中的这段描述:
# The API server addresses. If left empty, Prometheus is assumed to run inside
# of the cluster and will discover API servers automatically and use the pod's
# CA certificate and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/.
[ api_server: <host> ]
附录
参考文档
创建长期存在的token
首先创建了cluster-admin角色的ServiceAccount “arloor”,并生成长期存在的token
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: arloor
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: arloor
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: arloor
namespace: default
---
apiVersion: v1
kind: Secret
metadata:
name: arloor-secret
namespace: default
annotations:
kubernetes.io/service-account.name: arloor
type: kubernetes.io/service-account-token
EOF
kubectl get secret/arloor-secret -o yaml #查看token字段,base64格式的
kubectl describe secret/arloor-secret # 查看token字段,原始的
其中 kubectl get
得到的是Base64编码过的,需要base64解码才能使用:
base64 -d - <<EOF
xxxxxxx token
EOF