Kubernetes v1.22

Kubernetes v1.22 已经在今天正式发布了,这是 2021 年的第二个正式发布的版本。此版本中共包含 53 项增强更新,其中 13 项达到 stable,24 项达到 beta 还有 16 项为 alpha。当然,也有 3 项特性被标记为废弃。

从今年的 4 月份,Kubernetes 的发布节奏由原来的每 3 个月一个版本修改成了每 4 个月一个版本,这也是第一个应用了此节奏的长周期版本。

Server-side Apply 特性达到 GA

Server-side Apply 这个特性主要目标是把逻辑从 kubectl apply 移动到 kube-apiserver 中,这可以修复当前遇到的很多有关所有权冲突的问题。

Server-side Apply 当前是通过 Kubernetes 新增的 .meta.managedFields 属性来跟踪对象字段的更改的。

同时此特性的好处在于你可以直接通过 API 完成声明式配置的操作,而无需依赖于特定的 kubectl apply 命令,比如直接通过 curl 即可完成。

此功能的用法如下:

1
kubectl apply --server-side [--dry-run=server]

Pod Security Policy 的替代品

PodSecurity admission controller 是在 Kubernets v1.21 中被废弃的 Pod Security Policies 的替代品。

这个 admission controller 可以按 namespace 级别启用 Pod Security Standards ,可以有以下三种模式:

  • enforce: 违反策略的 Pod 将被拒绝;
  • audit:违反策略的 Pod 将会添加审计注释,但其他情况下都允许;
  • warn:违反策略的 Pod 将会触发面向用户的警告;

可通过如下配置文件进行控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
defaults: # Defaults applied when a mode label is not set.
enforce: <default enforce policy level>
enforce-version: <default enforce policy version>
audit: <default audit policy level>
audit-version: <default audit policy version>
warn: <default warn policy level>
warn-version: <default warn policy version>
exemptions:
usernames: [ <array of authenticated usernames to exempt> ]
runtimeClassNames: [ <array of runtime class names to exempt> ]
namespaces: [ <array of namespaces to exempt> ]

Node swap 支持

此特性现在是 Alpha 阶段。

虽然 swap 并不够快,但是现在有很多场景都是需要用到它的,尤其是一些 Java 和 Node 应用。

在 Kubernetes 的 issue 列表中有一个存在了 5 年左右的讨论,就是针对于能否开启 swap 支持的。当前这个特性一旦开启就是针对于整个 Node 的,并不能精确到某个 Pod 中。

你可以通过如下步骤启用此特性:

  • 在 Node 中启用 swap;
  • 开启 kubelet 的 NodeMemorySwap 特性;
  • 设置 --fail-on-swap=false
  • 可选在 Kubelet 的配置中增加 MemorySwap.SwapBehavior=UnlimitedSwap

更多内容可参考:https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2400-node-swap

外部客户端凭证提供工具

这个功能允许 client-go 使用外部工具进行身份验证,比如 LDAP、Kerberos、OAuth2、SAML 等。这个特性是从 v1.10 开始引入的。

使用此特性的话,需要你在 kubeconfig 配置文件中作为 user 字段下的字段进行配置。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Config
users:
- name: my-user
user:
exec:
command: "example-client-go-exec-plugin"
apiVersion: "client.authentication.k8s.io/v1beta1"

env:
- name: "FOO"
value: "bar"

args:
- "arg1"
- "arg2"

provideClusterInfo: true
clusters:
...

user.exec字段下配置可用的 client-go-exec plugin 即可。现在也有一个示例项目可供参考 https://github.com/ankeesler/sample-exec-plugin

可索引的 Job API

在 Kubernetes v1.21 中新增的可索引 Job API 可以更加方便的调度并行化的 Job。现在可以使用如下的方式通过环境变量让 Job 中的 Pod 知道自己的索引:

1
2
3
4
5
6
7
[...]
spec:
subdomain: my-job-svc
containers:
- name: task
image: registry.example.com/processing-image
command: ["./process", "--index", "$JOB_COMPLETION_INDEX", "--hosts-pattern", "my-job-{{.id}}.my-job-svc"]

为 Job API 增加 suspend 字段

自 v1.21 起,Job 可以通过设置 .spec.suspend=true 字段来临时的挂起。可以比较方便的去进行控制,类似 Argo workflow 中,也可以对某个 workflow 进行挂起操作。

CSR 的有效期

通过在 CertificateSigningRequestSpec 中增加的 ExpirationSeconds 可以接受的最小值是 600(10分钟),这样就可以很好的控制其有效期了。现在默认的是 1 年。

内存资源的 QoS

之前 Kubernetes 在使用 cgroups v1 ,对于 Pod 的 QoS 其实只适用于 CPU 资源。Kubernetes v1.22 中通过引入 cgroups v2 来提供了一个 alpha 特性,允许对内存资源也提供 QoS。(如果没记错,貌似是腾讯云团队提交的 KEP 吧)

当然,你也可以通过KIND 使用如下命令来快速的体验 Kubernetes v1.22 :

1
kind create cluster --image=kindest/node:v1.22.0@sha256:b8bda84bb3a190e6e028b1760d277454a72267a5454b57db34437c34a588d047

Kubernetes v1.23

Kubernetes v1.23 今天正式发布,这是 2021 年发布的第三个版本,也是 2021 年最后一个正式发布的版本。

此版本中主要包括 47 项增强更新,其中 11 项达到 stable, 17 项达到 beta 还有 19 项达到 alpha 。当然,也有 1 项被标记为废弃。相比于 v1.22 从数量上来说是少了一点(v1.22 有 53 项增强更新),但这并不影响这是一个很棒的版本!

在 Kubernetes 的发布周期变更为 每4个月一个版本 后,很明显的感觉就是不用在升级上面花费太多时间了,毕竟 Kubernetes 的升级操作是个体力活。

新增 kubectl alpha events 命令

《K8S 生态周报| Helm 新版本发布增强对 OCI 的支持》 文章的上游进展中曾介绍了该功能。它是按照 KEP #1440 实施的。

增加此命令主要是由于在不修改 kubectl get 的前提下,查看 event 有一些限制,所以直接增加 kubectl events 命令可以更方便的去获取到需要的信息,尤其是 event 是在 Kubernetes 中经常需要查看的一个信息。kubectl get events 比较典型的一些问题, 比如排序(虽然可以通过加参数解决), watch,以及无法按照时间线方式去查看 events 等。

来看看这个命令具体如何使用。

我们先来创建两个 Pod,分别叫 redisredis2

1
2
3
4
5
6
7
8
(MoeLove) ➜ kubectl run redis --image="ghcr.io/tao12345666333/redis:alpine" 
pod/redis created
(MoeLove) ➜ kubectl run redis2 --image="ghcr.io/tao12345666333/redis:alpine"
pod/redis2 created
(MoeLove) ➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 12m
redis2 1/1 Running 0 2m23s

执行 kubectl alpha events 可以看到当前 namespace 下的所有 events 。如果增加 --for 条件可以用来筛选只展示特定资源相关的 events 。同时 默认情况下就是按时间排序的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(MoeLove) ➜ kubectl  alpha events
LAST SEEN TYPE REASON OBJECT MESSAGE
12m Normal Scheduled Pod/redis Successfully assigned default/redis to kind-control-plane
12m Normal Pulling Pod/redis Pulling image "ghcr.io/tao12345666333/redis:alpine"
12m Normal Pulled Pod/redis Successfully pulled image "ghcr.io/tao12345666333/redis:alpine" in 4.028873745s
12m Normal Created Pod/redis Created container redis
12m Normal Started Pod/redis Started container redis
3m5s Normal Scheduled Pod/redis2 Successfully assigned default/redis2 to kind-control-plane
3m5s Normal Pulled Pod/redis2 Container image "ghcr.io/tao12345666333/redis:alpine" already present on machine
3m4s Normal Created Pod/redis2 Created container redis2
3m4s Normal Started Pod/redis2 Started container redis2
(MoeLove) ➜ kubectl alpha events --for pod/redis2
LAST SEEN TYPE REASON OBJECT MESSAGE
3m23s Normal Scheduled Pod/redis2 Successfully assigned default/redis2 to kind-control-plane
3m23s Normal Pulled Pod/redis2 Container image "ghcr.io/tao12345666333/redis:alpine" already present on machine
3m22s Normal Created Pod/redis2 Created container redis2
3m22s Normal Started Pod/redis2 Started container redis2

IPv4/IPv6 双栈支持达到 GA

在配置双栈网络的 Kubernetes 时,需要同时指定 --node-cidr-mask-size-ipv4--node-cidr-mask-size-ipv6 以便于设置每个 Node 上的子网大小。在此之前我们都是直接使用 --node-cidr-mask-size 进行设置即可。

如果我们仍然使用单栈 Kubernetes 集群的话,正常来说不需要做什么调整,当然我们也可以使用上面提到的选项,来单独设置集群的 IPv4/IPv6 子网。

PodSecurity Admission 达到 Beta

PodSecurity Admission 是之前的 PSP 的代替,关于 Kubernetes Admission 可以参考文章 《理清 Kubernetes 中 Admission 机制》

IngressClass 支持 namespace 级别的参数

IngressClass.Spec.Parameters.Namespace 字段当前达到 GA ,这样就可以为 IngressClass 设置参数为 namespace 级别了。比如:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: example.com/ingress-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
namespace: external-configuration
scope: Namespace

Probe 中增加 gRPC 协议的支持

通过 KEP #2727 ,在此版本中为 Pod.Spec.Container.{Liveness,Readiness,Startup} 的 Probe 添加了 gRPC 协议的支持。例如:

1
2
3
4
5
6
readinessProbe:
grpc:
port: 9090
service: moelove-service
initialDelaySeconds: 5
periodSeconds: 10

可通过 GRPCContainerProbe feature gate 开启此特性。具体细节可参考 #106463

新增 OpenAPI V3

这个特性是 Alpha 级别,可通过 OpenApiv3 feature gate 进行开启。

增加此特性主要是由于 CRD 目前可通过 OpenApi V3 进行定义,但是 api-server 目前还不支持。当从 OpenApi V3 转换为 V2 时,部分信息将会丢失。

更多详细信息可参考 KEP #2896

CRD Validation 表达式语言

