核心负载 API 升级为 GA

Tags: 

DaemonSet、Deployment、ReplicaSet 以及 StatefulSet 升级为 GA。

很高兴核心 Workload API 在 Kubernetes 1.9 中升级为 GA。本文来自 Kenneth Owens,讲述了核心负载对象如何从诞生走入 GA,回顾 1.9 中的变化,并对未来进行展望。

起初

Pods(注 1)将容器紧密结合在一起,共享资源、网络、存储以及生命周期。Pod 很有用,但是更进一步,用户希望无缝的、可重复的以及自动的创建同一个 Pod 的多个副本,所以我们有了 ReplicationController(注 2)

Replication 是一个进步,但是用户真正需要的是对 Pod 副本的高级编排能力。他们需要滚动更新。所以 OpenShift 团队开发了 DeploymentConfig(注 3),DeploymentConfig 很好用,OpenShift 用户很喜欢。为了让所有开源 Kubernetes 用户也能享受这一福利,并利用好标签选择器(注 4)ReplicaSet(注 5)Deployment(注 6)被纳入extensions/v1beta1,为所有用户提供提供滚动更新、回滚、Roll Over(在当前滚动更新未完成的情况下,如果接收新的滚动更新指令,则跨越当前指令)的能力。

这样几乎就解决了 Kubernetes 中对 12 要素应用中对容器化编排的需要。因此社区的注意力就转移到不同的问题上。集群里面,复制 N 多个 Pod 并不是万能钥匙。有时候,我们需要一个 Pod 在每个节点,或者某个节点集合上(例如用于运行日志或者指标收集任务的 Sidecar,Kubernetes 插件,以及分布式文件系统等)。可以使用 NodeSelector 或者静态 Pod 来实现,但这很不自然。习惯使用自动化程度较高的 Deployment 之后,用户需要对这样的应用也提供 Deployment 一样的支持。所以 DaemonSet(注 7)extension/v1beta1中应运而生。

再一次让用户满意,好景不长,用户们的编排需求超出了 12 要素和集群的基础设施能力。不论你的架构是 N-层的、面向服务的、还是微服务的,12 要素应用都依赖于有状态的工作负载(例如 RDBMS、分布式键值数据库以及消息队列)来为用户或其他应用提供服务。这些有状态应用必须通过分布的方式来满足对可用性和持久性的要求,用户希望在 Kubernetes 加入这一类型的支持,从而获得对整个应用栈的支撑能力。

无状态负载使用 Deployment 的方式运行得非常好,但他也无法保障对分布式系统能做出同样力度的支持。这些应用需要稳定的网络标识、有序的部署、更新以及删除操作,当然还有持久的存储。因此在apps/v1beta1中出现了 PetSet(注 8),用于为此类应用提供运行能力。不幸的是,这名字有些考虑不周(注 9),因此最终改名为 StatefulSet(注 10)

到这,我们就都搞定了——是吧?

Kubernetes 1.8 和 apps/v1beta2

Pod、ReplicationController、ReplicaSet、Deployment、DaemonSet 以及 StatefulSet,这许多对象一起被称为核心负载 API。我们现在总算可以编排所有东西了,但他们的 API 分散在三个不同的分组中,很是矛盾,也让用户产生了一些对于一致性和稳定性方面的担忧。

Pod 和 ReplicationController 处于 GA 状态。可以使用 Pod 运行工作负载,他们是核心中的原子要素。Deployment 是推荐的运行无状态应用的方式,转向 ReplicationController 没有什么意义。在 Kubernetes 1.8 中,我们把所有的核心工作负载 API 类型(DaemonSet、Deployment、ReplicaSet、以及 StatefulSet)合并到apps/v1beta2之中。这样在 API 接口中就更好的进行了聚合,并让我们可以打破向前兼容的能力,提高了一致性。我们的计划是把这些东西进一步完善,从而升级到 GA。过程中的修改,在apps/v1中有体现,下面会提到。

缺省标签选择器被弃用

以前版本的 apps 和 extension 组中,核心工作 API 类型的对象中如果没有指定标签选择器,会从模板标签中生成。

这一行为和 kubectl 的 apply 和 patch 行为是完全背道而驰的。而且我们认为,从一个字段中获取值,赋给另一个字段,是一种反模式行为,有时会对编排工作造成安全隐患。

可变选择器

选择器突变,能够支持一些特殊的用例,比如可升级的金丝雀部署,但是这一情况在工作负载控制器中的处理并不完善,所以我们一直强烈建议用户不要这样做(注 10)。为提供一个稳定、可用、一致的 API,选择器的可变性在所有的工作负载 API 中得以实现。

我们认为一定有更好的方式来支持这些特定的用例,但是如果这一方法能够满足用户的需要,我们可以在不破坏向后兼容性的情况下允许这一情况的发生。

