# 系统环境
- 部署方式:二进制
- Docker 版本:19.03.8
- kubernetes 版本:1.18.4
- 操作系统版本:CentOS 7.4
- metrics server 版本:0.4.1
#问题描述
二进制部署完集群后,部署Metrics Server,无法正常查看node及pod的信息,查看日志出现如下错误信息
```bash
E1231 10:33:31.978715 1 configmap_cafile_content.go:243] key failed with:
missing content for CA bundle "client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file"
E1231 10:34:22.710836 1 configmap_cafile_content.go:243] kube-system/extension-apiserver-authentication failed with:
missing content for CA bundle "client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file"
E1231 10:34:31.978769 1 configmap_cafile_content.go:243] key failed with:
missing content for CA bundle "client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file"
```
根据错误日志信息,可以知道是缺少认证的证书文件,导致不能访问 kube-apiserver 而出现的问题
#问题分析
通过网上查找资料及像大牛们请教,这个错误是因为kube-apiserver 没有开启 API 聚合功能,所以需要配置 kube-apiserver 参数,开启聚合功能即可(kubeadm部署方式默认开启)
## 什么是API聚合
API 聚合机制 是 Kubernetes 1.7 版本引入的特性,能够将用户扩展的 API 注册到 kube-apiserver 上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个 API 聚合层(API Aggregation Layer),用于将 扩展 API 的访问请求转发到用户服务的功能
为了能够将用户自定义的 API 注册到 Master 的 API Server 中,首先需要在 Master 节点所在服务器,配置 kube-apiserver 应用的启动参数来启用 API 聚合 功能,参数如下:
```bash
--runtime-config=api/all=true
--requestheader-allowed-names=aggregator
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-client-ca-file=/etc/kubernetes/pki/ca.pem
--proxy-client-cert-file=/etc/kubernetes/pki/proxy-client.pem
--proxy-client-key-file=/etc/kubernetes/pki/proxy-client-key.pem
```
如果 kube-apiserver 所在的主机上没有运行 kube-proxy,即无法通过服务的 ClusterIP 进行访问,那么还需要设置以下启动参数
```bash
--enable-aggregator-routing=true
```
设置完成重启 kube-apiserver 服务,就启用 API 聚合功能了
# 问题解决
## 安装cfssl工具
```bash
#下载三个组件
[root@k8s01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O cfssl
[root@k8s01 ~]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O cfssljson
[root@k8s01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O cfssl-certinfo
#复制到 bin 目录下
[root@k8s01 ~]# chmod +x ./cfssl*
[root@k8s01 ~]# mv ./cfssl* /usr/local/bin/
```
## 创建 cfssl 配置文件
```bash
[root@k8s01 ssl]# cat proxy-client-csr.json
{
"CN": "aggregator",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
```
## 生成证书和秘钥
```bash
[root@k8s01 ssl]# cfssl gencert \
-profile=kubernetes \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
proxy-client-csr.json
```
## 查看生成的证书
```bash
[root@k8s01 ssl]# ls -l|grep proxy
-rw-r--r-- 1 root root 1017 Dec 31 11:20 proxy-client.csr
-rw-r--r-- 1 root root 236 Dec 31 11:07 proxy-client-csr.json
-rw------- 1 root root 1675 Dec 31 11:20 proxy-client-key.pem
-rw-r--r-- 1 root root 1411 Dec 31 11:20 proxy-client.pem
```
## 复制到其它Master节点服务器中
```bash
[root@k8s01 ssl]# scp proxy-* root@k8s02:/opt/kubernetes/ssl
[root@k8s01 ssl]# scp proxy-* root@k8s03:/opt/kubernetes/ssl
```
## 修改 kube-apiserver参数
修改三个Master节点kube-apiserver配置参数
```bash
[root@k8s01 ~]# vim /opt/kubernetes/cfg/kube-apiserver.conf
...
--proxy-client-cert-file=/opt/kubernetes/ssl2/proxy-client.pem \
--proxy-client-key-file=/opt/kubernetes/ssl2/proxy-client-key.pem \
--runtime-config=api/all=true \
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--requestheader-allowed-names=aggregator \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
...
```
参数说明:
- –requestheader-client-ca-file: 客户端CA证书
- –requestheader-allowed-names: 允许访问的客户端 common names 列表,通过 header 中 –requestheader-username-headers 参数指定的字段获取。客户端 common names 的名称需要在 client-ca-file 中进行设置,将其设置为空值时,表示任意客户端都可访问
- –requestheader-username-headers: 参数指定的字段获取
- –requestheader-extra-headers-prefix: 请求头中需要检查的前缀名
- –requestheader-group-headers 请求头中需要检查的组名
- –requestheader-username-headers 请求头中需要检查的用户名
- –proxy-client-cert-file: 在请求期间验证Aggregator的客户端CA证书
- –proxy-client-key-file: 在请求期间验证Aggregator的客户端私钥
- –requestheader-allowed-names: 允许访问的客户端 common names 列表,通过 header 中 –requestheader-username-headers 参数指定的字段获取。客户端 common names 的名称需要在 client-ca-file 中进行设置,将其设置为空值时,表示任意客户端都可访问
修改完后重启kube-apiserver服务
# 验证
查看已有的 metrics server 的 pod
```bash
[root@k8s01 ~]# kubectl get -n kube-system po |grep metrics-server
metrics-server-646567c697-456kk 1/1 Running 3 18d
```
```bash
[root@k8s01 ~]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s01.gazellio.local 132m 1% 1488Mi 9%
k8s02.gazellio.local 161m 2% 1547Mi 9%
k8s03.gazellio.local 154m 1% 1571Mi 9%
k8s04.gazellio.local 1683m 21% 11708Mi 18%
k8s05.gazellio.local 1550m 19% 5918Mi 9%
k8s06.gazellio.local 2223m 27% 17364Mi 27%
k8s07.gazellio.local 2481m 31% 10743Mi 16%
k8s08.gazellio.local 1674m 20% 11242Mi 17%
```

Kubernetes部署Metrics Server无法访问Apiserver