这是一项 Alpha 级别的特性,默认是不开启的。可通过增加 CustomResourceValidationExpressions feature gate 来进行开启。单独介绍此 Alpha 级别的特性是因为目前基于 Custom Resource Definitions (CRDs) 的方式对 Kubernetes 进行扩展已经成为主流,但是在 CRD 中目前能添加的校验规则有限,更多的场景都需要通过额外的 Admission 来完成。

此功能使用一种叫做 Common Expression Language (CEL) 的语言进行规则定义,通过 x-kubernetes-validation-rules 字段进行规则的添加。

例如,某个 CRDs 的内容如下,其中定义了 minReplicas 小于 replicas 并且 replicas 小于 maxReplicas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-validation-rules:
- rule: "self.minReplicas <= self.replicas"
message: "replicas should be greater than or equal to minReplicas."
- rule: "self.replicas <= self.maxReplicas"
message: "replicas should be smaller than or equal to maxReplicas."
properties:
...
minReplicas:
type: integer
replicas:
type: integer
maxReplicas:
type: integer
required:
- minReplicas
- replicas
- maxReplicas

那么,当有如下的自定义资源创建时,Kubernetes 将会拒绝其请求。

1
2
3
4
5
6
7
8
apiVersion: "stable.example.com/v1"
kind: CustomDeployment
metadata:
name: my-new-deploy-object
spec:
minReplicas: 0
replicas: 20
maxReplicas: 10

并且返回如下错误:

1
2
The CustomDeployment "my-new-deploy-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: replicas should be smaller than or equal to maxReplicas.

这样相比原来我们通过 Admission 的方式来进行校验就会方便的多。关于 Kubernetes Admission 可以参考文章 《理清 Kubernetes 中 Admission 机制》

HPA v2 API 达到 GA

HPA v2 大约是在 5 年前首次提出,经过这 5 年的发展,终于在现在它达到了 GA 级别。

Kubernetes v1.24

各beta API默认关闭

在默认情况下,新的各beta API不会在集群内得到启用。但全部原有beta API及其新版本将在1.24中继续默认启用

OpenAPI v3

Kubernetes 1.24开始为API的OpenAPI v3发布格式提供beta支持。

存储容量与存储卷扩展双双迎来通用版本

存储容量跟踪通过CSIStorageCapacity对象公开当前可用的存储容量,并对使用后续绑定的CSI存储卷的pod进行调度增强。
存储卷扩展则新增对现有持久卷的重新调整功能。

NonPreemptingPriority迎来稳定版

此功能为PriorityClasses添加了新的选项,可开启或关闭Pod抢占机制

存储插件迁移

目前Kubernetes开发团队正在迁移树内存储插件,希望在实现CSI插件的同时、保持原有API的正常起效。Azure Disk与OpenStack Cinder等插件已经完成了迁移。

gRPC探针升级至beta版

在1.24版本中,gRPC探针功能已经进入beta阶段且默认启用。现在,大家可以在Kubernetes中为自己的gRPC应用程序原生配置启动、活动与就绪探测,而且无需公开HTTP商战或者使用额外的可执行文件。

Kubelet证书提供程序升级至beta版

最初在Kubernetes 1.20版本中以alpha版亮相的kubelet镜像证书提供程序现已升级至beta版。现在,kubelet将使用exec插件动态检索容器镜像注册表的凭证,而不再将凭证存储在节点文件系统之上。

避免为服务分配IP时发生冲突

Kubernetes 1.24引入了一项新的选择性功能,允许用户为服务的静态IP分配地址保留一个软范围。通过手动启用此项功能,集群将从您指定的服务IP池中自动获取地址,从而降低冲突风险。

也就是说,服务的ClusterIP能够以下列方式分配:
动态分配,即集群将在配置的服务IP范围内自动选择一个空闲IP。
静态分配,意味着用户需要在已配置的服务IP范围内指定一个IP。

服务ClusterIP是唯一的;因此若尝试使用已被分配的ClusterIP进行服务创建,则会返回错误结果。

Kubernetes v1.25

Kubernetes 正式发布了,包含了 40 项目增强更新。

本次 LOGO 的主要表达的意思是 尊重协作和开放的精神 ,这种精神将我们凝聚到一起转变为能改变世界的力量。

其实我每期的 「k8s生态周报」都有一个叫上游进展的部分,所以很多值得关注的内容在之前的文章中已经发过了。

这篇中我会再额外介绍一些之前未涵盖的,和之前介绍过的值得关注的内容。

core CSI Migration 达到 Stable

Kubernetes 对 CSI 的支持是自 v1.9 开始引入的,到 2019 年的 v1.13 时已经正式 GA 。最近几个版本中,社区正在将原本的 in-tree 插件逐步废弃或删除,并迁移至使用 CSI 驱动的方式。

迁移至使用 CSI 的好处在于,能提高可维护性,并减少因 in-tree 代码导致的漏洞或者错误的发生。

但是迁移也并不是直接替换,社区考虑到用户的迁移成本,于是提出了一种解决方案:CSI Migration ,这个方案是将 in-tree API 转换为等效 CSI API,并将操作委托给 CSI 驱动程序的功能。目前该功能达到 GA,in-tree 的迁移也有很多进展。

  • deprecate GlusterFS plugin from available in-tree drivers. by humblec · Pull Request #111485 · kubernetes/kubernetes

在这个 PR 中废弃了 in-tree 的 GlusterFS 的 plugin,这其实是最早的 dynamic provisioner ,自 Kubernetes v1.4 版本开始引入。

在后来 CSI 驱动出现的时候,社区中也立刻出现了对应的驱动实现 https://github.com/gluster/gluster-csi-driver/ ,只不过该项目并没有积极的进行维护。现在还有另一个比较推荐的替代方案,可以考虑使用 https://github.com/kadalu/kadalu/ 此项目最新的版本为 v0.8.15 。

经过社区之前的讨论,还是决定在 v1.25 版本开始将 in-tree 的 GlusterFS plugin 标记为废弃,并在后续的版本中进行移除。

如果有正在使用此插件的小伙伴,我建议可以尽早的评估 kadalu 的可行性 & 迁移成本。

  • cleanup: Remove storageos volume plugins from k8s codebase by Jiawei0227 · Pull Request #111620 · kubernetes/kubernetes
  • cleanup: Remove flocker volume plugins from k8s codebase by Jiawei0227 · Pull Request #111618 · kubernetes/kubernetes
  • cleanup: Remove quobyte volume plugins from k8s codebase by Jiawei0227 · Pull Request #111619 · kubernetes/kubernetes

上述的这几个 PR 所做的事情基本类似,是一些清理操作。将 Kubernetes 项目中 StorageOSFlockerQuobyte 等 in-tree 的卷插件都删除掉了。

其中 StorageOSQuobyte 如果有在使用,建议往 CSI plugin 进行迁移,而 Flocker 则是由于不再维护了,所以并没有任何迁移计划。

cgroup v2 支持达到 GA

在 2019 年 GitChat 对我的访谈中让我聊 2020 年的技术趋势,我当时的主要观点摘录如下:

作为云原生技术的基石,Kubernetes 在 2020 年的热度将会持续上升。而各个公司的集群规模,以及对容器技术的推进都将会持续加大。在经历了初步容器化后,更多的公司将面临的问题是稳定性和性能优化问题。与此同时,service mesh,serverless 等技术也都会逐步得到普遍应用。从底层次技术的角度来看,cgroups v2 将逐步普及,进而取代 cgroups v1,但这个过程可能需要两三年左右。整体而言,稳定性和性能优化将会是未来的主旋律。

如今,3 年时间已经过去,Kubernetes v1.25 中对 cgroup v2 的支持已经达到 GA 。

PodSecurity 特性达到 GA

#110459 · kubernetes/kubernetes 中正式将 PodSecurity 特性升级到 GA 。如果我没有记错,这个 特性应该是从引入到 GA 最快的特性之一了。

PodSecurity 是自 Kubernetes v1.22 引入的 alpha 特性,作为 PodSecurityPolicy 的一个替代。在 v1.23 达到 beta 级别,通过上述 PR,在 v1.25 正式 GA ,并且默认启用,可以看到 整个发展过程还是很快的。

PodSecurity 定义了 3 种级别:

  • Enforce:如果 Pod 违反策略,则不会被创建;
  • Audit:如果 Pod 违反策略,则在审计日志中会被记录,但是 Pod 仍将正常创建;
  • Warn:如果 Pod 违反策略,则会在 console 中打印 warning 信息,Pod 仍将正常创建;

使用起来也很简单,只需要给 namespace 添加 pod-security.kubernetes.io/<mode>=<standard> 标签即可。

只要你的 Kubernetes 集群版本先升级到 v1.22 以上,并且开启 PodSecurity 特性,那么就可以按照 Migrate from PodSecurityPolicy to the Built-In PodSecurity Admission Controller | Kubernetes 进行迁移了。

初步支持 user namespaces

  • Add support for user namespaces phase 1 (KEP 127) by rata · Pull Request #111090 · kubernetes/kubernetes

这个 PR 实现了 KEP127 的第一阶段,KEP127 旨在为 Pod 添加 user namespaces 的支持。对 user namespaces 不太熟悉的小伙伴,可以看看我之前的系列文章:《搞懂容器技术的基石:namespace (上)》 和 《搞懂容器技术的基石:namespace (下)》 。

在 Kubernetes 中支持使用 user namespaces 的好处在于,可以在与主机有不同 UID/GID 的 Pod 中运行进程,这样在 Pod 内的特权进程 实际是作为主机中的普通进程运行的。这样,假设 Pod 内的特权进程由于安全漏洞被攻破,对主机的影响也可以降到比较低。

直接相关的漏洞,比如 CVE-2019-5736 ,我也曾在 2019 年的文章 《runc 1.0-rc7 发布之际》 专门介绍过, 感兴趣的小伙伴可以到该文章中了解详情。

该实现是在 Pod 的 Spec 中添加了布尔类型的 HostUsers 字段,以决定是否启用主机的 user namespaces,默认是 true 。

此外,目前可预见的情况是,如果 Kubernetes 集群使用的 Linux 内核版本在 v5.19 以下的话,那么使用该特性可能会导致 Pod 的启动时间增加。

CronJobTimeZone 达到 Beta 级别

  • Promote CronJobTimeZone to beta by soltysh · Pull Request #111435 · kubernetes/kubernetes

CronJob TimeZone 的特性达到了 Beta 阶段。不过根据 Kubernetes 最新的特性策略,该特性仍然需要手动开启 CronJobTimeZone feature gate 。

注意,CronJob 如果不设置 TimeZone 的话,默认使用的是 kube-controller-manager 进程的 TimeZone 。之前有遇到小伙伴在这个问题上浪费了一些时间。

引入 alpha 特性 ContainerCheckpoint

#104907 · kubernetes/kubernetes 这是一个持续了将近一年的 PR,在这个 PR 中引入了一项新的特性:ContainerCheckpoint

对 Docker 比较熟悉的小伙伴,可能知道在 Docker 中存在一个 docker checkpoint 的子命令。这个子命令实际上是可以帮助我们为某个正在运行的容器创建一个状态点的快照,并将其保存到磁盘中。

后续,我们可以使用此 checkpoint 启动容器,恢复其原先的状态,或者将容器迁移到其他的机器上。

同样的,在 Kubernetes 中提供的这个 ContainerCheckpoint 的新特性是自 v1.25 开始作为 alpha 特性加入的,默认是关闭的。利用此特性可以通过 kubelet 提供的 API,为 container 创建一个有状态的快照,然后将其移动到另一个节点上进行调试,或者其他类似的需求。

此处需要注意的是,创建 checkpoint 可能会产生一些安全隐患,比如 checkpoint 实际上是对当前运行中 container 的内存快照,所以如果在 container 的内存中包含了某些隐私数据,那么有可能在迁移到其他机器上也可以访问到。

另一方面,创建 checkpoint 会产生一些文件,这些文件是需要占用磁盘的。如果频繁的创建 checkpoint 则可能导致磁盘压力过大。checkpoint 的存档,默认情况下会放在 /var/lib/kubelet/checkpoints 目录下,并且以 checkpoint-<podFullName>-<containerName>-<timestamp>.tar 进行命名。

这个特性使用起来也很简单,直接给 Kubelet 发送一个请求即可:

1
POST /checkpoint/{namespace}/{pod}/{container}

然后将获取到的归档文件,通过以下命令进行恢复:

1
crictl restore --import=<archive>

为 kubectl 引入 kuberc 配置文件

KEP-3104 这个 KEP 旨在为 kubectl 引入一个新的配置文件 kuberc,用来配置一些用户的自定义配置。这在很多的项目,或者工具中都有类似的用法。比如 Vim 中可以通过 -u 指定用户自己的配置文件,或者使用默认的 ~/.vimrc 来完成自定义配置。

这样做的好处就在于可以让 kubeconfig 更加的专注,仅仅需要保留和集群、用户凭证相关的信息即可,对于用户的自定义配置则分离开来。具体而言,这个配置文件看起来就会是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1alpha1
kind: Preferences

command:
aliases:
- alias: getdbprod
command: get pods -l what=database --namespace us-2-production

overrides:
- command: apply
flags:
- name: server-side
default: "true"
- command: delete
flags:
- name: confirm
default: "true"
- command: "*"
flags:
- name: exec-auth-allowlist
default: /var/kubectl/exec/...

看起来也比较直观,可以用来增加一些 alias 和覆盖一些默认的配置,这样大家不再需要定义很多的 alias,以后使用 kubectl 的时候敲的命令也能少很多。此特性未实现之前, 在这里顺便推荐另一个项目 kubectl-aliases,此项目中包含了很多 alias,可以让使用 kubectl 的过程更加简单。

但也有一些弊端,就像是每个 Vim 用户都要有自己的 vimrc 配置文件一样,这会养成一定的习惯。在一些没有自己自定义配置的机器上使用时,会有些不习惯。同时,这在排查问题时,也可能增加排查的链路(比如 kuberc 中增加了一个错误的配置之类的)。

举例来说,我在排查 Vim 的问题时候,通常会直接 vim -u /dev/null 这样,以防使用了任何自定义配置造成影响。那么后续如果这个功能完全实现了,那么大家在 排查问题的时候,需要注意使用 kubectl --kuberc /dev/null 类似这样的方式来避免本地自定义配置造成影响。

为 kubectl 添加 --subresource 的补全

  • Add shell completion for new --subresource flag by marckhouzam · Pull Request #109070 · kubernetes/kubernetes

在 Kubernetes v1.24 中,给 kubectl 增加了 subresource 的支持(指 statusscale),这样就可以很方便的直接对 subresource 进行操作了,而不需要每次都 -o yaml 之类的直接进行查看,或者通过 curl 之类的调用 API 来完成其他操作。使用了此特性后,可以有如下效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# v1.24+
tao@moelove:~$ kubectl get -n apisix --subresource status deploy apisix-ingress-controller
NAME AGE
apisix-ingress-controller 2d23h

tao@moelove:~$ kubectl get -n apisix --subresource scale deploy apisix-ingress-controller -ojson
{
"apiVersion": "autoscaling/v1",
"kind": "Scale",
"metadata": {
"creationTimestamp": "2022-08-04T18:57:45Z",
"name": "apisix-ingress-controller",
"namespace": "apisix",
"resourceVersion": "1656",
"uid": "7c191a14-ee55-4254-80ba-7c91b4c833bd"
},
"spec": {
"replicas": 1
},
"status": {
"replicas": 1,
"selector": "app.kubernetes.io/instance=apisix,app.kubernetes.io/name=ingress-controller"
}
}

但是在此之前版本使用该参数的话,会直接提示错误:

1
2
3
4
# v1.23
tao@moelove:~$ kubectl-v1.23 get -n apisix --subresource status deploy apisix-ingress-controller
Error: unknown flag: --subresource
See 'kubectl get --help' for usage.

此处我提到的这个在 v1.25 中的 PR 实际上是为了给 --subresource 提供一个命令补全的能力(虽然如上文提到的,目前就两种资源),还是比较方便的。

其他

  • #109074 · kubernetes/kubernetes

kubeadm 中为 etcd 的 static Pod 增加了一个 --experimental-initial-corrupt-check 选项,可以用来确认 etcd member 中数据的一致性。这个特性预期在 etcd 的 v3.6 版本中会正式可用。此外,etcd 的 Release 页面也写了,当前不建议将 etcd 3.5.x 用于生产环境,如果尚未进行升级,可以先继续使用 3.4.x。如果已经升级了,那么可以自行增加此参数;

  • Migrate Ginkgo from v1 to v2 · kubernetes/kubernetes

这个 PR 持续了将近三个月,主要是将 Kubernetes 项目中使用的 Ginkgo 从已经废弃的 v1 版本升级到 v2 版本。

其实目前很多项目都在积极的推进此事,但不同的项目对 Ginkgo 的依赖和使用程度不同,在这个 PR 中修改了超过 600 个文件,非常的庞大。而之前在 Apache APISIX Ingress controller 项目中,从 Ginkgo v1 升级到 v2 时,仅仅用了一周时间,修改文件不算太多。此外目前 Kubernetes Ingress-NGINX 项目也同样在进行此升级,可能工作量也不小。

  • Introduce KUBECACHEDIR environment variable to override default discovery cache dir by ardaguclu · kubernetes/kubernetes

这个 PR 说起来是比较小的一个改动,但是它的影响却很大。

在这个 PR 中引入了一个新的 KUBECACHEDIR 环境变量,来替代默认的 ~/.kube/cache 缓存目录。通过这个 PR 就有可能会导致用户在使用 kubectl 的时候,可以通过这个环境变量来跳过 缓存。进而可能会引起一些性能问题。

  • kube-apiserver: default --enable-logs-handler flag to false · kubernetes/kubernetes

kube-apiserver 中的 /logs 由于安全问题,默认情况下会进行关闭,然后通过 --enable-logs-handler 标签进行启用。如果要进行日志采集的话,需要额外注意下。

  • #111060 · kubernetes/kubernetes

kube-proxy 的 container image 将要变更为 distroless 的了。这可以规避很多安全隐患,提升集群的安全性。

以上就是 Kubernetes v1.25 中比较值得关注的内容。在进行集群升级前一定要注意检查。好了,我们下期再见!

Kubernetes v1.26

Kubernetes v1.26 是 2022 年的最后一个大版本更新,包含了 37 项主要的更新。

8 月底正式发布的 v1.25 中包含 40 项。

在 v1.26 中包含了很多直接影响用户与 Kubernetes 交互相关的功能,比如以下内容中会介绍的允许跨 namespace 持久化卷快照引用;允许用户无需额外的 exporter 即可自定义 Service Level Indicator(SLI); kubectl events 达到 Beta;支持 Pod 所需资源就绪后再进行调度;支持使用 OpenAPI v3 等。

以及针对高性能负载运行在哪个物理 CPU 的场景支持。

#3294 允许跨 namespace 持久化卷快照引用

在 Kubernetes 中,用户可以通过使用 VolumeSnapshot 特性,从卷快照创建新的持久化卷。这是非常有用的,比如说 DBA 可以在进行数据库大的变更/迁移操作前,对持久化卷做一次快照,如果出现异常,则可以直接从该快照恢复数据库之前的状态。

例如通过以下方式可以动态的创建一个快照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: test-snapclass
driver: testdriver.csi.k8s.io
deletionPolicy: Delete
parameters:
csi.storage.k8s.io/snapshotter-secret-name: mysecret
csi.storage.k8s.io/snapshotter-secret-namespace: mysecretnamespace
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: test-snapshot
namespace: ns1
spec:
volumeSnapshotClassName: test-snapclass
source:
persistentVolumeClaimName: test-pvc

当然,这里也有些需要注意的点,该功能只能用于 CSI 存储驱动,并且该功能是自 Kubernetes v1.17 达到 beta,v1.20 正式 GA 的。

在 v1.26 中增加的特性是 CrossNamespaceVolumeDataSource 当前是 Alpha 阶段,允许创建持久化卷的时候,跨 namespace 引用卷快照。它的主要价值在于,比如想要做应用跨 namespace 迁移的时候,直接从另一个 namespace 对持久化卷做快照,然后使用快照创建 PVC 即可很轻松的完成迁移。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: testvolumeclaim
namespace: nstest1
spec:
storageClassName: mystorageclass
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
dataSourceRef:
apiGroup: snapshot.storage.k8s.io
kind: VolumeSnapshot
name: testsnapshot
namespace: moelove
volumeMode: Filesystem

