heapster部署及配置使用https访问kubelet10250端口

默认情况下, heapster 使用 http 协议访问每个 kubelet 节点的10255这个非安全端口, 在kubelet 关闭此端口的情况下, 仅允许通过 https 通信时, heapster 找 kubelet拿数据成了大问题

基础环境:

auth mode: RBAC
kubelet port: only https(10250)
kubelet ca: SelfSign

创建 ServiceAccount

1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
name: heapster
namespace: kube-system

创建 ClusterRoleBinding

官方文档中的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: heapster
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:heapster
subjects:
- kind: ServiceAccount
name: heapster
namespace: kube-system

官方文档中的配置在 heapster 使用 http 协议访问 kubelet 10255 端口的时候时没有任何问题的, 但是用这份配置访问 kubelet 的 10250 端口, 你在 heapster 的 console log 日志中, 可以看到 403 Forbidden 的报错, 因为绑定的角色权限没有达到要求, 所以你需要下面这份绑定文件

1
2
3
4
5
6
7
8
9
10
11
12
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: heapster
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kubelet-api-admin
subjects:
- kind: ServiceAccount
name: heapster
namespace: kube-system

其实只是绑定的角色从 system:heapster 换成了 system:kubelet-api-admin

创建 heapster 服务

以下是官方示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: heapster
namespace: kube-system
spec:
replicas: 1
template:
metadata:
labels:
task: monitoring
k8s-app: heapster
spec:
serviceAccountName: heapster
containers:
- name: heapster
image: k8s.gcr.io/heapster-amd64:v1.5.4
imagePullPolicy: IfNotPresent
command:
- /heapster
- --source=kubernetes:https://kubernetes.default
- --sink=influxdb:http://monitoring-influxdb.kube-system.svc:8086

我们需要对如下参数做修改:

--sink 配置中有如下参数可以选择

  • inClusterConfig - Use kube config in service accounts associated with Heapster’s namespace. (default: true)
  • kubeletPort - kubelet port to use (default: 10255)
  • kubeletHttps - whether to use https to connect to kubelets (default: false)
  • insecure - whether to trust Kubernetes certificates (default: false)
  • auth - client auth file to use. Set auth if the service accounts are not usable.
  • useServiceAccount - whether to use the service account token if one is mounted at /var/run/secrets/kubernetes.io/serviceaccount/token (default: false)

需要设置访问 kubelet 的安全端口, 需要如下参数

  • kubeletPort 10250 访问10250端口
  • kubeletHttps true 以https协议访问
  • insecure true 信任kubernetes证书
  • useServiceAccount true 使用挂载进来的SA账户进行访问

最终的配置结果如下:

1
--source=kubernetes:https://k8s-master:6443?useServiceAccount=true&kubeletHttps=true&kubeletPort=10250&insecure=true

这里着重说明一下insecure配置, 一般情况下, kubelet 节点在没有静态配置服务端证书的情况下, kubelet 节点会自动生成一个自签名的服务端证书到指定或默认的目录下. 这个证书是独立于kubernetes集群的证书, 不是kubernetes集群根证书所签发的. 所以理论上, 在 kubernetse 的双向认证中, 当 apiserver 向 kubelet主动发起 https 请求后, 服务端首先会将自己的服务端证书发送给客户端(apiserver), 一般情况下, apiserver 是需要校验服务端证书是否可信的. 但是在 apiserver 与 kubelet 通信中比较特殊, 默认情况下, apiserver 是不会校验 kubelet 的服务端证书的, 因为 kubelet 一般是独立于k8集群的自签名证书, 如果真的校验, 结果肯定是服务端证书不可信, 所以索性默认就不校验了, 而是直接将 apiserver 持有的 kubelet 客户端证书发送给 kubelet, 供 kubelet 校验, 此时, kubelet 依据配置中指定的ca证书对 apiserver 发来的客户端证书进行校验.

话题再回到insecure配置. 如果你设置这个参数为true, 还要使用 https 协议去访问 kubelet, 那么 heapster 日志中将会报证书验证失败的错误. heapster 会取到每个 kubelet 的IP地址, 然后进行访问, 但问题是, kubelet 在自签名证书时, 默认依据的是自己的主机名, 所以 heapster 以 https 访问 kubelet, 一是证书不是自己持有的根证书签发的,不可信; 二是服务端的地址限定是基于DNS的主机名, 并没有设置IP, 所以也不会校验通过


参考文档: