生产化集群管理
计算节点相关
生产化集群的考量
计算节点
如何批量安装和升级计算节点的操作系统
如何管理和配置计算节点的网络信息
如何管理不同的SKU的计算节点
如何快速下架故障的计算节点
如何快速扩缩集群的规模
控制平面
如何从主节点上下载,安装和升级控制平面组件和所需的组件
如何确保集群所需要的其他组件
如何准备控制平面组件的各种安全证书
如何快速升级固件或是回滚组件的的版本
操作系统的选择
-
通用操作系统
ubuntu
centOS
fedora
-
专为容器优化的操作系统
coreOS
redHat Aotmic
Snappy ubuntu core
rancherOS
操作系统的评估和选择
是否有成熟的生态系统
内核版本
对运行时的支持
init system
包管理和系统升级
安全
云原生的原则
-
可变基础设施风险
在灾难发生的时候,难以重新构建服务,持续过的手工操作,没有记录
在服务运行过程中,持续修改服务器,持续引入变量,导致不可预知的风险
-
不可变基础设施
不可变的容器镜像
不可变的主机操作系统
atomic
由redHat支持的软件包系统
-
多种distro
redora
centOS
RHEL
-
优势
-
不可变操作系统,面向容器化的基础设施
灵活性和安全性较好
只有/etc/ /var/可以修改,其他目录均为只读
-
基于rpm-ostree管理系统包
Rpm-ostree是一个开源项目,使得生产系统中构建镜像非常简单
支持操作系统升级和回滚的原子操作
-
最小华操作系统
原则
最小化主机操作系统
-
只安装必要的工具
必要:支持系统运行的最小工具集
任何调试工具,比如性能排查,网络排查工具,均可以后期以容器的形式运行
-
意义
性能
稳定性
安全保证
Ostree
提供一个共享库和一些列命令行,提供和git命令行一致的体验,可以提交或是下载一个完整的可启动的文件系统树,提供将ostree部署到bootloader的机制
-
构建ostree
-
Rpm-ostree
基于treefile将rpm包构建成ostree管理ostree和bootloader配置
-
treefile
Refer: 分支名(版本,CPU架构)
Repo: rmp package repositories
Packages: 待安装的组件
-
-
加载ostree
初始化项目
导入ostree repo
拉取ostree
部署os
操作系统加载
-
物理机
通过foreman启动,foreman通过pxe boot,并加载kickstart
Kickstart 通过ostree deploy完成操作系统的部署
-
虚拟机
- 通过镜像工具将ostree构建成 qcow2格式,vhd,raw等格式
节点资源管理
状态汇报
资源预留
防止节点资源耗尽的防御机制
容器和系统资源的配置
状态上报
kubelet周期调度周期性向API Server进行汇报,更新节点的相关信息
节点基础信息,包括IP地址,操作系统,内核,kubelet kube-proxy版本信息
节点资源信息包括CPU,内存,HugePage,临时存储,GPU注册信息,以及这些资源中可以分配给容器使用的部分
调度器在Pod选节点的时候会将这些信息作为参考依据
lease
通过lease对象来保存健康信息,在默认的40s的nodeLeaseDurationSeconds周期呢,如果lease对象没有被更新,则对应的节点被判定为不健康
资源预留
计算节点除了用户容器外,还有很多支撑系统运行的基础服务,为了保证服务进程可以正常运行,在确保他们任务任何时候都可以获取足够的资源,需要对这些进程预留资源
kubele可以通过众多启动参数为系统服务预留出CPU,内存,PID等资源,比如:SystemReserved,KubeReserved等
Capacity 和Allocatable
-
Capacity:是说kubelet获取的计算节点当前的资源信息
Cpu: /proc/cpuinfo
Memory: /proc/memoryinfo
Ephemeral-storage:是说节点根分区的大小
Allocatable:用户Pod可用的资源,是资源容量减去分配给系统的资源剩余价值部分
节点磁盘管理
-
系统分区:nodes
- 工作目录和容器日志
-
容器运行时分区:imagefs
用户镜像和容器可写层
容器运行时分区是可选的,可以合并到系统分区中。
驱逐管理
kubelet会在系统资源不够的时候中止一些容器进程,以空出系统资源,保证节点的稳定性
-
kubelet发起的驱逐只是停止pod的所有容器进程,并不会直接删除pod
pod的status.phase会被标记为Failed
Status.reason:会被标记为evicted
Status:message会被记录为被标记为驱逐的原因
资源可用额的监控
Kubelet 依赖内嵌的开源软件cAdvisor,周期性检查节点资源的使用情况
CPU是可压缩资源,根据不同的进程分配时间配额和权重,CPU可以被多个进程竞争相使用
驱逐策略是基于磁盘和内存的资源使用量进行的,因为两者属不可压缩的资源,当此类资源使用耗尽的时候将无法在使用
检查类型 | 说明 |
---|---|
Memory.available | 节点当前的可用内存说明 |
Nodefs.available | 节点根分区的可用磁盘大小 |
nodefs.inodesFree | 节点根分区的可使用的inode |
Images.inodesFree | 节点运行时分区的可使用inode |
Images.available | 节点运行时饿分区的可使用大小,如果节点没有运行时分区,就没有想过监控 |
驱逐策略
Kubelet获得节点的可用额信息后,会结合节点的容量信息来判断当前节点运行的Pod是否满足驱逐条件。
驱逐条件可以是绝对值或是百分比,当监控资源的可使用额度少于设定的百分比的时候,kubelet就会发起驱逐操作
kubelet参数evictionMinimumReclaim可以设置每次回收的资源的最小值,以防止小资源多次被回收
kubelet参数 | 分类 | 驱逐方式 |
---|---|---|
evictionSoft | 软驱逐 | 当检测到当前资源达到软驱逐的阈值的时候,并不会立刻启动驱逐哦操作,而是要等待一个宽限期,这个宽限期选取evictionSoftGracePeriod和Pod指定的TerminationGracePeriodSeconds中较小的值 |
evictionHard | 硬驱逐 | 没有宽限期,一旦检测到满足硬件驱逐的条件,就直接终止容器来释放紧张的资源 |
基于内存压力的驱逐
Memory.avaiable表示当前系统的内存可用情况
kubelet默认了设置了memory.avaiable < 100Mi的硬件驱逐条件
当kubelet检测到当前节点可用内存资源紧张并满足驱逐条件的时候,会将节点的MemoryPressure的状态设置为True,调度器会阻止BestEffort Pod调度到内存承压的节点上
-
Kubelet启动对内存不足的驱逐操作的时候,会依照如下顺序选取目标pod
判断Pod所有容器的内存使用量总和是否超过请求的内存量,超出请求资源的Pod会成为备选目标
查询pod的调度优先级,低优先级的Pod会被优先驱逐
计算Pod所有容器的内存使用量和pod请求的内存量的差值,差值越小,越不容易被驱逐。
基于磁盘压力的驱逐
以下任何一项满足驱逐条件时,它会将节点的DiskPressure的状态设置为true,调度器不会在调度任何Pod到节点上
Nodefs.available:可用空间
Nodes.inodesFree : inode可用空间
imagefs.available
imagefs.inodesFree
驱逐行为
-
有容器运行时分区
Nodefs 达到驱逐阈值,那么kubelet删除已经退出的容器
Imagesfs达到驱逐阈值,那么kubelet删除所有未使用的镜像
-
无容器运行时分区
- kubelet同时删除未运行的容器和未使用镜像。
-
回收已经退出的容器以及未使用的容器后,如果节点依然满足驱逐条件,kubelet就会开始驱逐正在运行的Pod,进一步释放磁盘空间
判断pod的磁盘使用量是否超过了请求的大小,超过请求资源的pod会成为备选目标
查询pod的调度优先级,低优先级的pody优先被驱逐
根据磁盘使用超过请求的数量进行排序,差值越小,越不容易被驱逐。
容器资源配置
针对不同的Qos class的pod,kubenetes按照如下Hierarchy组织cgroup的cpu子系统
-
/sys/fs/cgroup/cpu
-
Kubepods.slice
-
Kubepods-besteffort.slice
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
Kubepods-burstable.slice
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
Cpu 的cgroup的配置
Cgroup | 参数 | Qos类型 | 值 |
---|---|---|---|
容器cgroup | Cpu.shares | bestEffort | 2 |
Burstable | Requests.cpu *1024 | ||
Guaranteed | Requests.cpu *1024 | ||
Cpu.cfs_quota_us | bestEffort | -1 | |
Burstable | Limit.cpu*100 | ||
Guaranteed | Limit.cpu*100 | ||
pod的Group | Cpu.shares | bestEffort | 2 |
Burstable | pod中容器的合集 | ||
Guaranteed | pod中容器的合集 | ||
Cpu.cfs.quota_us | bestEffort | -1 | |
Burstable | pod中容器的合集 | ||
Guaranteed | pod中容器的合集 |
针对不同的Qos class的pod,kubenetes按照如下Hierarchy组织cgroup的memory子系统
-
/sys/fs/cgroup/memory
-
Kubepods.slice
-
Kubepods-besteffort.slice
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
Kubepods-burstable.slice
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
Kubepods-pod
.slice docker
.scope docker
.scope
-
-
类型 | 参数 | Qos类型 | 值 | |
---|---|---|---|---|
容器的group | Memory.limit_in_bytes | bestEffort | 9223372036854771712 | |
Burstable | Limits.memory | |||
Guaranteed | Limits.memory | |||
pod的cgroup | Memory.limit_in_bytes | bestEffort | 9223372036854771712 | |
Burstable | pod中容器的合集 | |||
Guaranteed | pod中容器的合集 |
日志管理
节点上需要通过运行logrotate的定时任务对系统服务日志进行rotate清理,以防止系统日志占用大量磁盘空间。
同时配置日志的rotate条件,在日志不占用太多空间的情况下,保证有足够的日志可供查看
-
docker
除了基于系统logrotate管理日志,还可以依赖Docker自带的日志管理功能来设置日志的数量和每个日志的大小
Docker写入数据之前会对日志大小进行检查和rotate操作,确保日志文件不会超过配置的数量和大小
-
Containerd
日志的管理的通过kubelet定期执行du命令,来检查容器的日志数量和文件大小
每个容器日志的大小和保留的文件个数,可以通过kubelet的配置参数container-log-max-szie 和container-log-max-files进行调整。
Docker卷管理
在构建容器镜像的时候,可以在dockerFile中通过volume指令申明一个存储卷,目前kubernetes尚未将其纳入管控范围内,不建议使用
如果容器进程在可写层或是emptyDir卷进行大量读写操作,会推高磁盘i/o,从而导致其他其他容器有问题
Docker和Containerd运行时都基于CGROUPV1,对于块设备,只支持Direct I/O 的限速 而对于Buffer I/O 还不具备有效的支持,因此,针对设备限速问题,目前没有比较好的方案,对于有特殊 I/O需求的容器,建议使用独立的磁盘空间。
网络资源
由网络插件通过linux Traffic Control为Pod限制带宽,可以利用CNI社区提供的bandwith插件
进程数
kubelet默认不限制pode可以创建的子进程数,但是可以通过启动参数的podPidsLimit开启限制,还可以由reserved参数为系统进程预留进程数。
Kubelet通过系统调用的周期性的获得当前系统的PID使用情况,并读取/proc/sys/kernel/pid_max 获取系统支持pid的上限。
如果当前的可用进程数少于设定的阈值,那么kubelet会将节点对象的PIDPressure标记为true
Kube-scheduler在进行调度的时候,会从备选节点中对处于NodeUnderPIDPressure状态的节点进行过滤。
节点异常检测
kubernetes集群可能存在以下的问题
基础架构守护进程的问题:NTP服务关闭等
硬件问题:CPU,磁盘损坏
内核问题:内核死锁,文件系统损坏
容器运行时问题:运行时无响应
Node-problem-detector
为了解决节点检测的问题,社区引入了守护进程node-problem-detector,从各个守护进程收集节点问题,并使它们对上游层可见。
kubernetes节点诊断的工具,可以将节点的异常进行上报
runtime无反应
Linux kernel 无反应
网络异常
文件描述符异常
硬件问题比如CPU,内存,磁盘问题
Problem daemon types | nodeCondition | Description | Configs |
---|---|---|---|
系统日志监控 | KernelDeadLock,ReadOnlyFileSystem FrequentKubeletRestart FrequentDockerRestart FrequentContainerRestart | 通过系统监控日志来汇报问题并输出系统指标 | Filelog,kmsg, kernel abre systemd |
customPluginsMonitor | 按需定义 | 自定义插件监控运行用户自定义监控脚本 | 比如NTP服务 |
healthCheck | KubeletUnhealthy ContainerRuntimeUnhealthy | 针对kubelet和运行时的健康检查 | kubelet docker |
问题汇报手段
Node-proble-detector通过nodeCondition或者创建event对象来汇报问题
nodeCondition:针对永久性故障,会通过nodeCondition来改变节点状态
Event:临时故障通过event来提醒相关对象
安装过程
代码: https://github.com/kubernetes/node-problem-detector
-
安装:
Helm repo add deliveryhero https://charts.deliveryhero.io/
Helm install delivery hero/node-proble-detetor
常用节点问题排查手段
查看日志
针对使用systemd拉起服务
- Journalctl aft kubelet -S "2019-08-26 15:00:00" -u unit. // 对应的systemd拉起的组件,比如kubelet -f follow //跟踪最新的日志 -a show all // 显示所有的日志列 -S since // 从某一个时刻的日志
对于标准的容器日志
kubectl logs -f -c
kubectl logs -f --all-containers
kubectl logs -f -c
--previous Kubectl exec -it xxx --tail -f /path/to/log
基于extended resources 扩展节点资源
扩展资源时kubernetes.io域名之外的标准资源名称,它们使得集群管理员能够颁布非kubernetes内置资源,而用户可以使用他们
自定义扩展资源无法使用kubernetes.io作为资源域名。
管理扩展资源
-
节点级扩展资源
- 节点级扩展资源绑定到节点
-
设备插管管理的资源
- 发布到各节点上由设备插件所管理的资源,比如GPU,智能网卡
为节点配置资源
集群操作员可以向API服务器提交PATCH HTTP请求,以在集群中节点的status.capacity中为其配置可用数量
完成此操作后,节点的status.capacity字段中将包含新的资源
kubelet会异步的对status.allocatable字段执行自动更新操作,使之包含新的资源。
调度器在评估Pod是否在适合在某个节点上执行时会使用节点的status.allocatable值,在更新节点容量使之包含新资源之后和请求该资源的第一个pod被调度到该节点之间,可能会有段短暂的延迟
使用扩展资源
构建和管理高可用集群
高可用数据中心
多地部署
每个数据中心需要划分成具有独立供电,制冷,网络设备的高可用区
每个高可用区管理独立的硬件资产,包括机架,计算节点,存储,负载均衡,防火墙等硬件设备
Node的生命周期管理
运营kubernetes集群,除了搭建外,还需要对所有节点的生命周期负责
集群搭建
集群扩容/缩容
-
Node生命周期
-
Onboard
物理资产上架
操作系统安装
网络配置
kubernetes组件安装
创建Node对象
-
故障处理
临时故障:重启
永久故障:节点下架
-
Offboard
删除Node对象
物理资产下架
-
生产化集群管理
-
如何设定单个集群的规模
- 单一集群可支持达到5000节点
-
如何根据地域划分集群
不同地域的计算节点划分到同一个集群
将同一地域节点划分到同一集群
-
如何规划集群网络
企业办公环境,测试环境,预发环境,生产环境如何进行网络分离
不同租户之间如何进行网络隔离
-
如何自动化搭建集群
如何自动化搭建和升级集群,包括自动化部署控制面板和数据平面的核心组件
如何同企业公关服务集成
企业公共服务
需要同企业认证平台集成
集成企业的域名服务,负载均衡,提供集群服务对外的发布和访问入口
对于不能异步的请求,需要设置超时时间
有些失败是短暂的,可以增加重试机制
控制平面高可用
针对大规模的集群,应该为控制平面组件划分单独的节点,减少业务容器对控制平面或事守护进程的干扰和资源抢占
控制平面的所在节点,应该确保是在不同的机架上,防止某些硬件问题,导致所有的节点不可用。
保证控制平面每个组件有足够的CPU,内存和磁盘资源,过于严格的资源限制会导致系统效率低下
应该尽可能的将控制平面和数据平面解耦,确保控制平台组件故障的时候,将业务影响降到最低
高可用集群
集群安装方法
安装工具 | 方式 | 优势 | 缺点 |
---|---|---|---|
二进制 | 下载二进制文件,并通过设置systemd来管理 | 灵活度高 | 需要关心每一个组件 |
Kubeadm | kubeadm是一个搭建集群的命令行的工具 | 控制版面组件的安装和配置被封装起来,管理集群的生命后期,比如升级,证书管理 | 操作系统层面的配置无自动化运行时安装等复杂步骤的,CNI插件需要手动安装 |
Kubespray | 通过sensible-playbook安装 | 自动完成操作系统层面的配置,利用了kubeadm作为集群管理工具 | 缺少声明式API的支持 |
KOPS | 基于声明式API的集群管理工具 | 基于社区标准的clusterAPI进行集群管理,节点的操作系统安装等完全自动化 | 同云环境高度集成,灵活性差 |
kubespray 搭建高可用集群
基于声明式API管理集群
集群管理部只是包括集群搭建,还需要支持以下功能
集群扩缩容
节点健康检查和自动修复
操作系统升级
kubernetes升级
kubernetes cluster api
参与角色
-
管理集群
- 管理workload集群的集群,用来存放Cluster API对象的地方
-
Workload集群
- 真正开放给用户来运行应用的集群,由管理集群管理
-
Infrastructure provider
- 提供不同的云的基础架构管理,包括计算节点,网络等,目前流行的公有云多同cluster API集成
-
Bootstrap provider
证书生成
控制板面组件安装和初始化,监控节点的创建
将主节点和计算节点加入集群
-
Control plane
- kubernetes控制平面组件
涉及模型
-
machine
计算节点,用来描述可以运行的kubernetes组件的机器对象
一个新的machine被创建后,对应的控制器会创建一个计算节点,安装好操作系统并更新machine状态
当一个machine被删除后,对应的控制器会创建一个计算节点,安装好操作系统并更新machine的状态
当一个machine属性更新以后,对应的控制器会删除旧节点并创建新的节点
-
machine immutability
- 不可变基础架构
-
machineDeployment
- 提供针对machine和machineSet声明式更新,类似于kubernetes deployment
-
machineSet
- 维护一个稳定机器合集
-
machineHealthCheck
- 定义节点应该被标记为不可用的状态
Cluster Autoscaler
工作机制
-
扩容
- 由于资源不足,pod调度失败
-
缩容
node资源利用率较低,持续10分钟低于50%
此node上存在的pod都能被重新调度到其他node上运行
cluster autoscaler 架构
架构
Autoscaler: 核心模块,负责整体的扩缩容
Estimator: 负责评估计算扩容的节点
Simulator: 负责模拟调度,计算缩容节点
Cloud-provider:同云交互进行节点的增删改查,每个支持CA的主流厂商都实现自己的plugin实现动态缩放
扩展机制
为了自动创建和初始化Node,Cluster Autoscaler要求node必须属于某个node group
当集群中有多个node group时,可以通过 --expander=
Random: 随机选择
Most-pods:选择容量大的
Least-waste:以最小浪费原则,即选择有最少的可用资源的node group
多租户集群管理
租户
租户是指一组拥有访问特定软件资源权限的用户合集,在多租户的环境中,它还包括共享的应用,服务,数据和各项配置
多租户集群必须架构租户彼此隔离,以最大限度的减少租户和租户,租户和集群之间的影响
集群需要在租户之间公平的分配集群资源,通过多租户共享集群资源,有效降低集群管理成本,提高集群资源利用率。
隔离
-
权限隔离:
- 普通用户的容器默认不具备priviledged sys_admin net_admin等高级管理权限,以阻止对宿主机以及其他用户的容器进行读取,写入操作
-
网络隔离
- 不同的pod,运行在不同的network namespace中,拥有独立的网络协议栈,pod之间只能通过容器开放的端口进行通信,不能通过其他方式进行访问
-
数据隔离
- 容器之间利用namespace进行隔离
隔离手段
Namespace:Namespace属于且仅属于一个租户
权限定义:定义内容包括命令空间中的Role和RoleBinding。这些资源表示目前租户在归属于自己的民命空间中定义了什么权限,以及授权给了哪些用户
权限隔离
-
基于namespace的权限隔离
创建一个namespace-admin clusterRole,拥有所有对象的所有权限
为用户开辟新的namespace,并在该namespace创建rolebingding绑定namespace-admin clusterRole,用户即可拥有当前的namespace所有的操作权限
-
自动化解决方案
当namespace创立的时候,通过mutatingwebhook的方式将namespace变形,将用户信息记录到namespace annotation中
创建一个控制器 监控namespace创建rolebinding 为该用户绑定namespace-admin权限
节点资源隔离
通过为节点设置不同的taint来识别不同的租户的计算资源