当然如果考虑授权相关问题的话,这里使用 Gateway API 的 ReferenceGrant 来控制授权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: ReferenceGrant
metadata:
name: test
namespace: moelove
spec:
from:
- group: ""
kind: PersistentVolumeClaim
namespace: nstest1
to:
- group: snapshot.storage.k8s.io
kind: VolumeSnapshot
name: testsnapshot

我认为这是个很实用的功能。

#3488 允许使用 CEL 进行 Admission Control

这篇 K8S 生态周报| Kubernetes v1.23.0 正式发布,新特性一览 | MoeLove 文章中,曾介绍过 Kubernetes 中引入了 Common Expression Language (CEL) 进行 CRD Validation。该特性在 v1.25 达到 Beta。

例如,某个 CRDs 的内容如下,其中定义了 minReplicas 小于 replicas 并且 replicas 小于 maxReplicas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-validation-rules:
- rule: "self.minReplicas <= self.replicas"
message: "replicas should be greater than or equal to minReplicas."
- rule: "self.replicas <= self.maxReplicas"
message: "replicas should be smaller than or equal to maxReplicas."
properties:
...
minReplicas:
type: integer
replicas:
type: integer
maxReplicas:
type: integer
required:
- minReplicas
- replicas
- maxReplicas

那么,当有如下的自定义资源创建时,Kubernetes 将会拒绝其请求。

1
2
3
4
5
6
7
8
apiVersion: "stable.example.com/v1"
kind: CustomDeployment
metadata:
name: my-new-deploy-object
spec:
minReplicas: 0
replicas: 20
maxReplicas: 10

并且返回如下错误:

1
2
The CustomDeployment "my-new-deploy-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: replicas should be smaller than or equal to maxReplicas.

这个过程看起来和 Admission controller 做的事情很像。当然,我之前也写了一篇文章 《理清 Kubernetes 中的准入控制(Admission Controller) | MoeLove》,有兴趣的小伙伴可以再翻看下。

回到我们聊到这个特性中,可以认为这是一种对 Admission webhook 的替代,用一种更加原生,直观,并且声明式的方式来进行管理。

这里引入了一个新的资源 ValidatingAdmissionPolicy ,使用起来如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
name: "demo-policy.moelove.info"
Spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 2"

上述配置将会拒绝 replicas 不大于 2 的 Deployment。

这个特性的优势就在于无需额外的其他组件,除了需要学习 CEL 外,还是比较方便的。该特性目前是 alpha 级别。

#3545 改善 NUMA 中的拓扑管理

在文章 K8S 生态周报| Kubernetes v1.21 发布, 带来新的内存管理器 | MoeLove 中介绍,Kubernetes v1.21 中在 kubelet 中新增了一个内存管理器。

主要是为了应对多 NUMA 结构下的效率。多 NUMA 结构下,为了保证效率,所以会按内存和 CPU 的相对距离来按 node 定义是否为 local memory 或者说本地内存,同时由于实际位置不同,所以就可能会产生内存分配不均匀的情况了。比如,我们可以使用 numactl 管理工具查看下当前机器上的情况:

1
2
3
4
5
6
7
8
9
10
11
12
[tao@moelove ~]# numactl -H
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 20 21 22 23 24 25 26 27 28 29
node 0 size: 65186 MB
node 0 free: 9769 MB
node 1 cpus: 10 11 12 13 14 15 16 17 18 19 30 31 32 33 34 35 36 37 38 39
node 1 size: 65536 MB
node 1 free: 15206 MB
node distances:
node 0 1
0: 10 21
1: 21 10

可以看到在我当前的这台机器上就存在着比较明显的内存分配不均的情况。所以当某个进程达到了其 local memory 的上限,那自然就会影响到它的性能。我最早折腾 NUMA 相关问题是在前些年大量使用 MongoDB 的时候,在这上面也花了些时间,不过这也不影响我对 MongoDB 的喜爱~

这次在 kubelet 中增加的内存管理器便可以很好的解决这个问题,可以在启动 kubelet 的时候通过 --reserved-memory 以及配合 --memory-manager-policy 等参数来一起设置。例如:

1
--memory-manager-policy static --reserved-memory 0:memory=1Gi,hugepages-1M=2Gi --reserved-memory 1:memory=2Gi

注意:memory-manager-policy 必须设置为 static,如果不设置则默认为 none,即不采取任何行为。

不过这个特性还在较早期的阶段,目前只为 Guaranteed QoS 类的 Pod 提供支持。另外,如果正确启用了此特性,则在机器的 /var/lib/kubelet/memory_manager_state 可以看到其详细信息。

最终将会影响到拓扑管理器。

然后在 Kubernetes v1.22 则继续在 kubelet 中增加了另一个 --cpu-manager-policy-options 选项,对应为 CPU 管理器。

在 v1.26 中增加的则是 --topology-manager-policy-options 来控制整体的拓扑管理。现在仅支持一个 prefer-closest-numa-nodes=true 配置,当开启此配置的时候,拓扑管理器将尽量在单个 NUMA 或者尽可能少的 NUMA 节点中对齐资源。

这对于高性能负载是非常重要的一个优化。建议关注。

#113274 为 Pod 调度增加调度就绪的机制

这是 KEP 3521 的第一部分。

首先简单的回顾一下 Pod 的创建过程。

当 client 通过 kube-apiserver 创建成功 Pod 资源后,kube-scheduler 会去检查尚未被调度的 Pod,然后为其进行调度,分配 Node。之后 Node 获取到调度到该 Node 上的 Pod 然后进行创建。这里省略了很多细节,但其他的部分与我们此处要介绍的内容关系不太大,就不展开了。

根据上述的过程,我们可以发现,在 Pod 创建成功后,其实就默认该 Pod 是可以被调度了,kube-scheduler 就应该开始工作了。

但在实际的场景中,Pod 通常还会需要一些其他的资源,最典型的比如存储。在一些环境中,这些资源是需要预先进行创建的,尤其是在一些云厂商的场景中,还需要检查用户账户中是否还有余额可以用于创建云盘等

一但前置的依赖无法满足,假如 kube-scheduler 已经完成了 Pod 的调度,那么 kubelet 侧就会处于尝试创建 Pod ,但失败的情况。

这个 KEP 的出现就可以很好的解决这个问题,增加了一个 Pod 是否准备好被调度的机制。如果前置依赖不满足,那么 Pod 就无需被调度,这也不会消耗资源。kube-scheduler 和 kubelet 都无需进行处理。待条件满足,Pod 再被调度和创建即可。

这个机制我个人感觉还是挺好的,甚至我可以有更灵活的策略来控制应用的副本。比如在大流量,需要动态扩容的场景下,我可以利用此机制预先创建一些 Pod 资源以及准备好它的依赖, 甚至可以在 Node 上准备好镜像等。当需要增加副本时,直接标记 Pod 可被调度, 这样就可以更快的在 Node 上拉起 Pod 了。

移除 CRI v1alpha2

在移除了 dockershim 的支持后, 现在终于删掉了 CRI v1alpha2 的代码,这意味着之后所有实现了 CRI 的运行时,都必须实现 CRI v1 的接口。

目前 containerd 的 CRI v1 接口已经实现了,所以在 Kubernetes v1.26 发布后,也可以放心的使用 containerd 作为其运行时。

不过,你是否还记得 cri-dockerd 呢?用于将 Docker 作为 Kubernetes 运行时的组件,现在由 Mirantis 进行维护, 此项目目前的维护者比较少,目前还只支持 CRI v1alpha2 ,所以,如果你在使用此项目让 Docker 作为运行时,并且想要升级到 Kubernetes v1.26 的话,这是不行的。

#111333 Auth API 允许获取 User 属性

这是 KEP-3325: Self subject attributes review API 实现的一部分。

大家想必都知道,Kubernetes 中并没有 User(用户)的资源,但是 Kubernetes 中有权限校验的方式,比如我们常用到的利用 x509 证书进行用户权限相关的校验,或者 通过外部的 OIDC 和 webhook 等进行校验。

此功能实际上是为了添加一个新的接口,以便于用户身份通过校验后,获取其所具有的属性。这样就可以简单的通过增加一个 kubectl auth whoami 的命令,来了解当前用户的相关信息了。这功能比较类似于我们做 OAuth 的时候,可能会做个 UserInfo 之类的接口,用来查看用户相关的属性。

该功能是通过在 authentication.k8s.io Group 下添加了 SelfSubjectReview 资源来实现的,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.
type SelfSubjectReview struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Status is filled in by the server with the user attributes.
Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
// User attributes of the user making this request.
// +optional
UserInfo v1.UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}

此功能在 v1.26 版本开始引入,并作为 Alpha 特性提供,可通过 APISelfSubjectReview feature gate 控制是否启用。

同时,本次也在 kubectl 中添加了 kubectl alpha auth whoami 子命令,可直接查看当前用户的相关属性信息。当执行此命令后,会得到如下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: authentication.k8s.io/v1alpha1
kind: SelfSubjectReview
status:
userInfo:
username: tao.moelove.info
uid: a79aaf30-0c6a-66ed-881d-0888ac1266683
groups:
- admins
- speakers
- system:authenticated
extra:
skills:
- reading
- learning
subjects:
- kubernetes
- containers

#3386 减少 Kubelet 在 PLEG 中的 CPU 消耗

这个主要是为了减少 Kubelet 在跟踪 Pod 状态 PLEG 时的 CPU 消耗。

它将减少 Kubelet 的一些定期轮询,而是尽可能的依赖于 CRI 的通知。

经过这个调整,也许在生产环境中遇到的 PLEG 问题也能少一点吧。

其他

  • kubeadm: Add the option to cleanup the tmp directory by chendave · Pull Request #112172 · kubernetes/kubernetes

kubeadm 新增 cleanup-tmp-dir 配置项,在 kubeadm reset 时,可以通过传递此参数将 kubeadm 产生的临时文件给清理干净。

  • Avoid propagating "search ." into containers /etc/resolv.conf by dghubble · Pull Request #112157 · kubernetes/kubernetes

从 Kubernetes v1.25 开始,/etc/resolv.conf 中的 search . 会被传递到容器内。

这会导致任意基于 musl libc 系统的 DNS 查询失败,比如任何基于 Alpinelinux 的镜像都会失败。

要验证自己的集群是否会受该问题影响,只需要查看系统的 /etc/resolv.conf 文件的内容即可。比如:

