(一) 背景资料
对于Kubernetes来说,从架构设计上就是支持Docker和CoreOS rkt两种容器的,在1.2版本中,最低支持CoreOS rkt 0.13.0版本,这个rkt版本算是一个开发测试版本。CoreOS rkt在2016年正式发布了1.0,rkt从1.0开始算是一个正式生产版本了,Kubernetes在1.3中最低支持CoreOS rkt 1.9.1。由于Kubernetes支持了CoreOS rkt正式生产版本,也就意味着Kubernetes真正可以在生产环境中同时实现对Docker和CoreOS rkt的支持,所以把”在Kubernetes中使用rkt“又称作”rktnetes“,用来突出rkt在Kubernetes中的作用。
(二) CoreOS rkt同Docker对比
Docker需要有一个后台运行的Daemon,命令都是通过Docker Daemon进行执行,如果Daemon没有在后台运行,那么就无法执行Docker命令,而且应用容器的虚拟网络也可能会依赖于Daemon的虚拟网络。CoreOS rkt主要采用命令行直接执行,不需要后台运行的Daemon。
在对Docker进行升级时,至少需要升级Docker Engine daemon,如果应用容器的虚拟网络正在通过Docker Engine daemon进行通讯,那么此时应用容器上业务就会受到影响,但是对CoreOS rkt进行升级更新的时候,并不会影响已经运行的应用容器,但是因为应用容器的网络并不是通过Daemon的虚拟网络进行通讯的。
下面是CoreOS rkt同Docker处理模型对比图:
从图中可以看到:
1) 当在rkt1.0及以后版本上运行redis容器时,通过命令行执行一次类似“rkt run redis”的命令就可以启动application应用;
2) 当在Docker1.11以前版本运行redis容器时,执行类似“Docker run redis”的命令后,实际上是同Docker Engine进行通讯,由Docker Engine来启动application应用;
3) 当在Docker1.11及以后版本上运行redis容器时,执行类似“Docker run redis”的命令后,先同Docker Engine进行通讯,接着由Docker Engine同containerd进行通讯,然后由containerd同runC进行通讯,最后由runC来启动application应用。
根据对比至少可以分析出CoreOS rkt在启动的时候比Docker更简单,这种简单的好处在于遇到问题的时候可以快速的进行排查。同时还可以看出来,CoreOS rkt的这种设计更加遵循linux/unix架构的最佳实践,因为应用容器都是直接可以被操作系统systemd核心进程直接进行控制的,但是Docker中应用容器都是被Docker Engine这个进程控制的,操作系统systemd核心进程只是直接控制Docker Engine进程。
这里并不是说Docker架构设计不好,Docker采用Docker Engine这种中心化架构设计其实也是有优势的,其中包括这种设计更适合开发,因为Docker Engine提供了对外统一的API接口,所以开发人员直接可以使用这些API接口进行开发。
下面是CoreOS rkt同Docker在linux权限模型上的对比图:
从图中可以看到:
1) docker dasemon需要root用户权限,也就是说操作系统必须为Docker开放一个最高级别权限;
2) CoreOS rkt不需要root用户权限,可以完全按照linux/unix权限方案来使用;
根据对比可以可以分析出:CoreOS rkt设计上就是使用标准的linux/unix权限方案,可以利用linux/unix操作系统自带的权限方案在不同操作之间进行权限控制,但是Docker不是,因为Docker必须使用草系统最高级别权限。
(三) K8S中使用CoreOS rkt
1) 前置条件
2) 配置kubelet参数
3) Kubelet使用CoreOS rkt流程
4) CoreOS rkt限制
当创建POD时,如果挂载到POD中的路径在节点上不存在的时候,如果容器运行环境是rkt,那么会报错,但是如果容器运行环境是Docker的时候,会创建一个空目录,不会报错。比如按照下面配置文件来创建POD,如果容器运行环境是rkt,那么就会报错。
apiVersion: v1 kind: Pod metadata: labels: name: mount-dne name: mount-dne spec: volumes: - name: does-not-exist hostPath: path: /does/not/exist containers: - name: exit image: busybox command:["sh", "-c", "ls /test; sleep 60"] volumeMounts: - mountPath: /test name:does-not-exist
kubectl是操作kubernetes集群的命令行工具,kubectl语法如下:
kubectl [command] [TYPE] [NAME] [flags]
如果容器运行环境使用的是CoreOSrkt,那么下面kubectl参数是不被支持的:
• --attach=true
• --leave-stdin-open=true
• --rm=true
在kubernetes1.3的POD中,有两类容器,一类是系统容器(POD Container),一类是用户容器(User Container),在用户容器中,现在又分成两类容器,一类是初始化容器(Init Container),一类是应用容器(App Container),其中应用容器包含卷容器(Volume Container)。POD同初始化容器之间的对应关系是从0到N,POD同应用容器之间的对应关系是从1到N。
如果使用的是CoreOSrkt容器运行环境,那么是无法使用kubernetes1.3的初始化容器这个新功能的。
在kubernetes1.3中提供了对Nvidia品牌GPU的支持,在kubernetes管理的集群中每个节点上,通过将原有的Capacity和Allocatable变量进行扩展,增加了一个针对Nvidia品牌GPU的α特性:alpha.kubernetes.io/nvidia-gpu。其中Capacity变量表示每个节点中实际的资源容量,包括cpu、memory、storage、alpha.kubernetes.io/nvidia-gpu,而Allocatable变量表示每个节点中已经分配的资源容量,同样包括包括cpu、memory、storage、alpha.kubernetes.io/nvidia-gpu。
如果使用的是CoreOSrkt容器运行环境,那么是无法使用kubernetes1.3对Nvidia品牌GPU支持这个新功能的。
对于kubernetes来说,如果容器运行环境使用的是Docker,那么通过cgroup就可以给POD设置QoS级别,当资源不够使用时,先kill优先级低的POD,在实际使用时,是通过OOM(Out of Memory)分数值来实现的,OOM分数值从0到1000。OOM分数值是根据OOM_ADJ参数计算出来的,对于Guaranteed级别的POD,OOM_ADJ参数设置成了-998,对于BestEffort级别的POD,OOM_ADJ参数设置成了1000,对于Burstable级别的POD,OOM_ADJ参数取值从2到999,对于kube保留的资源,比如kubelet,OOM_ADJ参数设置成了-999。OOM_ADJ参数设置的越大,通过OOM_ADJ参数计算出来的OOM分数越高,OOM分数越高,这个POD的优先级就越低,在出现资源竞争的时候,就越早被kill掉,对于OOM_ADJ参数是-999的代表kubernetes永远不会因为OOM而被kill掉。如下图所示:
如果使用的是CoreOSrkt容器运行环境,那么就不会对OOM(Out of Memory)分数值进行调整。
(四) rktnetes总结
在kubernete1.3中,把”在Kubernetes中使用rkt“又称作”rktnetes“,用来突出rkt在Kubernetes中的作用,可以推断出在kubernetes开源项目发展过程中CoreOS团队起到了很重要的作用。在Docker1.12版本以后融合入swarm编排功能后,kubernetes更需要一个纯粹的容器运行环境来支撑,而CoreOS rkt就是一个专注性强的容器运行环境,并不涉及集群编排和节点管理,所以在1.13版本中突出了一个单词”rktnetes“很有象征意义。
不可否认,CoreOS rkt是按照unix/linux使用最佳实践来架构设计的,所以就像是在前面“CoreOS rkt同Docker对比“中介绍过的那样,rktnetes具有下面两项优势: