本文讨论 K8S 1.3 的一些新功能,以及正在进行中的功能。读者应该对 kubernetes 的基本结构已经有所了解。html
1 Init containernode
Init container 是1.3 中的 alpha feature,目的是支持一类须要在启动 Pod“普通容器”前,先进行 Pod 初始化的应用。执行该初始化任务的容器被成为“初始化容器”(init container)。例如,在启动应用以前,初始化数据库,或等待数据库启动等。下图是一个包含 init container 的 Pod:nginx
对于此类 Pod,kubernetes 的运行策略以下:git
初始化容器按顺序依次执行,即图中容器 1->2github
若其中某一个初始化容器运行失败,则整个 Pod 失败web
当全部初始化容器运行成功,启动普通容器,即图中容器 A 和 B数据库
在 alpha 版本中使用 init container 须要用 annotation,下图是来自 k8s 的一个例子(略有裁剪):后端
能够看到,咱们在启动 nginx 普通容器以前,先用 init container 来获取 index.html,以后访问 nginx 就会直接返回该文件。当 init container 功能稳定后,k8s 会直接在 pod.spec 内加上 init Containers 字段,以下所示:api
init container 看起来是一个小功能,可是在实现上仍是须要考虑很多问题,好比几个比较重要的点:安全
资源问题:当调度存在 init container 的 Pod 时,应该怎样计算所须要的资源?两个极端状况:若是对 init container 和 regular container 所须要的资源求和,那么当 init container 成功初始化 Pod 以后,就不会再使用所请求的资源,而系统认为在使用,会形成浪费;反之,不计算 init container 的资源又会致使系统不稳定(init container 所使用的资源未被算入调度资源内)。目前的方法是取折中:因为初始化容器和普通容器不会同时运行,所以 Pod 的资源请求是二者中的最大值。对于初始化容器,因为他们是依次运行,所以选择其中的最大值;对于普通容器,因为是同时运行,选择容器资源的和。
Pod Status: 目前,Pod 有 Pending, Running, Terminating 等状态。对于有初始化容器的 Pod,若是仍然使用 Pending 状态,则很难区分 Pod 当前在运行初始化容器仍是普通容器。所以,理想状况下,咱们须要增长一个相似于 Initializing 的状态。在 alpha 版本中暂时还未添加。
健康检查及可用性检查:有了 init container 以后,咱们该如何检查容器的健康状态?alpha 版本将两个检查都关闭了,但 init container 是会在 node 上实实在在运行的容器,理论上是须要进行检查的。对于可用性检查,关闭掉是一个可行的办法,由于 init container 的可用性其实就是当它运行结束的时候。对于健康检查,node 须要知道某个 Pod 是否处在初始化阶段;若是处在初始化阶段,那么 node 就能够对 init container 进行健康检查。所以,kubernetes 颇有可能在添加相似 Initializing 的 Pod 状态以后,开启 init container 的健康检查。
围绕 init container 的问题还有不少,好比 QoS,Pod 的更新等等,其中很多都是有待解决的问题,这里就不一一展开了 :)
2 PetSet
PetSet 应该算是社区期待已久的功能,其目的是支持有状态和集群化的应用,目前也是 alpha 阶段。PetSet 的应用场景不少,包括相似 zookeeper、etcd 之类的 quorum leader election 应用,相似 Cassandra 的 Decentralized quorum 等。PetSet 中,每一个 Pod 都有惟一的身份,分别包括:名字,网络和存储;并由新的组件 PetSet Controller 负责建立和维护。下面依次看一看 kubernetes 是如何维护 Pod 的惟一身份。
名字比较容易理解,当咱们建立一个 RC 以后,kubernetes 会建立指定副本数量的 Pod,当使用 kubectl 获取 Pod 信息时,咱们会获得以下信息:
其中,5 个字符的后缀为 kubernetes 自动生成。当 Pod 重启,咱们会获得不一样的名字。对于 PetSet 来说,Pod 重启必须保证名字不变。所以,PetSet 控制器会维护一个 identityMap,每个 PetSet 中的每一个 Pod 都会有一个惟一名字,当 Pod 重启,PetSet 控制器能够感知到是哪一个 Pod,而后通知 API server 建立新的同名 Pod。目前的感知方法很简单,PetSet 控制器维护的 identityMap 将 Pod 从 0 开始进行编号,而后同步的过程就像报数同样,哪一个编号不在就重启哪一个编号。
此外,该编号还有另一个做用,PetSet 控制器经过编号来确保 Pod 启动顺序,只有 0 号 Pod 启动以后,才能启动 1 号 Pod。
网络身份的维护主要经过稳定的 hostname 和 domain name 来维护,他们经过 PetSet 的配置文件指定。例如,下图是一个 PetSet 的 Yaml 文件(有裁剪),其中 metadata.name 指定了 Pod 的 hostname 前缀(后缀即前面提到的从 0 开始的索引),spec.ServiceName 指定了 domain name。
经过上面的 Yaml 文件建立出来两个 Pod:web-0 和 web-1。其完整的域名为 web-0.nginx.default.svc.cluster.local,其中 web-0 为 hostname,nginx 为 Yaml 中指定的 domain name,剩下的部分与普通 service 无异。当建立请求被下发到节点上时,kubelet 会经过 container runtime 设置 UTS namespace,以下图所示(省略了部分组件如 apiserver)。
此时,hostname 已经在容器层面设置完成,剩下还须要为 hostname 增长集群层面的解析,以及添加 domain name 的解析,这部分工做理所固然就交给了 kube dns。了解 Kubernetes 的读者应该知道,要添加解析,咱们须要建立 service;同理,这里也须要为 PetSet 建立 service。不一样的是,普通的 service 默认后端的 Pod 是可替换的,并采用诸如 roundrobin,client ip 的方式选择后端的 Pod,这里,因为每一个 Pod 都是一个 Pet,咱们须要定位每个 Pod,所以,咱们建立的 service 必需要能知足这个要求。在 PetSet 中,利用了 kubernetes headless service。Headless service 不会分配 cluster IP 来 load balance 后端的 Pod,但会在集群 DNS 服务器中添加记录:建立者须要本身去利用这些记录。下图是咱们须要建立的 headless service,注意其中的 clusterIP 被设置为 None,代表这是一个 headless service。
Kube dns 进行一番处理以后,会生成以下的记录:
能够看到,访问 web-0.nginx.default.svc.cluster.local 会返回 pod IP,访问 nginx.default.svc.cluster.local 会返回全部 Pet 中的 pods IP。一个常见的方式是经过访问 domain 的方式来获取全部的 peers,而后依次和单独的 Pod 通讯。
存储身份这块采用的是 PV/PVC 实现,当咱们建立 PetSet 时,须要指定分配给 Pet 的数据卷,以下图:
这里,volumeClaimTemplates 指定每一个 Pet 须要的存储资源。注意目前全部 Pet 都获得相同大小和类型的数据卷。当 PetSet 控制器拿到请求时,会为每个 Pet 建立 PVC,而后将每一个 Pet 和对应的 PVC 联系起来:
以后的 PetSet 只须要确保每一个 Pet 都与相对应的 PVC 绑定在一块儿便可,其余工做,相似于建立数据卷,挂载等工做,都交给其余组件。
经过名字,网络,存储,PetSet 可以 cover 大多数的案例。可是,目前还存在不少须要完善的地方,感兴趣的读者能够参考:https://github.com/kubernetes/kubernetes/issues/28718
3 Scheduled Job
Scheduled Job 本质上是集群 cron,相似 mesos chronos,采用标准的 cron 语法。遗憾的是在 1.3 中还并未达到发布的标准。Scheduled Job 其实在很早就提出来过,但当时 kubernetes 的重点还在 API 层面,而且即便有很大需求,也计划在 Job(1.2GA)以后实现。当 scheduled job 在以后的版本发布以后,用户能够用一条简单的命令在 kubernetes 上运行 Job,例如:kubectl run cleanup -image=cleanup --runAt="0 1 0 0 *" -- /scripts/cleanup.sh一些关于 scheduled job 的更新能够参考:https://github.com/kubernetes/kubernetes/pull/25595
4 Disruption Budget
Disruption Budget 的提出是为了向 Pod 提供一个反馈机制,确保应用不会被集群自身的变更而受影响。例如,当集群须要进行重调度时,应用能够经过 Disruption Budget 来讲明 Pod 能不能被迁移。Disruption Budget 只负责集群自身发起的变更,不负责突发事件好比节点忽然掉线,或者应用自己的问题好比不断重启的变更。Disruption Budget 一样没有在 1.3 中发布。
与 kubernetes 大多数资源相似,咱们须要经过 Yaml 文件建立一个 PodDisruptionBudget 资源,例如,下图所示的 Disruption Budget 选中了全部带有 app:nginx 标签的 pod,而且要求至少有 3 个 Pod 在同时运行。
Controller manager 内有一个新的组件 Disruption Budget Controller,来负责维护全部 Budget 的状态,例如上图中的 status 代表当前共有 4 个健康的 Pod(currentHealthy),应用要求至少有 3 个(desiredHealthy),总共有 5 个Pod(expectedPods)。为了维护这个状态,Disruption Budget Controller 会遍历全部的 Budget 和全部的 Pod。有了 Budget 的状态,须要改变 Pod 状态的组件都要先查询之。若其操做致使最小可用数低于应用要求,则操做会被拒绝。Disruption Budget 与 QoS 联系很紧密。例如,若是一个 QoS level 很低的应用有着很是严格的 Disruption Budget,系统应该如何处理?目前,kubernetes 尚未严格的处理这个问题,一个可行的办法是对 Disruption Budget 作优先级处理,确保高优先级的应用拥有高优先级的 Disruption Budget;此外,Disruption Budget 能够加入 Quota 系统,高优先级的应用能够得到更多 Disruption Budget Quota。关于 Disruption Budget 的讨论能够参考:https://github.com/kubernetes/kubernetes/issues/12611
1 Cascading Deletion
在 kubernetes 1.2 以前,删除控制单元都不会删除底层的资源。例如,经过 API 删除 RC 以后,其管理的 Pod 不会被删除(使用 kubectl 能够删除,但 kubectl 里面有 reaper 逻辑,会依次删除底层的全部 Pod,本质上是客户端逻辑)。另一个例子,当删除下图中的 Deployment 时,ReplicaSet 不会被自动删除,固然,Pod 也不会被回收。
Cascading deletion 指的就是在删除控制单元后,将被管理单元也同时回收。可是,kubernetes 1.3 中的 cascading deletion 并非简单地讲 kubectl 中的逻辑复制到 server 端,而是作了更高层次的工做:垃圾回收。简单来说,garbagecollector controller 维护了几乎全部集群资源的列表,并接收资源修改的事件。controller 根据事件类型更新资源关系图,并将受影响的资源放入 Dirty Queue 或者 Orphan Queue 中。具体实现能够参考官方文档和 garbage collector controller 实现:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/garbage-collection.md
2 Node eviction
Node/kubelet eviction 指的是在节点将要超负荷以前,提早将 Pod 剔除出去的过程,主要是为了内存和磁盘资源。在 kubernetes 1.3 以前,kubelet 不会“提早”感知节点的负荷,只会对已知的问题进行处理。当内存吃紧时,kubernetes 依靠内核 OOM killer;磁盘方面则按期对 image 和 container 进行垃圾回收。可是,这种方式有局限性,OOM killer 自己须要消耗必定资源,而且时间上有不肯定性;回收容器和镜像不能处理容器写日志的问题:若是应用不断写日志,则会消耗掉全部磁盘,但不会被 kubelet 处理。
Node eviction 经过配置 kubelet 解决了以上问题。当启动 kubelet 时,咱们经过指定 memory.available, nodefs.available, nodefs.inodesFree 等参数来确保节点稳定工做。例如,memory.available < 200Mi 表示当内存少于 200Mi时,kubelet 须要开始移除 Pod(能够配置为当即移除或者延迟移除,即 hard vs soft)。kubernetes 1.3 中,node eviction 的特性是 opt-in,默认关闭,能够经过配置 kubelet 打开相关功能。
尽管 node eviction 是 kubelet 层面采起的措施,咱们也必须考虑与整个集群的交互关系。其中最重要的一点是如何将这个问题反馈给 scheduler,否则被剔除的 Pod 颇有可能会被从新调度回来。为此,kubernetes 添加了新的 node condition:MemoryPressure, DiskPressure。当节点的状态包含其中任意一种时,调度器会避免往该节点调度新的 Pod。这里还有另一个问题,即若是节点的资源使用恰好在阈值附近,那么节点的状态可能会在 Pressure 和 Not Pressure 之间抖动。防抖动的方法有不少种,例如平滑滤波,即将历史数据也考虑在内,加权求值。k8s 目前采用较为简单的方法:即若是节点处于 Pressure 状态,为了转变成 Not Pressure 状态,资源使用状况必须低于阈值一段时间(默认 5 分钟)。这种方法会致使 false alarm,好比,若一个应用每隔一段时间请求一块内存,以后很快释放掉,那么可能会致使节点一直处于 Pressure 状态。但大多数状况下,该方法能处理抖动的状况。
说到 eviction pod,那么另一个不得不考虑的问题就是找一个倒霉的 Pod。这里 kubernetes 定义了很多规则,总结下来主要是两点:1. 根据 QoS 来判断,QoS 低的应用先考虑;2. 根据使用量判断,使用量与总请求量比例大的 Pod 优先考虑。具体细节能够参考:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/kubelet-eviction.md
3 Network Policy
Network policy 的目的是提供 Pod 之间的隔离,用户能够定义任意 Pod 之间的通讯规则,粒度为端口。例如,下图的规则能够解释成:拥有标签“db”的 Pod,只能被拥有标签“frontend”的 Pod 访问,且只能访问 tcp 端口 6379。
Network policy 目前处于 beta 版本,而且只是 API。也就是说,kubernetes 不会真正实现网络隔离:若是咱们将上述 Yaml 文件提交到 kubernetes,并不会有任何反馈,kubernetes 只是保存了这个 Policy 内容。真正实现 policy 功能须要其余组件,好比 calico 实现了一个 controller,会读取用户建立的 Policy 来实现隔离,能够参考:https://github.com/projectcalico/k8s-policy/。关于 Network Policy 的细节,能够参考:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/network-policy.md
4 Federation
Federation cluster 翻译成中文叫“联合集群”,即将多个 kubernetes 集群联合成一个总体,而且不改变原始 kubernetes 集群的工做方式。根据 kubernetes 官方设计文档,federation 的设计目的主要是知足服务高可用,混合云等需求。在 1.3 版本以前,kubernetes 实现了 federation-lite,即一个集群中的机器能够来自于相同 cloud 的不一样 zone;1.3 版本中,federation-full 的支持已是 beta 版本,即每一个集群来自不一样的 cloud(或相同)。
Federation的核心组件主要是 federation-apiserver 和 federation-controller-manager,以 Pod 形式运行在其中一个集群中。以下图所示,外部请求直接与 Federation Control Panel 通讯,由 Federation 分析请求并发送至 kubernetes 集群。
在应用层面,Federation 目前支持 federated services,即一个应用跨多个集群的访问,具体细节能够参考:http://blog.kubernetes.io/2016/07/cross-cluster-services.html 以及http://kubernetes.io/docs/admin/federation/
kubernetes 1.3 带来了很是多的特性,这里只 cover 了其中一部分。在安全方面,kubernetes 已经支持 RBAC,实现更好的权限控制;PodSecurityContext 也进入 beta 版本,支持运行部分须要特权的 Pod 等。在性能方面,因为 protocol buffere serialization 的引入,是性能提升了几倍,而且正在酝酿中的 etcd3 会将性能提高更进一步。相信以后的版本会带给咱们更多的惊喜。