1
2
3
nameserver 127.0.0.53
options edns0 trust-ad
search .

如果是上述的情况,一般说明是被 systemd resove 接管了,并且会受到此处描述的问题所影响。

  • Fix rollout history bug by brianpursley · Pull Request #111093 · kubernetes/kubernetes

在执行 kubectl rollout history 的时候可以传递 --revision=3 拿到指定版本的信息。但是如果指定了 output format ,则 --revision 可能会失效。通过此 PR 便可解决此问题,但要到 v1.26 才会携带。

  • Expose a pending pods summary in scheudler's dummper output by Huang-Wei · Pull Request #111726 · kubernetes/kubernetes

调度程序可以 dump 出更多信息。

  • Revert "promote LocalStorageCapacityIsolationFSQuotaMonitoring to beta" by rphillips · Pull Request #112076 · kubernetes/kubernetes

由于 OpenShift 团队发现在使用它的时候存在一些问题, 将 LocalStorageCapacityIsolationFSQuotaMonitoring 重新回退到 Alpha 阶段。

  • Removal of GlusterFS code from the repo by humblec · Pull Request #112015 · kubernetes/kubernetes

在之前的 「K8S 生态周报」中我曾介绍过,在 v1.25 中将树内的 GlusterFS plugin 标记为废弃,并建议迁移至使用 CSI , 如今这些插件已经被彻底删除了。

  • kubelet: append options to pod if there are multi options in /etc/resolv.conf by pacoxu · Pull Request #112414 · kubernetes/kubernetes

当前 kubelet 创建 Pod 的时候,如果 /etc/resolv.conf 中存在多行 options 配置,则只取最后一行。

例如 /etc/resolv.conf 包含的配置如下:

1
2
options timeout:1 
options attempts:3

则 Pod 中的 /etc/resolv.conf 只包含如下内容

1
options attempts:3

但事实上即使在 /etc/resolv.conf 中配置多行 options ,DNS 也是可以正常工作的。所以当前的 kubelet 行为就不一致了。

通过这个 PR, 会将主机的 /etc/resolv.conf 中的多行配置合并为一行。如果还是上面的例子,则 Pod 内看到的就是如下内容了.

1
options timeout:1 attempts:3

这里有个需要注意的点就是,Kubernetes 中的默认 DNS 策略并非 default,这个修改只是针对 default 策略的。

  • kubeadm: Inherit dry-run flags for each sub-phases by chendave · Pull Request #112945 · kubernetes/kubernetes kubeadm 所有的阶段都支持了 dry-run 模式;
  • Add categories to kubectl api-resources wide output and add --categories flag by brianpursley · Pull Request #111096 · kubernetes/kubernetes 为 kubectl api-resources -o wide 的输出中增加了一列 "Categories";
  • add --concurrent-horizontal-pod-autoscaler-syncs flag to kube-controller-manager by zroubalik · Pull Request #108501 · kubernetes/kubernetes 为 kube-controller-manager 增加了 --concurrent-horizontal-pod-autoscaler-syncs 的参数,原先 HPA 中默认只有一个 worker,在大规模集群中处理效率很低。本次的 PR 可以通过此参数来自行配置 worker 数量,以便于提升效率;
  • Normalize HTTP lifecycle handlers with HTTP probers by jasimmons · Pull Request #86139 · kubernetes/kubernetes

我们可以为 Pod 增加 postStartpreStop 的 Hook,并且其分别可以设置为 ExecHTTP 模式。这个 PR 主要是在修改 HTTP 模式下的行为。

具体来说,HTTP 模式下的代码与 readiness/liveness 下使用的并不一样,而且也不支持一些常见的功能,比如:

  • 设置自定义 HTTP header
  • 使用 HTTPS 连接

但经过此 PR ,终于将它们的行为进行了统一,但这毕竟是一个比较大的调整,如果你不希望应用此变更, 可以通过 -feature-gates=ConsistentHTTPGetHandlers=false 进行全局禁用,避免这个功能影响到你的环境。

  • Escape terminal special characters in kubectl by dgl · Pull Request #112553 · kubernetes/kubernetes

这个 PR 中对一些特殊字符进行了转义。这其实是一个比较有意思的内容,我来稍微介绍一下。

你可以在自己的终端中尝试执行如下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
kubectl create -f - <<EOF
{
"apiVersion": "v1",
"involvedObject": {
"kind": "Node",
"name": "node01",
"uid": "node01"
},
"kind": "Event",
"message": "\u001b[2J\u001b[3J\u001b[1;1H\u001b[m spoofed \u001b[60C\u001b[1;0m. Done",
"metadata": {
"name": "spoofEvent",
"namespace": "default"
},
"source": {
"component": "kubelet",
"host": "node01"
},
"type": "Normal"
}
EOF

这将会创建一条 event 记录,但是一但你执行 kubectl get events 你就会发现一些有趣的事情,屏幕上的记录被清空了。

