[TOC]
描述: 说过kubernetes
架构中介绍到 k8s Master
由三个组件组成, 分别是API Server、Controller Manager 与 Scheduler
图示1.k8s架构图示
WeiyiGeek.k8s架构
Q:什么是节点?
答:Kubernetes中节点(node)指的是一个工作机器曾经叫做 minion , 但是需要注意不同的集群中,节点可能是虚拟机也可能是物理机。
每个节点都由 master 组件
管理,并包含了运行 Pod(容器组)所需的服务包括:容器引擎 / kubelet / kube-proxy
节点的状态包含如下信息:
Conditions:节点的状态正常的如下面的节点信息,实际在文件中是以JSON对象的形式存在;
Ready #如果节点是健康的且已经就绪可以接受新的 Pod。则节点Ready字段为 True。False表明了该节点不健康不能够接受新的 Pod。
OutOfDisk #如果节点上的空白磁盘空间不够,不能够再添加新的节点时,该字段为 True 其他情况为 False
MemoryPressure #如果节点内存紧张,则该字段为 True,否则为False
PIDPressure #如果节点上进程过多,则该字段为 True,否则为 False
DiskPressure #如果节点磁盘空间紧张,则该字段为 True,否则为 False
NetworkUnvailable #如果节点的网络配置有问题,则该字段为 True,否则为 False
Addresses
#ExternalIP:通常是节点的外部IP(可以从集群外访问的内网IP地址此字段为空)
#InternalIP:通常是从节点内部可以访问的 IP 地址
Capacity and Allocatable : 描述了节点上的可用资源的情况即CPU,内存,该节点可调度的最大 pod 数量
Info : 描述了节点的基本信息该信息以信息由节点上的 kubelet 收集。
* Linux 内核版本
* Kubernetes 版本(kubelet 和 kube-proxy 的版本)
* Docker 版本
* 操作系统名称
Q:如何查看节点状态?
#查看所有节点的列表
$kubectl get nodes -o wide
#查看节点状态以及节点的其他详细信息
kubectl describe node <your-node-name>
$kubectl describe node node-1
Name: node-1 #节点名称
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=node-1
kubernetes.io/os=linux
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
projectcalico.org/IPv4Address: 10.20.172.82/24 #IPaddress
projectcalico.org/IPv4IPIPTunnelAddr: 10.100.84.128 #Tunnel IP
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Tue, 16 Jun 2020 15:15:11 +0800 #加入时间
Taints: <none>
Unschedulable: false
Lease:
HolderIdentity: node-1
AcquireTime: <unset>
RenewTime: Wed, 17 Jun 2020 00:01:37 +0800
# (1) 描述了节点的状态
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
NetworkUnavailable False Tue, 16 Jun 2020 23:17:13 +0800 Tue, 16 Jun 2020 23:17:13 +0800 CalicoIsUp Calico is running on this node
MemoryPressure False Tue, 16 Jun 2020 23:57:26 +0800 Tue, 16 Jun 2020 23:15:44 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Tue, 16 Jun 2020 23:57:26 +0800 Tue, 16 Jun 2020 23:15:44 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Tue, 16 Jun 2020 23:57:26 +0800 Tue, 16 Jun 2020 23:15:44 +0800 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Tue, 16 Jun 2020 23:57:26 +0800 Tue, 16 Jun 2020 23:16:35 +0800 KubeletReady kubelet is posting ready status
# (2) 依据你集群部署的方式(在哪个云供应商部署,或是在物理机上部署),Addesses 字段可能有所不同。
Addresses:
# 内部IP
InternalIP: 10.20.172.82
# 节点主机名称,启动 kubelet 时可以通过参数 --hostname-override 覆盖
Hostname: node-1
# (3) 容量描述了节点上的可用资源的情况
# Capacity 中的字段表示节点上的资源总数
Capacity:
cpu: 2
ephemeral-storage: 47285700Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 2037168Ki
pods: 110
# Allocatable 中的字段表示该节点上可分配给普通 Pod 的资源总数。
Allocatable:
cpu: 2
ephemeral-storage: 43578501048
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 1934768Ki
pods: 110
# 节点系统信息
System Info:
Machine ID: 6e65e151c0ef4248b78d6be0fb63eb58
System UUID: 564d504e-4027-b5c3-9c49-11f2de69bf26
Boot ID: 90c3795b-4823-41de-9893-ef6b89db9614
Kernel Version: 5.7.0-1.el7.elrepo.x86_64
OS Image: CentOS Linux 7 (Core)
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://19.3.9 #容器版本
Kubelet Version: v1.18.3 #kubernetes 版本
Kube-Proxy Version: v1.18.3
PodCIDR: 10.100.1.0/24 # Pod子网
PodCIDRs: 10.100.1.0/24
Non-terminated Pods: (2 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
kube-system calico-node-jp55x 250m (12%) 0 (0%) 0 (0%) 0 (0%) 46m #节点的Calicao网络
kube-system kube-proxy-kglgh 0 (0%) 0 (0%) 0 (0%) 0 (0%) 46m #节点的kube-proxy代理
Allocated resources: #分配资源 配置资源情况
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 250m (12%) 0 (0%)
memory 0 (0%) 0 (0%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Events: #事件信息
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Starting <invalid> kubelet, node-1 Starting kubelet.
Normal NodeHasSufficientMemory <invalid> (x2 over <invalid>) kubelet, node-1 Node node-1 status is now: NodeHasSufficientMemory
Normal NodeHasNoDiskPressure <invalid> (x2 over <invalid>) kubelet, node-1 Node node-1 status is now: NodeHasNoDiskPressure
Normal NodeHasSufficientPID <invalid> (x2 over <invalid>) kubelet, node-1 Node node-1 status is now: NodeHasSufficientPID
Normal NodeAllocatableEnforced <invalid> kubelet, node-1 Updated Node Allocatable limit across pods
Normal Starting <invalid> kube-proxy, node-1 Starting kube-proxy.
Normal NodeReady <invalid> kubelet, node-1 Node node-1 status is now: NodeReady
注意事项:
1) 如果 Ready 类型Condition 的 status 持续为 Unkown 或者 False
超过 pod-eviction-timeout(kube-controller-manager 的参数)所指定的时间(默认5分钟),节点控制器(node controller)将对该节点上的所有 Pod 执行删除的调度动作; 然而在某些特殊情况下(例如,节点网络故障)apiserver 不能够与节点上的 kubelet 通信导致删除 Pod 的指令不能下达到该节点的 kubelet 上
,直到 apiserver 与节点的通信重新建立指令才下达到节点, 意味着虽然对Pod执行了删除的调用指令, 但是这些Pod仍然在失联的节点上运行。
# 不同版本的解决方式
< kubernetes v1.5 : 节点控制器将从 apiserver 强制删除这些失联节点上的 Pod
>= kubernetes v1.5 : 节点控制器将不会强制删除这些 Pod,直到已经确认他们已经停止运行为止,此时发现失联节点上的Pod仍然是在运行的(在该节点上运行docker ps即可以看见容器的运行状态), 然而 apiserver 中他们的状态已经变为 Terminating 或者 Unknown;
== Kubernetes v1.12 : TaintNodesByCondition 特性利用node lifecycle controller 将自动创建该 Condition 对应的 污点。相应地调度器在选择合适的节点时,不再关注节点的 Condition而是检查节点的污点和 Pod 的容忍
# 手动解决方式: 如果 Kubernetes 不能通过 cloud-controller-manager 判断失联节点是否已经永久从集群中移除(例如,在虚拟机或物理机上自己部署 Kubernetes 的情况)
kubectl delete node your-node-name #删除 apiserver 中的节点对象, 此时Kubernetes 将删除该节点上的所有 Pod。
描述:前面我们说过Node(节点)可以是一台物理主机或者虚拟机的资源池再或者云供应商创建的,在向 Kubernetes 中创建节点时,仅仅是创建了一个描述该节点的 API 对象。 当节点 API 对象创建成功后,Kubernetes将检查该节点是否有效。
注意事项:
节点有效(节点组件正在运行)
,则可以向该节点调度 Pod
;否则该节点 API 对象将被忽略,直到节点变为有效状态。kubectl delete node my-first-k8s-node
命令删除该节点。#例如,假设您创建如下节点信息:
apiVersion: v1
kind: Node
metadata:
name: "10.240.79.157"
labels:
name: "my-first-k8s-node"
节点控制器(Node Controller)
描述:在节点的生命周期中,节点控制器起到了许多作用。节点控制器是一个负责管理节点的 Kubernetes master 组件
;
工作流程:
1.首先节点控制器在注册节点时为节点分配 CIDR 地址块
$kubectl describe node node-1
Addresses:
InternalIP: 10.20.172.82
projectcalico.org/IPv4Address: 10.20.172.82/24
projectcalico.org/IPv4IPIPTunnelAddr: 10.100.84.128
PodCIDR: 10.100.1.0/24
PodCIDRs: 10.100.1.0/24
2.第二,节点控制器通过(Kube-controller-manager)和云供应商(cloud-controller-manager)接口检查节点列表中每一个节点对象对应的虚拟机是否可用。
云环境
中只要节点状态异常,节点控制器检查其虚拟机在云供应商的状态,如果虚拟机不可用自动将节点对象从 APIServer 中删除
。本地局域网环境
中如果节点状态异常它会不断地检查该节点是否有效,并不会将点对象从 APIServer 中删除,除非您手动删除
;3.节点控制器监控节点的健康状况,每隔 --node-monitor-period
秒检查一次节点的状态;当节点变得不可触达时(例由于节点已停机,节点控制器不再收到来自节点的心跳信号
),默认40秒未收到心跳
,此时节点控制器将节点API对象的NodeStatus Condition
取值从 NodeReady
更新为 Unknown
;然后在等待 pod-eviction-timeout
为 5分钟 时间后,将节点上的所有 Pod 从节点驱逐。
# (1) NodeStatus(< V1.13) 和 node lease(>= V1.13)都被用来记录节点的心跳信号。
- 1.1) NodeStatus 的更新频率远高于 node lease ,因为是每次节点向 master 发出心跳信号NodeStatus 都将被更新, 只有在 NodeStatus 发生改变,或者足够长的时间未接收到 NodeStatus 更新时,节点控制器才更新 node lease(默认为1分钟,比节点失联的超时时间40秒要更长)
- 1.2) 由于 node lease 比 NodeStatus 更轻量级,该特性显著提高了节点心跳机制的效率,并使 Kubernetes 性能和可伸缩性得到了提升;
- 1.3) 在v1.4 中优化了节点控制器的逻辑以便更好的处理大量节点不能触达 master 的情况;主要的优化点在于节点控制器在决定是否执行 Pod 驱逐的动作时,会检查集群中所有节点的状态。默认情况下节点控制器限制了驱逐 Pod 的速率为 `--node-eviction-rate (默认值是0.1)每秒`即每10s驱逐一个Pod;
- 1.4) 当节点所在的高可用区出现故障时,节点控制器驱逐 Pod 的方式将不一样;
节点自注册(Self-Registration)
描述:如果 kubelet 的启动参数 --register-node
为 true(默认为 true),kubelet 会尝试将自己注册到 API Server。
kubelet自行注册时,将使用如下选项:
<key>=<value>:<effect>
)如果 Node authorization mode 和 NodeRestriction admission plugin 被启用,kubelet 只拥有创建/修改其自身所对应的节点 API 对象的权限。
手动管理节点
描述:集群管理员可以创建和修改节点API对象。
如果管理员想要手工创建节点API对象,可以将 kubelet 的启动参数 --register-node 设置为 false
,管理员可以修改节点API对象不管是否设置了该参数。
可以修改的内容有:增加/减少标签,标记节点为不可调度(unschedulable)
节点的标签与 Pod 上的节点选择器(node selector)配合可以控制调度方式,例如限定 Pod 只能在某一组节点上运行(后面会进行讲解);
执行如下命令可将节点标记为不可调度(unschedulable),此时将阻止新的 Pod 被调度到该节点上,但是不影响任何已经在该节点上运行的 Pod。
# 重启节点一直有效
$ kubectl cordon $NODENAME
$ kubectl cordon node-1
node/node-1 cordoned
Tips: DaemonSet Controller
创建的 Pod 将绕过 Kubernetes 调度器,并且忽略节点的 unschedulable 属性。因为我们假设 Daemons 守护进程属于节点,尽管该节点在准备重启前,已经排空了上面所有的应用程序。
节点容量(Node Capacity) 描述:节点API对象中描述了节点的容量(Capacity),例如,CPU数量、内存大小等信息。通常,节点在向 APIServer 注册的同时,在节点API对象里汇报了其容量(Capacity)。
手动管理节点
,您需要在添加节点时自己设置节点
的容量。具体来说调度器检查节点上所有容器的资源请求之和不大于节点的容量
。此时只能检查由 kubelet 启动的容器,不包括直接由容器引擎启动的容器,更不包括不在容器里运行的进程。
Q: 什么是控制器? A:在机器人技术和自动化技术中,控制循环是一个控制系统状态的无限循环。比如房间里的恒温器就是控制循环的一个应用例子;
在 Kubernetes 中控制器就是上面所说的 控制循环,它不断监控着集群的状态,并对集群做出对应的变更调整。每一个控制器都不断地尝试着将 当前状态 调整到 目标状态。作为一个底层设计原则Kubernetes使用了大量的控制器,每个控制器都用来管理集群状态的某一个方面。普遍来说任何一个特定的控制器都使用一种 API 对象作为其目标状态,并使用和管理多种类型的资源,以达到目标状态。使用许多个简单的控制器比使用一个全能的控制器要更加有优势。控制器可能会出故障,而这也是在设计 Kubernetes 时要考虑到的事情。
控制器模式 描述:在K8S中每个控制器至少追踪一种类型的资源,在资源对象中有一个 spec 字段代表了目标状态,资源对象对应的控制器负责不断地将当前状态调整到目标状态。
理论上控制器可以自己直接执行调整动作,实际上控制器发送消息到 API Server 而不是直接自己执行调整动作。
Job 是一种 Kubernetes API 对象,一个 Job 将运行一个(或多个)Pod,执行一项任务,然后停止。当新的 Job 对象被创建时,Job Controller 将确保集群中有合适数量的节点上的 kubelet 启动了指定个数的 Pod,以完成 Job 的执行任务。Job Controller 自己并不执行任何 Pod 或容器,而是发消息给 API Server,由其他的控制组件配合 API Server,以执行创建或删除 Pod 的实际动作。
当新的 Job 对象被创建时,目标状态是指定的任务被执行完成。Job Controller 调整集群的当前状态以达到目标状态:创建 Pod 以执行 Job 中指定的任务, 控制器同样也会更新其关注的 API 对象。
例如:一旦 Job 的任务执行结束,Job Controller 将更新 Job 的 API 对象,将其标注为 Finished。(这有点儿像是恒温器将指示灯关闭,以表示房间里的温度已经到达指定温度。)
例如:您想用一个控制器确保集群中有足够的节点,此时控制器需要调用云供应商的接口以创建新的节点或移除旧的节点。这类控制器将从 API Server 中读取关于目标状态的信息,并直接调用外部接口以实现调整目标。
描述:我们知道 Kubernetes集群和Master节点(实际上是API Server)之间的通信路径;
Master-Node 之间的通信可以分为如下两类:
--kubelet-certificate-authority
参数为 apiserver 提供校验 kubelet 证书的根证书。如果不能完成这个配置,又需要通过不受信网络或公网将节点加入集群,则需要使用 SSH隧道 连接 apiserver 和 kubelet。同时,Kubelet authentication/authorization需要激活,以保护 kubelet APSSH隧道当前已被不推荐使用(deprecated),Kubernetes 正在设计新的替代通信方式
。Tips: 高可用区出现故障时节点控制器驱逐Pod,将检查高可用区里故障节点的百分比(NodeReady Condition 的值为 Unknown 或 False
);
--unhealthy-zone-threshold(默认为 0.55)
则降低驱逐 Pod 的速率;--large-cluster-size-threshold
个节点,默认值为 50),则停止驱逐 Pod;--large-cluster-size-threshold
个节点,则驱逐 Pod 的速率降低到 --secondary-node-eviction-rate
(默认值为 0.01)每秒;针对每个高可用区使用这个策略的原因是,某一个高可用区可能与 master 隔开了,而其他高可用区仍然保持连接。如果您的集群并未分布在云供应商的多个高可用区上,此时,您只有一个高可用区(即整个集群)。
将集群的节点分布到多个高可用区最大的原因是,在某个高可用区出现整体故障时,可以将工作负载迁移到仍然健康的高可用区。因此,如果某个高可用区的所有节点都出现故障时,节点控制器仍然使用正常的驱逐 Pod 的速率(–node-eviction-rate)。
最极端的情况是,所有的高可用区都完全不可用(例如,集群中一个健康的节点都没有),此时节点控制器 master 节点的网络连接出现故障,并停止所有的驱逐 Pod 的动作,直到某些连接得到恢复。
简单的集群配置文件:
vim kubeadm-config.yaml
apiServer:
certSANs:
- k8s-master-01
- k8s-master-02
- k8s-master-03
- master.k8s.io
- 192.168.9.80
- 192.168.9.81
- 192.168.9.82
- 192.168.9.83
- 127.0.0.1
extraArgs:
authorization-mode: Node,RBAC
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta1
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: "master.k8s.io:16443"
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.16.3
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.1.0.0/16
scheduler: {}
1) 创建 流程步骤:
API SERVER
与Scheduler联系,将该Pod绑定在指定的Node节点之上;WeiyiGeek.Pod创建时序图
2) 删除
WeiyiGeek.Pod删除时序图
描述: K8S API Server 简称Kubernetes Master
是k8s最重要的核心组件之一负责集群内各个模块的通信。其通过kube-apiserver的进程提供服务,它提供了k8s各类资源对象(Pod/RC/Server)等的增删改查以及Watch等HTTP Rest
接口,它是整个系统的数据总线和数据中心;
原理: 集群中各个功能模块通过API Server将信息存入etcd之中,当需要获取这些信息时则通过API Server提供的REST接口实现, 从而实现各个组件之间的交互; 即API Server本身是无状态服务,通过将资源数据存储到etcd中,后续业务则是由Sheduler与Controller-manager进行执行;
高可用: K8s Api Server
服务高可用可以同时起多个K8S API Server服务,通过使用负载均衡器(Nginx / HAProxy)把客户端的流量转发到不同的后端ApiServer从而实现接入层的高可用;
API Server 功能:
在kubernetes API Server的主要功能有提供了集群管理的REST API 接口(包括认证授权、数据校验及集群状态变更)
和提供其它模块之间的数据交互和通信枢纽(只有API Server才能直接操作etcd数据库)、资源配额控制的入口、拥有完备的集群安全机制;
API Server 应用场景:
API Server 工作原理图:
描述: Kube-ApiServer 提供了K8s的REST API实现了认证、授权、准入
等安全校验功能,同时负责集群状态的存储(ETCD)操作;
WeiyiGeek.API-Server工作原理图
Tips : 分成四个部分一是API、二是访问控制、三是Registry(Pod Namespace Services)
、四是Etcd Cluster
集群
Api Server 与 集群三大组件通信介绍:
API Server
的REST接口报告自身状态,API Server 收到信息后会将节点状态存储在etcd
数据库之中,另外 kubelet 还会调用API Server 的Watch接口监听Pod信息,正对于Pod增删改查分别执行相应逻辑;kube-scheduler
其通过API Server的Watch接口,监听到新创建Pod请求后会根据设定的策略执行相应的调度逻辑,最后成功将Pod绑定在目标节点之上; Tips: 各个功能模块都会定期从API Server获取指定的资源对象然后通过LIST 或者 Watch
采用缓存来缓存数据到本地之中,然后通过访问缓存的方式来减少对Api Server
访问的压力;
API-Server 启动参数:
kube-apiserver
- --advertise-address=192.168.12.107
- --allow-privileged=true
- --authorization-mode=Node,RBAC # 这就是前面所说的鉴权方式
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --insecure-port=0
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
描述: Kube-apiserver 同时支持提供https(默认监听在6443端口)以及http(默认监听127.0.0.1的8080端口),其中后者是非安全接口,不做任何认证授权机制生产环境中不建议启用,注意两个接口REST API 格式一致;
Q: 如果查询API调用格式?
$ kubectl -v 8 get pod
# I0228 06:39:04.991697 3929980 loader.go:375] Config loaded from file: /home/weiyigeek/.kube/config
# I0228 06:39:04.996106 3929980 round_trippers.go:421] GET https://weiyigeek-lb-vip.k8s:16443/api/v1/namespaces/default/pods?limit=500
# I0228 06:39:04.996128 3929980 round_trippers.go:428] Request Headers:
# I0228 06:39:04.996147 3929980 round_trippers.go:432] Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json
# I0228 06:39:04.996159 3929980 round_trippers.go:432] User-Agent: kubectl/v1.19.6 (linux/amd64) kubernetes/fbf646b
# I0228 06:39:05.008580 3929980 round_trippers.go:447] Response Status: 200 OK in 12 milliseconds
# I0228 06:39:05.008598 3929980 round_trippers.go:450] Response Headers:
# I0228 06:39:05.008604 3929980 round_trippers.go:453] Cache-Control: no-cache, private
# I0228 06:39:05.008609 3929980 round_trippers.go:453] Content-Type: application/json
# I0228 06:39:05.008619 3929980 round_trippers.go:453] Date: Sun, 28 Feb 2021 06:39:05 GMT
# I0228 06:39:05.008806 3929980 request.go:1097] Response Body: {"kind":"Table","apiVersion":"meta.k8s.io/v1","metadata":{"selfLink":"/api/v1/namespaces/default/pods","resourceVersion":"12507375"},"columnDefinitions":[{"name":"Name","type":"string","format":"name","description":"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names","priority":0},{"name":"Ready","type":"string","format":"","description":"The aggregate readiness state of this pod for accepting traffic.","priority":0},{"name":"Status","type":"string","format":"","description":"The aggregate status of the containers in this pod.","priority":0},{"name":"Restarts","type":"integer","format":"","description":"The number of times the containers in this pod have been restarted.","priority":0},{"name":"Age","type":"string", [truncated 7667 chars]
Swagger && Swagger-UI
描述: 通过/swagger.json
查看OpenAPI;
操作流程:
# 开启代理
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
# 通过`/swagger.json`查看OpenAPI
curl http://127.0.0.1:8001/swagger.json
{
"paths": [
"/apis",
"/apis/",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1",
"/apis/apiextensions.k8s.io/v1beta1",
"/healthz",
"/healthz/etcd",
"/healthz/log",
"/healthz/ping",
"/healthz/poststarthook/crd-informer-synced",
"/healthz/poststarthook/generic-apiserver-start-informers",
"/healthz/poststarthook/max-in-flight-filter",
"/healthz/poststarthook/start-apiextensions-controllers",
"/healthz/poststarthook/start-apiextensions-informers",
"/livez",
"/livez/etcd",
"/livez/log",
"/livez/ping",
"/livez/poststarthook/crd-informer-synced",
"/livez/poststarthook/generic-apiserver-start-informers",
"/livez/poststarthook/max-in-flight-filter",
"/livez/poststarthook/start-apiextensions-controllers",
"/livez/poststarthook/start-apiextensions-informers",
"/metrics",
"/openapi/v2",
"/readyz",
"/readyz/etcd",
"/readyz/informer-sync",
"/readyz/log",
"/readyz/ping",
"/readyz/poststarthook/crd-informer-synced",
"/readyz/poststarthook/generic-apiserver-start-informers",
"/readyz/poststarthook/max-in-flight-filter",
"/readyz/poststarthook/start-apiextensions-controllers",
"/readyz/poststarthook/start-apiextensions-informers",
"/readyz/shutdown",
"/version"
]
}c
# 查看所有OpenAPI接口
~$ curl http://127.0.0.1:8001
{
"paths": [
"/api",
"/api/v1",
"/apis",
"/apis/",
"/apis/admissionregistration.k8s.io",
"/apis/admissionregistration.k8s.io/v1",
"/apis/admissionregistration.k8s.io/v1beta1",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1",
"/apis/apiextensions.k8s.io/v1beta1",
"/apis/apiregistration.k8s.io",
"/apis/apiregistration.k8s.io/v1",
"/apis/apiregistration.k8s.io/v1beta1",
"/apis/apps",
"/apis/apps/v1",
"/apis/authentication.k8s.io",
"/apis/authentication.k8s.io/v1",
"/apis/authentication.k8s.io/v1beta1",
"/apis/authorization.k8s.io",
"/apis/authorization.k8s.io/v1",
"/apis/authorization.k8s.io/v1beta1",
"/apis/autoscaling",
"/apis/autoscaling/v1",
"/apis/autoscaling/v2beta1",
"/apis/autoscaling/v2beta2",
"/apis/batch",
"/apis/batch/v1",
"/apis/batch/v1beta1",
"/apis/certificates.k8s.io",
"/apis/certificates.k8s.io/v1",
"/apis/certificates.k8s.io/v1beta1",
"/apis/coordination.k8s.io",
"/apis/coordination.k8s.io/v1",
"/apis/coordination.k8s.io/v1beta1",
"/apis/discovery.k8s.io",
"/apis/discovery.k8s.io/v1beta1",
"/apis/events.k8s.io",
"/apis/events.k8s.io/v1",
"/apis/events.k8s.io/v1beta1",
"/apis/extensions",
"/apis/extensions/v1beta1",
"/apis/networking.k8s.io",
"/apis/networking.k8s.io/v1",
"/apis/networking.k8s.io/v1beta1",
"/apis/node.k8s.io",
"/apis/node.k8s.io/v1beta1",
"/apis/policy",
"/apis/policy/v1beta1",
"/apis/rbac.authorization.k8s.io",
"/apis/rbac.authorization.k8s.io/v1",
"/apis/rbac.authorization.k8s.io/v1beta1",
"/apis/redis.kun",
"/apis/redis.kun/v1alpha1",
"/apis/scheduling.k8s.io",
"/apis/scheduling.k8s.io/v1",
"/apis/scheduling.k8s.io/v1beta1",
"/apis/storage.k8s.io",
"/apis/storage.k8s.io/v1",
"/apis/storage.k8s.io/v1beta1",
"/healthz",
"/healthz/autoregister-completion",
"/healthz/etcd",
"/healthz/log",
"/healthz/ping",
"/healthz/poststarthook/aggregator-reload-proxy-client-cert",
"/healthz/poststarthook/apiservice-openapi-controller",
"/healthz/poststarthook/apiservice-registration-controller",
"/healthz/poststarthook/apiservice-status-available-controller",
"/healthz/poststarthook/bootstrap-controller",
"/healthz/poststarthook/crd-informer-synced",
"/healthz/poststarthook/generic-apiserver-start-informers",
"/healthz/poststarthook/kube-apiserver-autoregistration",
"/healthz/poststarthook/max-in-flight-filter",
"/healthz/poststarthook/rbac/bootstrap-roles",
"/healthz/poststarthook/scheduling/bootstrap-system-priority-classes",
"/healthz/poststarthook/start-apiextensions-controllers",
"/healthz/poststarthook/start-apiextensions-informers",
"/healthz/poststarthook/start-cluster-authentication-info-controller",
"/healthz/poststarthook/start-kube-aggregator-informers",
"/healthz/poststarthook/start-kube-apiserver-admission-initializer",
"/livez",
"/livez/autoregister-completion",
"/livez/etcd",
"/livez/log",
"/livez/ping",
"/livez/poststarthook/aggregator-reload-proxy-client-cert",
"/livez/poststarthook/apiservice-openapi-controller",
"/livez/poststarthook/apiservice-registration-controller",
"/livez/poststarthook/apiservice-status-available-controller",
"/livez/poststarthook/bootstrap-controller",
"/livez/poststarthook/crd-informer-synced",
"/livez/poststarthook/generic-apiserver-start-informers",
"/livez/poststarthook/kube-apiserver-autoregistration",
"/livez/poststarthook/max-in-flight-filter",
"/livez/poststarthook/rbac/bootstrap-roles",
"/livez/poststarthook/scheduling/bootstrap-system-priority-classes",
"/livez/poststarthook/start-apiextensions-controllers",
"/livez/poststarthook/start-apiextensions-informers",
"/livez/poststarthook/start-cluster-authentication-info-controller",
"/livez/poststarthook/start-kube-aggregator-informers",
"/livez/poststarthook/start-kube-apiserver-admission-initializer",
"/logs",
"/metrics",
"/openapi/v2",
"/readyz",
"/readyz/autoregister-completion",
"/readyz/etcd",
"/readyz/informer-sync",
"/readyz/log",
"/readyz/ping",
"/readyz/poststarthook/aggregator-reload-proxy-client-cert",
"/readyz/poststarthook/apiservice-openapi-controller",
"/readyz/poststarthook/apiservice-registration-controller",
"/readyz/poststarthook/apiservice-status-available-controller",
"/readyz/poststarthook/bootstrap-controller",
"/readyz/poststarthook/crd-informer-synced",
"/readyz/poststarthook/generic-apiserver-start-informers",
"/readyz/poststarthook/kube-apiserver-autoregistration",
"/readyz/poststarthook/max-in-flight-filter",
"/readyz/poststarthook/rbac/bootstrap-roles",
"/readyz/poststarthook/scheduling/bootstrap-system-priority-classes",
"/readyz/poststarthook/start-apiextensions-controllers",
"/readyz/poststarthook/start-apiextensions-informers",
"/readyz/poststarthook/start-cluster-authentication-info-controller",
"/readyz/poststarthook/start-kube-aggregator-informers",
"/readyz/poststarthook/start-kube-apiserver-admission-initializer",
"/readyz/shutdown",
"/version"
]
}
# 例如查看当前api-server版本
$ curl http://127.0.0.1:8001/version
{
"major": "1",
"minor": "19",
"gitVersion": "v1.19.6",
"gitCommit": "fbf646b339dc52336b55d8ec85c181981b86331a",
"gitTreeState": "clean",
"buildDate": "2020-12-18T12:01:36Z",
"goVersion": "go1.15.5",
"compiler": "gc",
"platform": "linux/amd64"
}
如果想保留部分的 REST API 可以通过加入 --reject-paths="^/api/v1/pods",如果想限制非法的客户端访问则采用--accept-host="^127\\.0\\.0\\.1
# (1) 在拒绝前
~$ curl -si http://127.0.0.1:8001/api/v1/pods | more
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: application/json
Date: Sun, 28 Feb 2021 07:02:56 GMT
Vary: Accept-Encoding
Transfer-Encoding: chunked
# (2) 添加资源访问限制
~$ kubectl proxy --reject-paths="^/api/v1/pods" --accept-hosts="^127\\.0\\.0\\.1$,^\\[::1\\]$" --port 8888 -v 2
Starting to serve on 127.0.0.1:8888
# (3) 在拒绝后其拒绝访问pod相关信息
~$ curl -si http://127.0.0.1:8888/api/v1/pods | more
HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Sun, 28 Feb 2021 07:07:20 GMT
Content-Length: 10
Forbidden
# (4) 访问非127.0.0.1地址由于没有本地192.168.12.107网卡监听则无任何回显
~$ curl -si http://192.168.12.107:8888/version | more
# (5) 查看 Api Server 目前所支持的资源对象种类
~$ curl -s http://127.0.0.1:8888/api/v1 | head -n 13
{
"kind": "APIResourceList",
"groupVersion": "v1",
"resources": [
{
"name": "bindings",
"singularName": "",
"namespaced": true,
"kind": "Binding",
"verbs": [
"create"
]
},
......
# (5) 查看 Api Server 目前所支持的资源对象种类
~$ curl -s http://127.0.0.1:8888/api/v1/pods # Pod 相关信息
~$ curl -s http://127.0.0.1:8888/api/v1/servics # Service 相关信息
~$ curl -s http://127.0.0.1:8888/api/v1/deployments # deployments 部署相关信息
下面我们可以通过访问Swagger-UI接口
查看REST API接口
,但是首先需要配置启用swagger-ui具有操作流程如下:
# (1) 通过开启-enable-swagger-ui=true还可以通过/swagger-ui访问Swagger UI
# (2) 修改 `/etc/kubernetes/manifests/kube-apiserver.yaml`中启动参数如下之后重新生成静态Pod
# - --insecure-port=0
- --enable-swagger-ui=true
- --insecure-bind-address=0.0.0.0
- --insecure-port=30999
# (3) 发现kube-apiserver已经重启了
/etc/kubernetes/manifests$ kubectl get pod -n kube-system -o wide | grep "kube-apiserver-weiyigeek-107"
kube-apiserver-weiyigeek-107 1/1 Running 0 87s 192.168.12.107 weiyigeek-107
# (4) 访问http://192.168.12.107:30999 与 /swagger-ui 查看你效果
$ curl -si http://127.0.0.1:30999 # 与上面的OPENAPI 返回一致
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Content-Type: application/json
Date: Sun, 28 Feb 2021 08:24:07 GMT
Transfer-Encoding: chunked
描述: Controller Manager 作为集群的管理控制中心(大脑),负责整个集群内的Node、Pod Replica、Endpoint、Namespace、ServiceAccout以及ResourceQuota; 它通过API Server监控整个集群状态,并确保集群处于预期的工作状态;
Controller-Manager 分类由一系列的控制器组成:
而云Controller-Manager用来配合云服务提供商的控制,也包括一系列的控制器如:
描述: 优良的调度是分布式系统的核心,承载着整个集群的调度功能,其根据特定的调度算法和策略,将Pod调度到最优工作节点之上,从而更合理与更充分的利用集群计算资源,使得资源更好的服务于业务服务的需求;
Tips : Scheduler 是一个调度器, 普通用户可以将其理解为一个黑盒(里面是待调度的Pod和全部计算节点的信息
),经过黑盒内部的调度算法和策略处理输出为最优的节点,而后将Pod调度在该节点之上;
Q: 上述过程看似简单但在实际的生产环境的调度过程中,由很多问题需要进行考虑;
Tips: 用户可以自定义调度器并以插件的形式与Kubernetes集成或集成其他调度器,便于调度不同类型的任务。
K8s调度器的源码位于kubernetes/plugin
中而创建和运行的过程对应的代码在plugin/pkg/scheduler/scheduler.go
。其大体的代码目录结构如下所示:
kubernetes/plugin/pkg/
`-- scheduler //调度相关的具体实现
|-- algorithm
| |-- predicates //节点筛选策略
| `-- priorities //节点打分策略
| `-- util
|-- algorithmprovider
| `-- defaults //定义默认的调度器
上面初步介绍了Kubernetes调度器。具体的说,调度器是Kubernetes容器集群管理系统中加载并运行的调度程序,负责收集、统计分析容器集群管理系统中所有Node的资源使用情况,然后以此为依据将新建的Pod发送到优先级最高的可用Node上去建立。
Kubernetes调度器使用Predicates和Priorites来决定一个Pod应该运行在哪一个节点上, 即调度分为以下几个部分:
注意: 如果中间任何一步骤有错误,就直接返回错误。
Tips : 如果在预选(Predicates)过程中,如果所有的节点都不满足条件,Pod 会一直处在Pending 状态
,直到有节点满足条件,这期间调度器会不断的重试。经过节点过滤后,如多个节点满足条件,会按照节点优先级(priorities)
大小对节点排序,最后选择优先级最高的节点部署Pod。
具体的调度过程:
API Server
的REST API/kubectl/helm
创建pod/service/deployment/job
等,支持类型主要为JSON/YAML/helm tgz。
Predicates是用来形容主机匹配Pod所需要的资源,如果没有任何主机满足该Predicates,则该Pod会被挂起,直到有节点
预选(Predicates)与优选(Priorites)的策略罗列如下:
预选(Predicates)
优选(Priorites): Kubernetes用一组优先级函数处理每一个通过预选的节点,每一个优先级函数会返回一个0-10的分数,分数越高表示节点越优, 同时每一个函数也会对应一个表示权重的值 finalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + … + (weightn * priorityFuncn)
1.LeastRequestedPriority: 节点的优先级就由节点空闲资源与节点总容量的比值,即由(总容量-节点上Pod的容量总和-新Pod的容量)/总容量)来决定。即CPU和内存具有相同权重,资源空闲比越高的节点得分越高。
cpu((capacity – sum(requested)) * 10 / capacity) + memory((capacity – sum(requested)) * 10 / capacity) / 2
# 例如CPU的可用资源为100,运行容器申请的资源为15,则cpu分值为8.5分,内存可用资源为100,运行容器申请资源为20,则内存分支为8分。则此评价规则在此节点的分数为(8.5 +8) / 2 = 8.25分。
2.BalancedResourceAllocation : CPU和内存使用率越接近的节点权重越高,该策略不能单独使用,必须和LeastRequestedPriority
组合使用,尽量选择在部署Pod后各项资源更均衡的机器。
3.InterPodAffinityPriority : 通过迭代 weightedPodAffinityTerm 的元素计算和,并且如果对该节点满足相应的PodAffinityTerm,则将 “weight” 加到和中,具有最高和的节点是最优选的。
4.SelectorSpreadPriority:为了更好的容灾,对同属于一个service、replication controller或者replica的多个Pod副本,尽量调度到多个不同的节点上。
5.NodeAffinityPriority:Kubernetes调度中的亲和性机制。
6.NodePreferAvoidPodsPriority(权重1W):如果 节点的 Anotation 没有设置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods = "."
,则节点对该 policy 的得分就是10分,加上权重10000,那么该node对该policy的得分至少10W分
7.TaintTolerationPriority : 使用 Pod 中 tolerationList 与 节点 Taint 进行匹配,配对成功的项越多,则得分越低。
8.ImageLocalityPriority: 根据Node上是否存在一个pod的容器运行所需镜像大小对优先级打分,分值为0-10。
9.EqualPriority : EqualPriority 是一个优先级函数,它给予所有节点相等权重。
10.MostRequestedPriority : 在 ClusterAutoscalerProvider 中,替换 LeastRequestedPriority,给使用多资源的节点,更高的优先级
(cpu(10 sum(requested) / capacity) + memory(10 sum(requested) / capacity)) / 2
最后会把表格中按照节点把优先级函数的权重列表相加,得到最终节点的分值。上面代码就是这个过程,中间过程可以并发计算(下文图中的workQueue)以加快速度。
… | node1 | node2 | … | Noden |
---|---|---|---|---|
PriorityFunc1 | S(1,1) | S(1,2) | … | S(1,N) |
PriorityFunc2 | S(2,1) | S(1,2) | … | S(2,N) |
… | … | … | … | … |
PriorityFuncM | S(2,1) | S(1,2) | … | S(2,N) |
Result | Score1 | Score2 | … | ScoreN |
自定义调度 描述: 我们可以根据实际环境进行相应的调整,方便用户对调度的定制与二次开发。
方式1.定制预选
和优选
策略
我们可以在kube-schduler启动时加入–policy-config-file参数可以指定调度策略文件,例如用户可以根据需要进行组装Predicates和Priority函数
,即可以选择不同的过滤含税和优先级函数,控制优先级含税的权限,调整过滤函数的顺序都会影响调度过程。
"kind" : "Policy",
"apiVersion" : "v1",
"predicates" : [
{"name" : "PodFitsHostPorts"},
{"name" : "PodFitsResources"},
{"name" : "NoDiskConflict"},
{"name" : "NoVolumeZoneConflict"},
{"name" : "MatchNodeSelector"},
{"name" : "HostName"}
],
"priorities" : [
{"name" : "LeastRequestedPriority", "weight" : 1},
{"name" : "BalancedResourceAllocation", "weight" : 1},
{"name" : "ServiceSpreadingPriority", "weight" : 1},
{"name" : "EqualPriority", "weight" : 1}
],
"hardPodAffinitySymmetricWeight" : 10
方式2.自定义Priority和Predicate: 即Kubernetes还允许用户编写自己的Priority 和 Predicate函数,而并非上面的方式一是对已有的调度模块进行组合。
# 过滤函数的接口:
// FitPredicate is a function that indicates if a pod fits into an existing node.
// The failure information is given by the error.
type FitPredicate func(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (bool, []PredicateFailureReason, error)
plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go
完成,可以参考其他过滤函数(例如PodFitsHostPorts)的注册代码:kubernetes/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.gofactory.RegisterFitPredicate("PodFitsPorts", predicates.PodFitsHostPorts)
。方式3.编写自己的调度器: Kubernetes也允许用户编写自己的调度器组件,并在创建资源的时候引用它。多个调度器可以同时运行和工作,只要名字不冲突。 描述: 使用某个调度器就是在Pod的spec.schedulername字段中填写上调度器的名字。Kubernetes提供的调度器名字是default,如果自定义的调度器名字是my-scheduler,那么只有当spec.schedulername字段是my-scheduler才会被调度。
简单调度脚本:
#!/bin/bash
SERVER='localhost:8001'
while true;
do
for PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName == "my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"')
;
do
NODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"'))
NUMNODES=${#NODES[@]}
CHOSEN=${NODES[$[ $RANDOM % $NUMNODES ]]}
curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1", "kind": "Binding", "metadata": {"name": "'$PODNAME'"}, "target": {"apiVersion": "v1", "kind"
: "Node", "name": "'$CHOSEN'"}}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/
echo "Assigned $PODNAME to $CHOSEN"
done
sleep 1
done
$ kubectl get nodes -o json | jq '.items[].metadata.name' | tr -d '"'
weiyigeek-107
weiyigeek-108
weiyigeek-109
weiyigeek-223
weiyigeek-224
weiyigeek-225
weiyigeek-226
脚本解释: 它通过kubectl命令从apiserver获取未调度的Pod(spec.schedulerName 是my-scheduler,并且spec.nodeName 为空
),同样地,用kubectl从apiserver获取nodes的信息,然后随机选择一个node作为调度结果,并写入到apiserver中。我们可通过kubectl describe pod pod_name
查看一个Pod采用的调度器;
Tips: 当然要想编写一个生产级别的调度器,要完善的东西还很多比如:
调度器总结:
描述: 没有什么事情是完美的,调度器也一样,用户可结合实际业务服务特性和需求,利用或定制Kubernetes调度策略,更好满足业务服务的需求。
描述: 什么是QoS? 即: Quality Of Service 服务质量;
描述: Kubernetes 对 资源的限制实际上是通过 cgroup 来控制的,cgroup是容器的一组用来控制内核如何运行进程的相关属性集合,针对内存、CPU 和network、存储以及各种设备都有对应的 cgroup。
默认情况下,Pod运行没有CPU和内存的限额,意味着系统中的任何Pod将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU和内存。在生产环境中一般会针对某些特定应用的 pod 资源进行资源限制,常常资源限制是通过resources的 requests 和 limits
来实现;
Tips: Requests 申请的范围是0到Node节点的最大配置(0<= request<=NodeAllocatable
) ,而Limit申请范围是Request到无限(Request<=limit<=Infinity
)
Kuberneters 资源限制可以针对以下对象:
Tips :ResourceQuota / LimitRange
- 在名称空间那节讲述过
QoS 分类 描述: Kubelet 提供QoS服务质量管理,支持系统级别的OOM控制.在K8s中Pod的QoS级别Guaranteed(保证)、Burstable(瓶颈)、Best-Effort(尽力而为)
Tips :如果一个容器只指明Limit而未设定Request则其值为Limit的值
基础示例
示例1.对于Pod资源的请求(requests)与限制(limits)
,可以简单理解为初始值和最大值
spec:
containers:
- image: nginx:latest
imagePullPolicy: Always
name: auth
ports:
- containerPort: 8080
protocol: TCP
resources: # 关键点
limits: # limits 为最高请求的资源值
cpu: "4"
memory: 2Gi
requests: # requests 要分分配的资源
cpu: 250m
memory: 250Mi
示例2.对于名称空间的资源限制
# (1) 计算资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: spark-cluster
spec:
hard:
pods: "20"
requests.cpu: "20"
requests.memory: 100Gi
limits.cpu: "40"
limits.memory: 200Gi
# (2) 配置对象数量配额限制
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: spark-cluster
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
# (3) 配置 CPU和内存 LimitRange
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default: # default 即 limit 的值
memory: 50Gi
cpu: 5
defaultRequest: # defaultRequest 即 request 的值
memory: 1Gi
cpu: 1
type: Container
描述: k8s将资源压缩分为两类,一类是可压缩资源,另外一类是不可压缩资源。
CPU资源
当Pod容器超过设置的Limit值, Pod中进程使用CPU会被限制但不会被Kill;内存资源
与磁盘资源
当资源不足时其会先Kill掉优先级较低的Pod。上面的方式在实际使用过程中是通过OOM分数值来实现的 OOM 分数值从 0-1000 区间范围之内, 其分值是根据OOM_ADJ参数计算得出;
Tips :对于K8s的保留资源比如Kubelet、docker其OOM_ADJ参数设置为-999 (表示永远不会被Kill
)
Tips : 对于OOM_ADJ参数来说如果其越大则计算出的OOM分数越高,则表明该Pod优先级就越低当出现资源竞争时就会被越早Kill;
QoS优先级: 从低到高的有 BestEffort < Burstable < Guranteed
Pod
Tips : 如果Pod进程因使用超过预先设定的Limit而非Node资源紧张,系统一般倾向于其原所在的机器上重启该Container或者本机以及其它节点上创建一个Pod。
QoS 使用建议 描述: 如果资源充足或者想更好的提高资源利用率可以将QoS Pods类型设置为Guarantee用计算资源换业务性能和稳定性、减少排查问题时间和成本。而其它服务根据重要程度可分别设置为Burstable或BestEffort,例如 Filebeat 业务;