1.基于CEL的Admission Control简单回顾
1.1 Admission Control简单回顾
在说明基于CEL的Admission Control之前,我们首先来简单回顾下Admission Control。
如上图,我们向Kubernetes发送一个请求,该请求从开始被 kube-apiserver 接收到最终持久化到 ETCD 的过程,即为 Kubernetes API 的请求处理流程。其中开头的API Handler可以看成一个WebServices,而Authentication和Authorization则为认证/鉴权,这两个就不展开描述。重点在于后面的Mutating和Validating Admission。
什么是准入控制器?准入控制器是指在请求通过认证和授权之后,可用于对其进行变更操作或验证操作的一些代码或功能。准入控制的过程分为两个阶段:
• 第一阶段,运行变更准入控制器(Mutating Admission)。它可以修改被它接受的对象,将相关资源作为请求处理的一部分进行变更; • 第二阶段,运行验证准入控制器(Validating Admission)。它只能进行验证,不能进行任何资源数据的修改操作;
而为什么我们需要需要准入控制器?主要的原因如下:
• 安全控制,我们可以限制Deployment只拉取指定域名的相关镜像,或者禁止开启特权容器。
• 功能处理,比如cert-manager的一些注入功能与证书处理等,依赖于Admission Control来实现。
• 资源治理,比如自动修改或者限制资源配额限制,以免出现资源超卖等情况。
1.2 基于CEL的Admission Control
Kubernetes在v1.26新增了一个特性,允许使用CEL(Common Expression Language)来进行Admission Control,在此之前我们在使用Admission Control时,都是通过配置Mutating/ValidatingWebhookConfiguration, Service, Deployment来实现一个相应的Admission Control,总体来看复杂且不稳定。而Kubernetes这个新特性相比于传统的Admission Control要简单灵活许多,可以接管一些简单的小校验和小修改。
在这里,我们需要配置的是ValidatingAdmissionPolicy和ValidatingAdmissionPolicyBinding,在v1.30版本正式提供。
比如,我们要实现一个简单的限制,控制replicas不能超过3个:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: minimum-replicas-requirement
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 3 "
message: "Deployment的副本数不能超过3个"
reason: Invalid
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: maximum-replicas-requirement-binding
spec:
policyName: maximum-replicas-requirement
validationActions: ["Deny"]
matchResources:
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values: ["kube-system"]
只需要创建这两个Kubernetes资源,便可以进行自定义的资源控制,不需要我们再去编写程序来控制了。
2.Pod调度就绪机制
2.1 Pod调度流程的简单回顾
首先我们来对Pod的调度过程进行一下简单的回顾,这里我们假设使用的是常见的Deployment来对Pod进行管理。
1. 创建 Deployment 请求
- kubectl 命令: 当你运行
kubectl apply -f <filename>.yaml
时,kubectl 读取 YAML 文件中的内容,将其转化为一个HTTP请求,并向Kubernetes API服务器发送创建或更新资源的请求。
2. API 服务器处理请求
- 验证和存储: API服务器接收请求后,会首先对其进行验证,确保YAML文件中的字段符合Kubernetes的规范。然后,将该Deployment对象存储在etcd中,etcd是一种高可用的分布式键值存储系统。
3. 控制器管理器工作
- 触发控制器: Deployment控制器监视Deployment对象的变化。当检测到新Deployment创建时,它会根据Deployment的模板参数创建ReplicaSet对象。
- 创建 ReplicaSet: ReplicaSet是由Deployment创建和管理的,它定义了应该运行多少个Pod副本。
4. ReplicaSet 同步
- 管理 Pod 副本: ReplicaSet控制器检测到新的ReplicaSet之后,会通过Pod模板生成并创建指定数量的Pod对象(如配置要求3个副本,则创建3个Pod对象)。
5. 调度 Pods
- 调度器工作: 每个Pod对象创建后,调度器会介入,它负责决定Pod应该运行在哪个节点上。调度器根据节点的资源状态、Pod的调度约束(如亲和性和反亲和性规则)、Taints和Tolerations以及其他策略进行决策。
6. Kubelet 启动 Pods
- Kubelet 负责: 调度器一旦为Pod分配了节点,目标节点上的kubelet会监视到有新的Pod需要启动。kubelet根据PodSpec从容器镜像仓库拉取镜像,并启动相应的容器。
- 健康检查: kubelet负责定期对运行中的容器进行健康检查,并重新启动不健康的容器。
7. Pod 就绪
- 初始化和就绪探针: Pod启动后,kubelet继续运行就绪探针(Readiness Probe)来检查Pod是否已经准备好对外服务。只有通过这些探针的检查,Pod的状态才会被标记为Ready。
- 更新状态: 当Pod处于就绪状态时,kubelet更新Pod的状态,API服务器记录这些更新,集群中的其他组件可以基于这些更新做出相应调整。
2.2 Pod调度就绪要解决的问题
通过上面的过程,我们可以注意到一个问题,在Pod创建成功后,其实就默认该Pod是可以被调度了,kube-scheduler就应该开始工作了。但是在很多场景中,Pod还需要其他资源,比如存储之类的,一些云厂商还需要检查用户的账户情况等等。还有如果Pod没有调度成功,那么调度器会每隔一段时间重新调度一次,而这种调度失败的Pod还有可能会影响一些下游组件(Cluster Autoscaler)除此之外,部分编排开发人员以及调度开发人员,需要灵活的对Pod进行自定义的调度控制,因此,Pod Scheduling Readiness便可以较好的解决这些问题。
2.3 Pod调度就绪的使用
使用Pod调度就绪很简单,只需要在Pod Spec SchedulingGates指定好name就行。
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
schedulingGates:
- name: volume.info/disk
containers:
- name: pause
image: pause:latest
在schedulingGates中可以指定多个name,但是需要注意唯一性。将上述的Pod配置应用到集群中后,会看到:
NAME READY STATUS RESTARTS AGE
test-pod 0/1 SchedulingGated 0 17s
而当我们移除掉SchedulingGates时,Pod便可以重新调度了。
3.HPA基于Container Resource Autoscaling
HPA(Horizontal Pod Autoscaler)用于确保缩放的目标以特定的当前指标值维持在特定水平的方式进行扩大和缩小。参考:
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough
但是在这里,Pod资源使用量的计算是通过Pod的各个容器使用值的总和,这就导致一个问题,当Pod中有多个容器时,它们各自资源的使用量可能并没有关系,比如常见的sidecar模式,当业务主容器的资源使用量大幅度增加后,可能sidecar容器并没有什么波动,这就导致了整个服务并没有按照我们的预期进行扩缩容。因此,Kubernetes推出了ContainerResource来帮助我们解决这个问题。
我们可以通过创建对应的HPA资源yaml,来配置container级别的Metrics:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: sre
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 3
metrics:
- type: ContainerResource
containerResource:
name: cpu
container: php-apache
target:
type: Utilization
averageUtilization: 60
这样便可以给单独的Container来配置HPA的Metrics。