这是由于 kubectl 在输出内容的时候并不会进行任何转义,比如上述示例中包含了一些特殊字符:

  • \u001b[2J:清屏
  • \u001b[60C: 将光标向前移动 60

当然还有一些其他的,我印象中我早年刚开始接触 Linux 不久后还花费了一些时间来学习这些东西,因为这些东西可以配置到终端里面,实现一些比如变换颜色之类的事情。

我翻了下我之前的文章,曾经还有将 bash 做过如下设置:

1
2
3
4
5
6
7
8
9
10
11
function git-branch-name {
git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3
#git rev-parse --abbrev-ref HEAD
}

function git-branch-prompt {
local branch=`git-branch-name`
if [ $branch ]; then printf " [%s]" $branch; fi
}

PS1="\u@\h \[\033[0;36m\]\W\[\033[0m\]\[\033[0;32m\]\$(git-branch-prompt)\[\033[0m\] \$ "

对此内容感兴趣的小伙伴可以试试看把上述内容贴到自己的 .bashrc 文件中,然后 source 一下看看。

回到这个 PR 中,之前这个问题还给分配成了 CVE-2021-25743, 修复的办法也比较简单,但是比较耗时耗力,就是对一些输出的位置做了转义操作。

不过可能还有一些遗漏的,比如 kubectl logs 之类的,可能也会受到影响,有兴趣的小伙伴可以去验证一下。

  • (kubectl certificates): Remove certificates/v1beta1 client usage by ardaguclu · Pull Request #111990 · kubernetes/kubernetes

certificates.k8s.io/v1beta1 自 Kubernetes v1.19 已被废弃,通过此 PR 移除,将在 v1.26 版本中生效。

以后使用 certificates.k8s.io/v1 即可。这个主要是影响 kubectl certificate 命令。

Kubernetes v1.27

Kubernetes v1.27 是 2023 年的第一个大版本更新,包含了近 60 项主要的更新。 而 1.26 只有 37 项,所以这个版本可以说是一个变化非常显著的版本了。

其中 18 个增强功能正在进入 Alpha 阶段,29 个将升级到 Beta 阶段,而另外 13 个则将升级到稳定版。

尽管这个版本中包含了这么多的特性变更,但值得一提的是,这个版本应该算是第一个完全按照即定流程,恪守每个 deadline 的版本。之前的版本中,每次都或多或少会有一些变数,不过这也从侧面可以看到 release team 做了很多幕后的工作。

SeccompDefault 达到 Stable

如果想要默认使用 seccomp profile,则必须在每个想要使用它的节点上为 kubelet 启用 --seccomp-default 选项。如果启用了该选项,则 kubelet 将默认使用由容器运行时定义的 RuntimeDefault seccomp profile,而不是使用 Unconfined(禁用seccomp)模式。“

默认配置文件旨在提供强大的安全性设置,并保留工作负载功能。容器运行时的不同发布版本之间可能存在不同的默认配置文件。

印象里很早之前 Docker 的配置文件就因为修补安全漏洞而调整过。

Pod 调度就绪机制达到 Beta

这个功能实际上是从 Kubernetes v1.26 开始增加的。是 KEP 3521 的第一部分。

首先我们来简单的回顾一下 Pod 的创建过程。

当 client 通过 kube-apiserver 创建成功 Pod 资源后,kube-scheduler 会去检查尚未被调度的 Pod,然后为其进行调度,分配 Node。之后 Node 获取到调度到该 Node 上的 Pod 然后进行创建。这里省略了很多细节,但其他的部分与我们此处要介绍的内容关系不太大,就不展开了。

根据上述的过程,我们可以发现,在 Pod 创建成功后,其实就默认该 Pod 是可以被调度了,kube-scheduler 就应该开始工作了。

但在实际的场景中,Pod 通常还会需要一些其他的资源,最典型的比如存储。在一些环境中,这些资源是需要预先进行创建的,尤其是在一些云厂商的场景中,还需要检查用户账户中是否还有余额可以用于创建云盘等

一但前置的依赖无法满足,假如 kube-scheduler 已经完成了 Pod 的调度,那么 kubelet 侧就会处于尝试创建 Pod ,但失败的情况。

这个 KEP 的出现就可以很好的解决这个问题,增加了一个 Pod 是否准备好被调度的机制。如果前置依赖不满足,那么 Pod 就无需被调度,这也不会消耗资源。kube-scheduler 和 kubelet 都无需进行处理。待条件满足,Pod 再被调度和创建即可。

这个机制我个人感觉还是挺好的,甚至我可以有更灵活的策略来控制应用的副本。比如在大流量,需要动态扩容的场景下,我可以利用此机制预先创建一些 Pod 资源以及准备好它的依赖, 甚至可以在 Node 上准备好镜像等。当需要增加副本时,直接标记 Pod 可被调度,

使用时,通过配置 Pod 的 .spec.schedulingGates 即可。

新增 NodeLogQuery 特性 - KEP-2258

我们通常最习惯使用 kubectl logs 命令来获取 Kubernetes 集群中运行的应用的日志,也可以通过给它传递一些参数来调整它的过滤范围。

比如:kubectl logs job/hello 来指定获取 hello 这个 job 的日志;也可以增加 -l / --selector='' 来基于 label 进行过滤。

但这并没有扩展到 Node 级别的日志,无法直接获取到某个 Node 上的全部日志,要想得到这个结果需要写一段很复杂的 Shell 来完成。

当前 Kubernetes 社区已经逐渐提供了更多 Node 调试工具,旨在为调试 Node 故障提供统一体验,并更好地支持极简操作系统。通过 KEP 2258: add node log query by LorbusChris · Pull Request #96120 · kubernetes/kubernetes ,我们现在可以远程获取底层 Node 日志。与容器日志记录一样,这是Kubelet API的一部分。

对于Linux系统,它查询journald;对于Windows系统,则查询事件日志(Event Log)。目前还没有专门针对此功能的 kubectl 命令,但可以使用如下命令进行尝试:

1
(MoeLove) ➜ kubectl get --raw "/api/v2/nodes/$NODE_NAME/proxy/logs/?query=kubelet

基于 CEL 的 Admission Control

对 Kubernetes 中的 Adminssion Control 感兴趣的小伙伴可以看看我之前的文章:理清 Kubernetes 中的准入控制(Admission Controller) | MoeLove

  • KEP-3488: Implement secondary authz for ValidatingAdmissionPolicy by jpbetz · Pull Request #116054 · kubernetes/kubernetes
  • KEP-3488: Implement Enforcement Actions and Audit Annotations by jpbetz · Pull Request #115973 · kubernetes/kubernetes

Kubernetes 在 v1.26 增加了一项很重要的特性,那就是允许使用 CEL 进行 Admission Control,具体内容可以参考文章:Kubernetes v1.26 新特性一览 | MoeLove

其中引入了一个新的资源 ValidatingAdmissionPolicy ,使用起来如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
name: "demo-policy.moelove.info"
Spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 2"

但是在当时也只是实现了 KEP-3488 的一部分。

在这个 PR 中是在实现 Authz 的部分,这允许用 CEL 表达式编写复杂的 admission control 规则, 放置在声明式资源中,而不是构建和部署 webhook。

虽然 admission webhook 一直是我们灵活的与第三方工具集成的基石,但是对于新用户来说,它们有很多复杂性,新的 CEL 系统有望接管仅需要对默认规则进行小修改的简单独立案例。

以前,表达式上下文会公开有关当前请求和目标资源的信息,现在通过这个 PR 可以在授权层中动态检查 RBAC 权限。一些有用的地方可能是使用 RBAC 进行每个字段的更新权限,允许 RBAC 检查特定对象而不使用 resourceNames 系统, 或基于请求者身份限制对程序敏感字段(例如 finalizers )的访问而无需生成复杂的 RBAC 策略。

例如:

1
2
3
authorizer.group('').resource('pods').namespace('default').check('create').allowed()
authorizer.path('/healthz').check('GET').allowed()
authorizer.requestResource.check('my-custom-verb').allowed()

本次还加入了#115973,该功能允许在失败时作为主要操作发出审计日志事件,或者如果需要更多数据,可以编写一个或多个CEL表达式,以提供详细的值, 这些值将发送到审计子系统。

这既可以在开发新策略时提供强大的调试选项,也可以进行运行时分析。其他 CEL admission 特性包括成本检查,以防止您使用所有这些新功能意外拒绝服务自己的 kube-apiserver,以及改进的类型检查。

总的来说,基于 CEL 的 admission 处理有了很多新的功能,希望进一步将 webhook 推入到一个有限的用例空间中(防止滥用)。

Pod In-place 原地伸缩能力

这个功能允许在不重启 Pod 的情况下,更新 Pod 的 resources 配置。

  • In-place Pod Vertical Scaling feature by vinaykul · Pull Request #102884 · kubernetes/kubernetes

经过 4 年的规划和至少 2 年的开发,在 Kubernetes v1.27 中终于推出了 Pod 的就地资源缩放的第一版。这个PR实现了核心缩放功能和一些相关的API处理。主要功能非常简单,现在可以在现有容器上编辑 resources 配置,而不会导致 API 错误。

在看到缩放请求后,Kubelet 会立即采取行动并检查节点是否有足够的资源来满足新的请求。如果是这样,它将 Status.Resize 字段设置为 InProgress,并继续进行 CRI 调用和其他内部更新。

如果新的大小不合适,将启动其他状态流,但总体目标相同,即尝试在可能的情况下提供请求的更改。还有一个新的 per-resource 缩放策略字段,可以设置为 RestartNotRequired(默认值)表示不需要重新启动(但某些运行时仍然可能需要这样做), 或设置为 Restart 以强制关闭和重新启动容器(例如具有需要重新计算-Xmx 堆大小标志的 Java 应用)。

现在缺少一个显著的特性是基于缩放的驱逐。目前,Kubelet 不会自动处理它,但如果外部系统执行 Pod 删除,它将适当地作出反应。

尽管现在还处于比较早期的阶段,但至少我们看到了它的变化,期待后续的演进。

一些废弃提醒

不再提供的API版本:

  • Kubeadm v1beta2,可以使用 kubeadm config migrate 迁移到 v1beta3
  • resource.k8s.io/v1alpha1.PodScheduling :请使用 resource.k8s.io/v1alpha2.PodSchedulingContext
  • DynamicResourceManagement v1alpha1:请使用 v1alpha2
  • CSIStorageCapacity:storage.k8s.io/v1beta1:请使用 v1。

已弃用,在下一个版本发布之前实现替代方案:

  • seccomp.security.alpha.kubernetes.io/podcontainer.seccomp.security.alpha.kubernetes.io annotations :请改用 securityContext.seccompProfile 字段。
  • SecurityContextDeny 准入插件。
  • service.kubernetes.io/topology-aware-hints annotations:请改用 service.kubernetes.io/topology-mode

已删除

  • Feature gates:

    • IPv6DualStack
    • ExpandCSIVolumes
    • ExpandInUsePersistentVolumes
    • ExpandPersistentVolumes
    • ControllerManagerLeaderMigration
    • CSI Migration
    • CSIInlineVolume
    • EphemeralContainers
    • LocalStorageCapacityIsolation
    • NetworkPolicyEndPort
    • StatefulSetMinReadySeconds
    • IdentifyPodOS
    • DaemonSetUpdateSurge
  • appProtocol: kubernetes.io/grpc.

  • kube-apiserver 参数: --master-service-namespace.

  • CLI 参数: --enable-taint-manager--pod-eviction-timeout.

  • kubelet 参数: --container-runtime, --master-service-namespace.

  • Azure disk in-tree storage plugin.

  • AWS kubelet credential provider: 使用 ecr-credential-provider.

  • Metrics:

    • node_collector_evictions_numbernode_collector_evictions_total 替换
    • scheduler_e2e_scheduling_duration_secondsscheduler_scheduling_attempt_duration_seconds 替换

Kubernetes v1.28

Kubernetes v1.28 是 2023 年的第二个大版本更新,包含了 46 项主要的更新。 而今年发布的第一个版本 v1.27 有近 60 项,所以可以看出来,在发布节奏调整后,每个 Kubernetes 版本中都会包含很多新的变化。

其中 20 个增强功能正在进入 Alpha 阶段,14 个将升级到 Beta 阶段,而另外 12 个则将升级到稳定版。

可以看出来很多都是新特性。

Kubernetes 集群可以真正年度升级了

我们知道 Kubernetes 集群的架构中 control plane 和 Node 分离的,虽然用户在部署集群的时候,通常会选择将 control plane 和 Node 部署为相同版本。 但是如果要进行集群版本升级的时候,就会发现 control plane 和 Node 在升级过程中是无法保持版本一致的。

举例来说:

  • 我部署了一套 v1.23 版本的 Kubernetes 集群,control plane 和 Node 目前都是 v1.23;
  • 升级 control plane 到 v1.24;
  • 这个时候 Node 还是 v1.23;
  • 最后将 Node 也升级到 v1.24;

在这个升级过程中,control plane 和 Node 有一段时间版本是不一致的,这会产生问题吗?

通常来说,对于大多数软件,如果是这种分离式架构,版本不一致是有可能存在问题的(这里我就不说某些系统/软件了)。 但上述过程很明显是一定存在的,所以 Kubernetes 在这方面专门做了处理和兼容 。我们把这个策略叫作 Kubernetes 的版本偏差策略。

Kubernetes 中允许 control plane 和 Node 之间的版本存在 n-2 的偏差。比如:

  • control plane 版本为 v1.27
  • Node 版本可以为 v1.27, v1.26 和 v1.25

不过从 v1.28 开始,这个版本偏差策略扩展成了 n-3,比如:

  • control plane 版本为 v1.28
  • Node 版本可以为 v1.28, v1.27, v1.26 和 v1.25

解释完这个版本偏差策略后,我们来看下这个事情到底有多么重要。

Kubernetes 当前的发布和支持策略,是用户可以在一年内持续升级到最新的补丁版本以获取安全修复,并且只要进行 3 个连续的版本升级,就可以追上最新支持的版本了。

然而,由于 control plane 和 Node 之间测试/支持偏差目前仅限于 n-2 个版本,因此每年的 3 个版本升级将不得不进行两次 Node 的升级,才能保持在受支持范围内。例如,从 v1.24 升级到 v1.27 ,这个场景正好是从 2022 年的第一个版本升级到 2023 年的第一个版本。

  • control plane 和 Node 都是 v1.24;
  • control plane 升级 v1.24 - v1.25 - v1.26;
  • Node 升级 v1.24 - v1.26;
  • control plane 升级 v1.26 - v1.27
  • Node 升级 v1.26 - v1.27

从这里可以看到 Node 要升级两次,事实上在 Kubernetes 集群的维护过程中,Node 版本的升级带来的影响是很大的, 比如原先运行在这些 Node 上的 Pod 需要重新调度/重建等,虽然理想状况下对于业务应该没什么影响(但实际情况下...) 此外,随着集群规模的增加,这个 Node 升级的工作量也是很大的。

如果使用现在新的 n-3 偏差策略,我们来看看效果,还是从 v1.24 到 v1.27 (此处只是用做举例,从 v1.28 才生效):

  • control plane 和 Node 都是 v1.24;
  • control plane 升级 v1.24 - v1.25 - v1.26 - v1.27;
  • Node 升级 v1.24 - v1.27;

这样的话,Node 只需要升级一次,很明显 节省了很多工作量,并且也可以减少对业务的影响 ,这样也真正实现了 Kubernetes 的年度支持策略。

注意:首个可用 n-3 偏差策略的是 v1.28 ,它允许 control plane 是 v1.28 而 Node 最旧为 v1.25。

关于 Kubernetes 的版本偏差策略的详细说明可以参考 https://kubernetes.io/releases/version-skew-policy/

基于 CEL 的 Admission Control 达到 Beta

对 Kubernetes 中的 Adminssion Control 感兴趣的小伙伴可以看文章:理清 Kubernetes 中的准入控制(Admission Controller) | MoeLove

  • KEP-3488: Implement secondary authz for ValidatingAdmissionPolicy by jpbetz · Pull Request #116054 · kubernetes/kubernetes
  • KEP-3488: Implement Enforcement Actions and Audit Annotations by jpbetz · Pull Request #115973 · kubernetes/kubernetes

Kubernetes 在 v1.26 增加了一项很重要的特性,那就是允许使用 CEL 进行 Admission Control,具体内容可以参考文章:Kubernetes v1.26 新特性一览 | MoeLove

其中引入了一个新的资源 ValidatingAdmissionPolicy ,使用起来如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
name: "demo-policy.moelove.info"
Spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 2"

但是在当时也只是实现了 KEP-3488 的一部分。

在这个 PR 中是在实现 Authz 的部分,这允许用 CEL 表达式编写复杂的 admission control 规则, 放置在声明式资源中,而不是构建和部署 webhook。

虽然 admission webhook 一直是我们灵活的与第三方工具集成的基石,但是对于新用户来说,它们有很多复杂性,新的 CEL 系统有望接管仅需要对默认规则进行小修改的简单独立案例。

以前,表达式上下文会公开有关当前请求和目标资源的信息,现在通过这个 PR 可以在授权层中动态检查 RBAC 权限。 一些有用的地方可能是使用 RBAC 进行每个字段的更新权限,允许 RBAC 检查特定对象而不使用 resourceNames 系统, 或基于请求者身份限制对程序敏感字段(例如 finalizers )的访问而无需生成复杂的 RBAC 策略。

例如:

1
2
3
authorizer.group('').resource('pods').namespace('default').check('create').allowed()
authorizer.path('/healthz').check('GET').allowed()
authorizer.requestResource.check('my-custom-verb').allowed()

在 v1.27 还加入了#115973,该功能允许在失败时作为主要操作发出审计日志事件,或者如果需要更多数据,可以编写一个或多个CEL表达式,以提供详细的值, 这些值将发送到审计子系统。

这既可以在开发新策略时提供强大的调试选项,也可以进行运行时分析。 其他 CEL admission 特性包括各种检查,以防止您使用所有这些新功能意外拒绝服务自己的 kube-apiserver,以及改进的类型检查。

本次升级到 Beta 阶段,API version 也就随之升级到了:

1
admissionregistration.k8s.io/v1beta1

此外,还引入了包括 ValidatingAdmissionPolicy: support namespace access by cici37 · Pull Request #118267 · kubernetes/kubernetes 等在内的特性,进一步将 webhook 推入到一个有限的用例空间中(防止滥用)。

CRD 使用 CEL 进行 Validate 的特性再次达到 Beta

Kubernetes v1.23.0 正式发布后,引入了 Common Expression Language (CEL) 进行 CRD Validation。该特性计划在 v1.25 达到 Beta,这次是它第二次宣布达到 Beta 了。

例如,某个 CRDs 的内容如下,其中定义了 minReplicas 小于 replicas 并且 replicas 小于 maxReplicas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-validations:
- rule: "self.minReplicas <= self.replicas"
message: "replicas should be greater than or equal to minReplicas."
- rule: "self.replicas <= self.maxReplicas"
message: "replicas should be smaller than or equal to maxReplicas."
properties:
...
minReplicas:
type: integer
replicas:
type: integer
maxReplicas:
type: integer
required:
- minReplicas
- replicas
- maxReplicas

那么,当有如下的自定义资源创建时,Kubernetes 将会拒绝其请求。

1
2
3
4
5
6
7
8
apiVersion: "stable.example.com/v1"
kind: CustomDeployment
metadata:
name: my-new-deploy-object
spec:
minReplicas: 0
replicas: 20
maxReplicas: 10

并且返回如下错误:

1
2
The CustomDeployment "my-new-deploy-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: replicas should be smaller than or equal to maxReplicas.

这次还增加了 [KEP-2876]Add reason and fieldPath into CRD validation rules by cici37 · Pull Request #118041 · kubernetes/kubernetes 这个 PR, 新增了 fieldPathreason 字段的配置,可以更加方便使用。

其中 reason 字段可以传递给调用方的 HTTP status code,目前支持 FieldValueInvalid, FieldValueForbidden,FieldValueRequired, FieldValueDuplicate。如果未设置,默认使用 FieldValueInvalid

与之相关的,还有一个新增的 Alpha 特性 CRD Validation Ratcheting · Issue #4008 · kubernetes/enhancements

非优雅的节点关闭特性达到 GA

当一个节点被关闭但没有被 Kubelet 的 Node Shutdown Manager 检测到时,StatefulSet 的 Pod 将会停留在正在终止状态,并且不能移动到新运行的节点上。

这是因为关闭节点上的 Kubelet 不可用来删除 Pod ,所以 StatefulSet 无法创建具有相同名称的新 Pod 。如果 Pod 使用卷,则 VolumeAttachments 将不会从原始关闭节点中删除,因此这些 Pod 使用的卷将无法附加到新运行的节点上。

结果是,在 StatefulSet 上运行应用程序将无法正常工作。如果原始关闭节重新启动,则 Pods 将被 Kubelet 删除,并在不同运行中创建新 Pods 。如果原始关闭节没有重新启动,则这些 Pods 将永远停留在正在终止状态下。

所谓的非优雅关闭节点的特性就是一种处理未被 Kubelet 的 Node Shutdown Manager 检测到的情况下进行 node 关闭的方法。 在此情况下强制删除 pods ,触发 VolumeAttachments 的删除,并在健康 Node 中创建 pod ,以便应用程序可以继续正常工作。 类似地,在遇到硬件故障或破损操作系统等不可恢复状态时也可以采取此方法。

这个特性的 feature gate 是 NodeOutOfServiceVolumeDetach,在旧版本的 kube-controller-manager 也可以自行开启。

目前它还需要人工操作,可以执行如下操作:

1
kubectl taint nodes <node-name> node.kubernetes.io/out-of-service=nodeshutdown:NoExecute

这样非正常关闭的节点上的有状态应用的 Pod 只要没有匹配的容忍度,此污点将触发强制删除该节点上的 Pod。附加到关闭节点的持久卷将被分离,并且新的 Pod 将成功创建在另一个运行中的节点上。

这个特性还是很有用的。

其他

  • in-tree 的 Ceph RBD, Ceph FS 的插件都废弃了,并且没有迁移 CSI 的计划;
  • Sidecar container 的支持达到 alpha 级别;
  • PodResources API 达到 GA;
  • Node swap 特性达到 Beta, 这是从 v1.22 引入的;

Kubernetes v1.29

KEP-2876: 基于 CEL 的 CRD 规则校验正式达到 GA

这个特性对于所有在 Kubernetes 上进行开发的小伙伴来说应该都是非常重要的。 因为大多数情况下,我们都是通过 CRD 来实现 Kubernetes 中的功能扩展。

在通过 CRD 实现功能扩展的时候,为了能提供更好的用户体验,和更可靠的输入校验,就需要支持校验了。

CRD 目前原生支持两类校验能力:

  • 基于 CRD 结构定义的校验
  • OpenAPIv3 的校验规则

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.13.0
name: kongplugins.configuration.konghq.com
spec:
group: configuration.konghq.com
names:
categories:
- kong-ingress-controller
kind: KongPlugin
listKind: KongPluginList
plural: kongplugins
shortNames:
- kp
singular: kongplugin
scope: Namespaced
versions:
name: v1
schema:
openAPIV3Schema:
description: KongPlugin is the Schema for the kongplugins API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
protocols:
description: Protocols configures plugin to run on requests received on
specific protocols.
items:
description: KongProtocol is a valid Kong protocol. This alias is necessary
to deal with https://github.com/kubernetes-sigs/controller-tools/issues/342
enum:
- http
- https
- grpc
- grpcs
- tcp
- tls
- udp
type: string
type: array
type: object
...
x-kubernetes-validations:
- message: Using both config and configFrom fields is not allowed.
rule: '!(has(self.config) && has(self.configFrom))'
- message: Using both configFrom and configPatches fields is not allowed.
rule: '!(has(self.configFrom) && has(self.configPatches))'
- message: The plugin field is immutable
rule: self.plugin == oldSelf.plugin

以上示例中定义了一个名为 KongPlugin 的自定义资源,其中使用 openAPIV3Schema 定义了 OpenAPI schema 的校验规则。

但这些内置规则能达到的效果相对有限,如果想要实现更加丰富的校验规则/特性,则可以使用:

不过 无论是 Admission webhook 还是自定义验证器,它们与 CRD 自身都是分离的,并且这也会导致开发 CRD 的难度和后续的维护成本增加。

为了能解决这些问题,Kubernetes 社区为 CRD 引入了一种基于 CEL(Common Expression Language)的校验规则,这个规则是可以直接 在 CRD 的声明文件中编写的,无需使用任何 Admission webhook 或者自定义验证器,大大简化了 CRD 的开发和维护成本。

我从社区刚开始想要引入这个功能起就一直在文章中宣传该功能了,持续关注的小伙伴对这个应该不算陌生了。 我大概查看了以下文章中都有介绍 Kubernetes 中 CEL 相关特性的演进过程,感兴趣的小伙伴可以逐篇阅读:

在 Kubernetes v1.29 版本中基于 CEL 的 CRD 校验能力达到 GA,只需要使用 x-kubernetes-validations 定义校验规则即可, 它足够轻量且安全,可以直接在 kube-apiserver 中运行,我们来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.13.0
name: kongplugins.configuration.konghq.com
spec:
group: configuration.konghq.com
scope: Namespaced
versions:
name: v1
schema:
openAPIV3Schema:
description: KongPlugin is the Schema for the kongplugins API.
properties:
plugin:
...
x-kubernetes-validations:
- message: Using both config and configFrom fields is not allowed.
rule: '!(has(self.config) && has(self.configFrom))'
- message: The plugin field is immutable
rule: self.plugin == oldSelf.plugin

例如其中的这句 self.plugin == oldSelf.pluginselfoldSelf 代表了变化前后的资源对象, 一旦定义了 plugin 字段的内容,则不允许修改它。

此外,CEL 还有非常丰富的特性,可以通过在线的 Playground 来体验它 https://playcel.undistro.io/

正如我前面提到的,这个特性引入的时间已经两年多了,在 Kubernetes v1.25 中达到 Beta 并默认开启,如今终于达到了 GA。

额外一说,Kubernetes Gateway API 项目正在将它的所有 Admission webhook 删掉,全部使用基于 CEL 的规则进行校验, 这大概是目前社区中最大的一个用例了。

KEP-3668: 为动态和静态分配预留 NodePort 端口范围达到 stable

众所周知 Kubernetes 原生的 Service 对象有一种 NodePort 的类型,用于将集群内的服务暴露到集群外。

在当前情况下,如果用户想要新建一个 NodePort,并为它固定的指定一个 Port,其实是存在一定的风险的。 有可能指定的 Port 已经被分配出去了,这样就会冲突,导致 Service 创建失败。

这个 KEP 提出了为 NodePort 类型的 Services 动、静态地预留一段可选区间,并且支持两种方式进行 Port 配置:

  • 自动化地随机生成(由 Kubernetes 按照规则自动生成)
  • 手工设置(由用户根据需求自行设定)。

举个例子:

kube-apiserver 可以通过 --service-node-port-range 控制 NodePort 可以使用的端口范围,默认是 30000-32767。在这个 KEP 中引入的计算公式是:min(max($min, node-range-size/$step), $max) ,也就是说:

  • Service Node Port 范围: 30000-32767
  • 范围大小: 32767 - 30000 = 2767
  • Band Offset: min(max(16,2767/32),128) = min(86,128) = 86
  • Static band start: 30000
  • Static band ends: 30086

按照这种方式计算,也就是 30000-30086 作为 static 段,之后的作为 dynamic 段。

1
2
3
4
5
6
 ┌─────────────┬─────────────────────────────────────────────┐
│ static │ dynamic │
└─────────────┴─────────────────────────────────────────────┘

◄────────────► ◄────────────────────────────────────────────►
30000 30086 32767

如果用户想要自己指定一个 NodePort 的端口,若在 static 范围内,则相对来说不容易出现冲突。

不过,总体来说这个特性实际上是一个 Kubernetes 内部的特性,多数情况下只要记住一个原则:“手动指定 NodePort 时尽量选择在 static 范围(前段)内即可”。如果用户指定的 Port 在 dynamic 范围内,如果该 Port 尚未被分配,则也可以创建成功。

这种计算方式实际上是来自于 KEP-3070,用于给 Service 分配 ClusterIP 使用的。

KEP-753:SidecarContainers 特性达到 Beta 并默认启用

Sidecars 是一种辅助容器,它们能够给主容器添加额外功能。尽管这种模式在 Service Mesh 场景用例更多,但很多用户也会在非 Service Mesh 场景下使用,比如像日志记录、监控等场景。

但是之前 Sidecars 在这些场景中使用存在一些问题,比如当 Pod 删除的时候,由于 Sidecar 容器的生命周期管理的缺失,会导致这些服务和主容器的生命周期不同步,进而影响服务的可靠性。

这个 KEP 在 Pod 规范中将 Sidecar 容器定义为 init containers 的一部分,并且指定其具有“始终重启”策略。

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: moelove-pod
spec:
initContainers:
- name: log
image: moelove/fluentbit
restartPolicy: Always
...

在 Kubernetes v1.29 版本中该特性将默认启用,同时 Sidecar containers 的停止顺序将按照与它们启动时候相反的顺序来进行,这样一方面可以确保是主容器先停止的,另一方面也便于控制所有组件的生命周期。

KEP-3960: PreStop Hook 引入 Sleep 动作(Alpha)

这个 KEP 也比较有意思,主要是为了简化一个最常见的需求。

很多应用 Pod 在关闭的时候,需要断开连接,以免影响用户流量。所以很多时候会在关闭前设置 PreStop 来进行一些相关的处理或者等待。

但是当前的 PreStop Hook 只支持 exechttpGet 这两种,这个 KEP 是想要实现一种原生的 sleep 操作,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.25.3
lifecycle:
preStop:
sleep:
seconds: 5
readinessProbe:
httpGet:
path: /
port: 80

这样就可以很简单了。在引入这个 KEP 之前,需要设置为类似 exec sh -c "sleep 5" 这样,这需要容器内还包含 sleep 这个命令才行。

不过这个特性目前处于 Alpha,能否最终 GA 还需要看看社区的反馈。

KEP-4193:改善 service account token 绑定机制(Alpha)

在 Kubernetes 中,service account token 是保障安全性不可或缺的一环。它们用于验证集群中各个工作负载,并且可以防止未经授权访问。

Kubernetes v1.29 中进一步加强了对这些令牌的安全保护:现在每个 service account 仅能与特定 Pod 实例相关联,在外泄后也无法被滥用。这种方式有效地将 service account 和 Pod 生命周期捆绑在一起,大大减少了攻击者利用盗取 token 进行攻击的可能。

在 v1.29 中 kube-apiserver 有如下相关的 feature gates 可以控制相关的特性,当然除了 KEP-4193 外,这个版本中也推进了 KEP-2799,减少了基于 secret 的 service account token。这有助于缩短 Token 的有效时间,尽可能的减少攻击面。

1
2
3
4
5
LegacyServiceAccountTokenCleanUp=true|false (BETA - default=true)
ServiceAccountTokenJTI=true|false (ALPHA - default=false)
ServiceAccountTokenNodeBinding=true|false (ALPHA - default=false)
ServiceAccountTokenNodeBindingValidation=true|false (ALPHA - default=false)
ServiceAccountTokenPodNodeInfo=true|false (ALPHA - default=false)

KEP-727:Kubelet Resource Metrics 达到 GA

这是一个有很长历史的 KEP 了,从开始提出到现在 GA 用了 5 年的时间,中间也发生了很多有趣的事情。这次主要涉及的部分是如下 metrics:

  • container_cpu_usage_seconds_total
  • container_memory_working_set_bytes
  • container_start_time_seconds
  • node_cpu_usage_seconds_total
  • node_memory_working_set_bytes
  • pod_cpu_usage_seconds_total
  • pod_memory_working_set_bytes
  • resource_scrape_error

以下是一个示例的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# HELP container_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the container in core-seconds
# TYPE container_cpu_usage_seconds_total counter
container_cpu_usage_seconds_total{container="coredns",namespace="kube-system",pod="coredns-55968cc89d-bhhbx"} 0.195744 1691361886865
# HELP container_memory_working_set_bytes [STABLE] Current working set of the container in bytes
# TYPE container_memory_working_set_bytes gauge
container_memory_working_set_bytes{container="coredns",namespace="kube-system",pod="coredns-55968cc89d-bhhbx"} 1.675264e+07 1691361886865
# HELP container_start_time_seconds [STABLE] Start time of the container since unix epoch in seconds
# TYPE container_start_time_seconds gauge
container_start_time_seconds{container="coredns",namespace="kube-system",pod="coredns-55968cc89d-bhhbx"} 1.6913618235901163e+09 1691361823590
# HELP node_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the node in core-seconds
# TYPE node_cpu_usage_seconds_total counter
node_cpu_usage_seconds_total 514578.636 1691361887931
# HELP node_memory_working_set_bytes [STABLE] Current working set of the node in bytes
# TYPE node_memory_working_set_bytes gauge
node_memory_working_set_bytes 1.9501084672e+10 1691361887931
# HELP pod_cpu_usage_seconds_total [STABLE] Cumulative cpu time consumed by the pod in core-seconds
# TYPE pod_cpu_usage_seconds_total counter
pod_cpu_usage_seconds_total{namespace="kube-system",pod="coredns-55968cc89d-bhhbx"} 1.30598 1691361880003
# HELP pod_memory_working_set_bytes [STABLE] Current working set of the pod in bytes
# TYPE pod_memory_working_set_bytes gauge
pod_memory_working_set_bytes{namespace="kube-system",pod="coredns-55968cc89d-bhhbx"} 1.6715776e+07 1691361880003
# HELP resource_scrape_error [STABLE] 1 if there was an error while getting container metrics, 0 otherwise
# TYPE resource_scrape_error gauge
resource_scrape_error 0
# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
# TYPE scrape_error gauge
scrape_error 0

KEP-3466: Kubernetes Component Health SLIs 达到 GA

这个 KEP 的主要目的是为了让每个组件暴露它们自己的健康状态,以便于可以根据其健康状态的 SLI 计算集群的 SLO。

很久之前 Kubernetes 中存在一个 ComponentStatus,可以用于查看集群中组件的状态。但正如下方所示,在 v1.19 已经实际上废弃了。

1
2
3
4
5
6
moelove@k8s-test:~$ kubectl  get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
etcd-0 Healthy ok
controller-manager Healthy ok

我们期望能通过这个 KEP 使用各个组件的健康状态作为 SLI,采集聚合后,计算出集群的 SLO。进而可以给出 SLA。(关于它们之间的关系有兴趣的小伙伴可以搜索下相关内容)

以下是一个示例的输出:

1
2
3
4
5
6
7
8
9
10
11
tao@moelove:/$ kubectl get --raw "/metrics/slis"
# HELP kubernetes_healthcheck [STABLE] This metric records the result of a single healthcheck.
# TYPE kubernetes_healthcheck gauge
kubernetes_healthcheck{name="etcd",type="healthz"} 1
kubernetes_healthcheck{name="etcd",type="livez"} 1
kubernetes_healthcheck{name="etcd",type="readyz"} 1
kubernetes_healthcheck{name="etcd-readiness",type="readyz"} 1
kubernetes_healthcheck{name="informer-sync",type="readyz"} 1
kubernetes_healthcheck{name="ping",type="healthz"} 1
kubernetes_healthcheck{name="ping",type="livez"} 1
kubernetes_healthcheck{name="ping",type="readyz"} 1

已知问题

EventedPLEG 这个特性在 v1.27 中升级到了 Beta,但是在新版本的测试中发现了比较多的问题,所以现在将它默认禁用了,待社区修复后会再打开。建议在 v1.29 中先关闭此特性

其他

  • KEP-2495: PV/PVC ReadWriteOncePod 达到 GA
  • NodeExpandSecret 特性达到 GA
  • kube-proxy 有了个 nftables 的新后端