对于可升级金丝雀、Pod 重标签以及选择器的变更特性都是由用户需求驱动的。如果你目前正在修改核心工作负载对象的选择器,请使用 Github Issue 告知我们你的案例、或者参与 Apps SIG。

缺省滚动更新

apps/v1beta2之前,有些对象的缺省更新策略并不是RollingUpdate(例如 apps/v1beta1/StatefulSet的缺省策略是OnDelete)。我们希望在有足够自信之后才把这一策略设置为缺省,另外因为对向后兼容的承诺,我们不能在既有版本上进行这一变更。在apps/v1beta2中我们将RollingUpdate设置为所有核心工作负载 API 对象的缺省更新策略。

注解CreatedBy过期

kubernetes.io/created-by是一个 GC 之前的历史残留。用户要从对象的ControlllerRef来判断该对象的属主。在 1.8 中我们设置这一特性为Deprecated,1.9 中进行了删除。

Scale 子资源

所有的apps/v1beta2都加入了 Scale 子资源(DaemonSet 的 Scale 是基于节点选择器的)。

Kubernetes 1.9 和 apps/v1

按照 Kubernetes 1.9 的计划,我们将所有核心工作负载 API 升级为apps/v1。虽然做了不少改变来保持 API 的一致性,但apps/v1基本上和apps/v1beta2是一致的。事实上绝大多数用户会把核心工作负载的 Beta 版当做 GA 来看待。担心DaemonSetDeployment以及StatefulSet的稳定性,依然在坚持使用 ReplicaController 的用户,是时候考虑把工作负载迁移到apps/v1中了。这次升级中的一些显著变化包括以下一些内容。

垃圾收集的缺省策略:删除

apps/v1之前,DaemonSetDeploymentReplicaSetStatefulSet的垃圾收集,只是把Pod进行孤立。这样如果在没有指定级联删除的情况下,删除这样的对象,他的下属 Pod 不会自动删除。如果你使用的是 Kubectl,由于这类对象在删除之前首先会进行缩减副本数到 0 的操作,你可能不会注意到这样的情况。在apps/v1中,这类对象的删除缺省就会触发 Pod 的删除。这一变更对多数用户来说都是透明的。

Condition

apps/v1之前,只有DeploymentReplicaSetStatus对象具有Condition,而所谓一致性,就是要么都有,要么全无。经过一番讨论之后,我们确定这一数据是有用的,所以将其加入StatefulSetStatus以及DaemonSetStatusStatefulSetDaemonSet的控制器目前并不会处理Condition,未来我们可能会以此和客户端进行交互。

Scale 子资源迁移到autoscale/v1

之前我们将 scale 子资源加入到apps API 组中。在集成autoscaling的时候我们意识到了这一做法的问题。我们需要使用自定义指标对StatefulSet进行自动伸缩。所以现在apps/v1对象使用了autoscaling/v1中的scale子资源。

迁移和弃用

用户最可能问的问题可能是:“迁移到apps/v1应该怎么做?投入如何?”在 Kubernetes 1.9 中所有的apps/v1之前的东西都已经启用了,所有的新代码都应该转向apps/v1,但是正如上文讨论的,很多用户将extensions/v1beta1作为 GA 版本在使用,根据弃用策略(注 10)的时间线,会做出最小支持。

未来的发布中,在移除任何 API 组版本之前,首先会在 API Server 中禁止,这种情况下,只要显式的打开这一开关,就可以继续使用这一组 API。还可以提供工具来把 API 对象升级为apps/v1。所有版本的核心工作负载对象都是可以双向转换的。如果想要手工进行转换,可以使用kubectl convert(注 11)在不同 Group 版本之间进行转换。

下一步

核心工作负载 API 现在已经稳定了,但这始终是一个软件,软件是永远不会结束的。我们会经常为稳定 API 中加入特性来满足新的需求,这一部分也不会例外。GA 的稳定性意味着所有的新功能都需要严格的向后兼容,这是一个不容破坏的承诺。如果想要参与这一部分 API 的工作,可以留意我们的 Github(注 12) 或者 SIG Apps(注 13)

注释

  1. https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/
  2. https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/
  3. https://docs.openshift.org/latest/architecture/core_concepts/deployments.html#deployments-and-deployment-configurations
  4. https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
  5. https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
  6. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
  7. https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
  8. https://kubernetes.io/docs/tasks/run-application/upgrade-pet-set-to-stateful-set/
  9. https://github.com/kubernetes/kubernetes/issues/27430
  10. https://kubernetes.io/docs/reference/deprecation-policy/
  11. https://kubernetes.io/docs/user-guide/kubectl/v1.7/#convert
  12. https://github.com/kubernetes/kubernetes
  13. https://github.com/kubernetes/community/tree/master/sig-apps