Kubernetes集群的构成
Master Node (Control plane)
Master 是整个 Kubernetes 集群构成的基础,它负责整个集群的管理,例如处理集群的状态;组件包含 API Server, Controller manager, Scheduller, Etcd
API server
API 服务器是 Master 的统一前端入口,负责集群内其他组件的 协调 与 通信。该组件用于定义集群的状态。可以通过命令行, HTTP API, 第三方托管平台(dashboard, Rancker, Kuboard等)与 Kubernetes API 进行交互。
Scheduler
调度程序 Scheduler 负责根据可用资源来决定如何去部署容器,部署到哪里?确保所有 Pod(容器组)都分配给某一组节点。
Controller Manager
Controller manager,又分为Controller 和 Manager,Controller的组要作用是用于协调各种控制器(Deployment, Daemonset…),这些控制器可确保在节点发生故障时采取适当的措施。而 Manager 则管理的众多Controller;更一般地说,CM 负责随时将集群的当前状态调整到所需状态(Kubernetes设计基石)。
etcd
etcd 是控制平面内的一个组件,他提供了 Kubernetes 资源的存储,并为集群内组件提供了 Watch 的功能,这将意味着,etcd 在 kubernetes 集群中作为存储与分布式协调的功能。
Worker nodes
每个集群中至少需要存在一个工作节点,但是通常会有大量的节点;而工作节点包括的组件不限于 Kubelet, Kube-proxy, CNI Plugin。
Kubelet
kubelet是工作节点中管理运行时的组件,负责整个Pod (容器组)进程的生命周期
Kube-proxy
Kube-proxy 为整个集群内提供了 service 的功能,如果这个组件无法正常工作,那么整个集群内的网络通信将不能正常,因为 service 是作为集群内服务的访问入口,包含 Kubernetes API service。
CNI
CNI (Container Network Interface) 是 Kubernetes 集群中提供跨节点通信的一个组件,通常来说,它是一个独立于容器运行时(Docker等)的网络插件规范,旨在实现容器之间和容器与宿主机之间的网络连接。
一个 CNI 基本的功能就是去管理网络设备的生命周期,例如,生成网卡,添加IP地址,注销网卡,而构成这些网络功能的则有操作系统来提供的,例如网络隧道(VxLAN),而还存在一种情况就是三层网络,这时CNI会作为一个路由器来分发路由。除此之外,CNI还提供了更多的功能,例如数据包加密,网络策略,服务网格,网络加速,IPAM等功能
通过二进制安装Kubernetes cluster
硬件配置推荐
在选择节点数量时,需要考虑集群的用途,通常情况下建议至少使用 3 个节点 (APIServer),对于控制平面其他组件来说,通常最少为两个即可,因为HA架构中工作节点总是需要一个即可
要运行 apiserver 和 etcd,您需要一台具有 2 个内核和 2GB RAM 的 机器,用于中小型集群,更大规模集群可能需要更多的核心。工作节点必须有足够的资源来托管您的应用程序,并且可以有不同的配置。
etcd 硬件配置推荐
Kuberentes 中工作节点需要启动一个或多个 etcd 实例,通常官方推荐运行奇数个 etcd 实例,因为一个 3 实例时有两个活跃就具备了集群的 quorum ,同理五个实例时存在3个实例活跃即可,7=>4 等,通常集群规模不大于9,否则存在同步时的延迟。
集群的部署模式
- 单独托管的 etcd 集群
- master节点同台主机上托管 etcd 集群
- 通过 kubeadm 生成的 etcd 集群
在这里我们使用二进制方式最小化部署,即 单节点的 etcd 集群,与同时为 control plane 与 worker 一体托管在单台物理/虚拟机之上的 Kubernetes 集群
题外话:kubeadm 和 二进制究竟有什么区别?
实际上 kubeadm 和 二进制本质上并没有什么区别,如果非要说存在区别的话,那么就是其 Procss Manager 不同,
- 一个是由 systemd/system v 或其他操作系统维护的1 id的进程进行维护;
- kubeadm 部署的 kubelet 将 由
kubelet
进程自己来监控,当pod
崩溃时重启该pod
,kubelete
也无法对他们进行健康检查。静态 pod 始终绑定在某一个kubelet
,并且始终运行在同一个节点上,可以通过在 master 节点上查看/etc/kubernetes/manifests
目录
配置证书
通常情况下,大家都知道安装 kubernetes 集群需要证书,但是不知道为什么需要证书,这里需要了解 Kubernetes 认证机制,也就是“用户”在kubernetes集群中被称为什么
Kubernetes 中用户被分为几类:
- X.509 证书
- 静态 Token 文件
- Bootstrap Tokens
- Service Account Tokens
kubernetes 使用了客户端证书方式进行认证,这是作为外部用户的一种方式,这些证书会被默认生成对应的内部用户,所以需要准备证书文件,在本文中一切准备文件都是由脚本生成,不做基础的配置讲解。
对于 X.509 证书,需要注意有几点
- kubernetes 中,对于证书的用户,CN就是用户名,O 就是组织。
- 对于证书认证来说,客户端证书,也就是说客户端必须在可信任列表中,也就是 subject_name 中允许的
- 对于 Kubernetes 组件来说,通常情况下需要包含 Kubernetes API service 的所有名称(短域名+完整域名)
- kubernetes
- kubernetes.default
- kubernetes.default.svc
- kubernetes.default.svc.cluster
- kubernetes.default.svc.cluster.local
如果你希望使用IP,而不是域名,也可以对证书中sub_name增加对应域名
对于组件间认证,目前 Kubernetes 中基本上组件间认证都有 kubeconfig 完成,而 kubelet,kube-controller-manager 这两个组件,由于提供的功能不同,可能存在其他的认证方式;例如 kubelet 所作的事情是 “监听Pod资源进行部署” 那么这个时候与 APIServer 通讯使用了 kubeconfig,在例如 kubelet 要被 APIServer 签发时,此时认证是使用的 bootstrap token 进行的,而这个kubeconfig 就是 签发后生成的内容,本质上来说,kubelet 没有客户端证书,只有token,而例如 kube-scheduler 是有客户端证书,但是需要生产 kubeconfig 文件
签发kubelet
给 kubelet 签发证书主要由两部分组成,一种是 kube-controller-manager 自动签发,一种是 kubectl certifcate approve
手动签发,这里就有必要知道 kubelet 的认证的流程:
- kubelet启动时会找 kubeconfig ,如果没有进入下一部
- 没有 kubeconfig,会使用 bootstraps 进行认证,此时会被颁发客户端证书
- 在通过后,kubelet 会根据签发证书 生成 –kubeconfig 指定的 kubeconfig 文件
- 下次后,kubelet 会根据这个 kubeconfig 同 Kubernetes API 进行 验证
了解了 kubelet 的签发过程,就明白在二进制部署时,为什么需要做一个 clusterrolebinding ?
因为Kubernetes API 为 kubelet 的 bootstraps-token 使用的是用户 system:node-bootstrapper
,所以要想让这个用户可以访问 API 资源,那么就需要为这个用户绑定上集群角色(用户/组),这就需要执行一个命令
|
|
此时再去查看证书颁发,这时因为有权限访问 API 资源了, 所以获得了证书的被签发
|
|
kube-dns 的部署
coredns部署
|
|
开启IPVS
内核开启IPVS功能否则降级
|
|
or
|
|
Troubleshooting
apiserver报错 没有kubeappserver用户
|
|
Mar 2 04:54:56 node02 systemd: controller-manager.service: main process exited, code=exited, status=1/FAILURE
Mar 2 04:54:56 node02 kube-controller-manager: Get http://127.0.0.1:8443/api/v1/namespaces/kube-system/configmaps/extension-apiserver-authentication: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02"
Mar 2 04:54:56 node02 systemd: Unit controller-manager.service entered failed state.
可能是启动单元文件有问题,手动启动后正常
|
|
node “xxxx” not found
如下面问题,可能原因为 kubelet 正式还未签发
|
|
User “system:anonymous” cannot list resource xxx
原因为:kubelet 正式还未签发
|
|
问题:
"master01" is forbidden: User "system:anonymous"
原因:用户未授权
需要注意的是,这里使用的是 bootstrap 证书进行授权,所以绑定的用户必须为 bootstrap 证书授权的用户或组。
|
|
The kube-apiserver has several requirements to enable TLS bootstrapping: Authenticating the bootstrapping kubelet to the
system:bootstrappers
group [2]
|
|
报错如下
|
|
容器内 dial tcp 10.96.0.1:443: connect: connection timed out
问题1: flannela访问
dial tcp 10.96.0.1:443: connect: connection timed out
问题2:
open /run/flannel/subnet.env: no such file or directory
问题3:
Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
解决:检查kube-proxy组件
|
|
|
|
kubectl get csr 显示No Resources Found的解决记录
问题:kubectl get csr 显示No Resources Found的解决记录
解决:需要先将 bootstrap token 文件中的 kubelet-bootstrap 用户赋予 system:node-bootstrapper 角色,然后 kubelet 才有权限创建认证请求
授予KUBE-APISERVER对KUBELET API的访问权限
kubelet启动启动时,--kubeletconfig
使用参数对应的文件是否存在 如果不存在--bootstrap-kubeconfig
指定的kubeconfig文件向kube-apiserver发送CSR请求
kube-apiserver 收到 CSR 请求后,对其中的 token 进行认证,认证通过后将请求的用户设置为system:bootstrap:<Token ID>
,组设置为 ,system:bootstrappers
此操作称为Bootstrap Token Auth
。
默认这个用户和组没有创建CSR的权限,kubelet没有启动,错误日志如下:
|
|
解决方法是:创建一个集群角色绑定,绑定一个组:system:bootstrapper
和一个clusterrole system:node-bootstrapper
|
|
测试授权
|
|
kube flannel cant get cidr although podcidr available on node
|
|
参考:kube flannel cant get cidr although podcidr available on node 原因为 CIDR无法分配
network plugin is not ready: cni config uninitialized
|
|
没有安装网络插件,安装任意网络插件后恢复。
mvcc: required revision has been compacted
kube-apiserver: W1120 17:18:20.199950 70454 watcher.go:207] watch chan error: etcdserver: mvcc: required revision has been compacted
这里是etcd返回的错误,被apiserver视为警告,在注释中有这么一句话
If the context is “context.Background/TODO”, returned “WatchChan” will not be closed and block until event is triggered, except when server returns a non-recoverable error (e.g. ErrCompacted).
如果这个上下文返回WatchChan将在下次事件被触发前不会被关闭或阻塞,除非服务器返回一个ErrCompacted (不可恢复)
对于etcd 对 Revision 有如下说明
etcd对每个kv的revision 都会保留一个压缩周期的值,例如每5分钟收集一次最新revision,当压缩周期达到时,将从历史记录中后去最后一个修订版本,例如为100,此时会压缩,压缩成功会重置计数器,并以最新的revision和新的历史记录进行开始,压缩失败将在5分钟后重试--auto-compaction-retention=10
是配置压缩周期的 每多少个小时键值存储运行定期压缩。
如果最新的revision已被修订,etcd返回一个 ErrCompacted
表示已修订,此时表示为不可恢复状态
返回错误时表示这个watch被关闭,为了优雅的关闭chan,kubernetes会对这个watch错误进行返回,而 ErrCompacted
本质上不算错误
|
|
Reference
[1] Maintenance