
kubernete编排技术一:pod
作者 | 朱晋君
来源 | 君哥聊技术(ID:gh_1f109b82d301)
在之前的文章《kubernete中的原子调度单位:pod》中提到过,如果把kubernete比作linux操作系统,那pod就是虚拟机,pod里面的容器就是虚拟机上的进程。这个类比可以说非常形象。在Linux上,进程并不是完全独立的,一些进程之间存在着一些关联,比如一个springboot应用和一个日志收集服务。pod正是使用了容器进程之间的这些关系,做的编排。
在kubernete上创建pod
下面的yaml文件springboot-mybatis.yaml定义了一个参数replicas: 2,这个参数的意思就是创建2个pod,image: zjj2006forever/springboot-mybatis:1.2则定义了pod中运行这容器的镜像。
执行下面命令这两个pod就被创建出来
我们用命令可以查看到
pod的本质
pod是一个逻辑上的概念,不是一个物理存在。pod的本质是有关联关系的一组容器调度在一起,这些容器可以共享linux的networknamespace和volume。那为什么需要pod呢?
我们举一个例子,假如我们有3个容器,container1是一个springboot应用,container2负责收集container1的日志,container3负责对container2的日志进行分析处理。我们如果想把这3个容器部署在同一个node上,每个容器需要分配1G的内存。
但我们目前有2个node,node1有2.5G内存,node2有3G内存,如果没有pod的逻辑存在,container1和container2调度到了node1上,但是container3调度到node1上时发现内存不够而失败了。如果我们有了pod,我们把这3个容器编排在一个pod里面,pod会直接被调度到3G内存的node2上。
pod里面的容器是怎么共享namespace的?在之前的文章《浅谈kubernete中的flannel网络插件》文章中介绍过,pod中有一个infra的容器,在pod创建时这个容器总是第一个被创建。这个容器镜像使用的是k8s.gcr.io/pause,占用空间非常小,解压后也就100多k。在pod启动时,先创建出这个infra容器,用这个容器控制住networknamespace,这样其他容器启动时共享这个网络就可以了。
pod里面的容器是怎么共享volume?还是上面3个容器的例子,我们编写一个yaml文件,代码如下:
上面的yaml文件中,我们定义了3个container,分别是应用容器spingboot-mybatis,日志收集spingboot-log-accumulate,日志分析spingboot-log-analysis,从上面的文件定义中我们可以看到,这3个容器都挂载了boot-log这个volum,对应宿主机目录/tmp/boot-log,本质上就是/tmp/boot-log这个目录被绑定在了上面3个容器中,这样上面3个容器就可以通过这个目录访问其他容器的绑定目录了。即spingboot-log-accumulate可以访问spingboot-mybatis的/logs,spingboot-log-analysis可以访问spingboot-log-accumulate的/accumulate。
所以:容器的本质其实是一组共享了networknamespace和volume的容器的集合。
pod的关键属性
pod是kubernete中最小的调度单位。在kubernete中,调度、网络、存储以及安全等属性,都是pod级别的。下面看一下pod的几个重要属性
1.shareProcessNamespace代表pod内容器共享pid namespace,hostNetwork代表共享宿主机网络
2.NodeSelector代表绑定宿主机标签,宿主机标签可以用下面命令查看
beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker1,kubernetes.io/os=linux
3.hostAliases定义了host文件,上面yaml文件创建pod后,pod内的hosts文件会增加内容如下:
4.ImagePullPolicy
Always:默认,创建pod是总是拉取镜像
Never:从不拉取
IfNotPresent:宿主机上不存在镜像时拉取
5.lifecycle:它是一个hook,在容器发生变化是触发一个事件。
postStart表示容器启动时触发一个操作,容器启动时立即触发,不等容器启动完成
preStop表示在容器被杀死之前触发一个操作,触发这个操作结束后才执行杀死容器的动作,比如这里可以触发eureka优雅发布。
注:
pod的生命周期状态主要有以下几种
- Pending:创建不成功
- Running:pod创建成功,并且里面至少一个容器在运行中
- Succeeded:pod中容器运行完毕正常退出
- Failed:pod里至少一个容器创建不成功
- Unknown:异常
pod的健康检查
修改之前部署springboot的yaml文件如下:
启动pod
查看容器状态:
下面这句可以看出,失败了3次,从上面的Events中也可以看出这个被删除重新创建的过程
pod健康检查失败后默认会重启pod,所以这时查看pod状态,发现重启了4次
注意:
1.kubernete中pod的restartPolicy默认是Always,即只要容器status不是RUNNING,就自动重启容器。除此之外,还有OnFailure(只有容器异常时才自动重启)和Never(从来不重启容器)。
2.在一个有多个容器的pod中,只有所有的容器都不是RUNNING状态时,pod才会执行restartPolicy,否则pod状态一直是RUNNING
3.livenessProbe有多种方式,比如http,tcp,也可以在容器中执行命令来判断
4.在我们定义的yaml文件中,我们定义了kind: Deployment,如果我们定义了kind: pod,那就只能在当前宿主机重启pod,这样如果当前宿主机故障,就会一直调度失败。但是kind: Deployment这种方式是可以调度到其他宿主机节点上的。
总结
pod是kubernete中最重要的概念,把pod类比成操作系统上的虚拟机、pod中的容器类比成虚拟机上运行的进程,是非常恰当的。kubernete强大的编排功能,原子单位是pod,pod是kubernete中的原子编排和调度对象。
