k8s系列文章:html
Pod是k8s中最小的调度单元,包含了一个“根容器”和其它用户业务容器。node
若是你使用过k8s的话,固然会了解pod的基本使用,可是为了更好的应用,你须要深刻了解pod的配置、调度、升级和扩缩容等。本文将会更进一步的介绍pod。nginx
为何须要pod?docker
pod包含一个或多个相对紧密耦合的容器,处于同一个pod中的容器共享一样的存储空间、IP地址和Port端口。后端
为何k8s要设计出Pod这个概念并做为最小调度单元呢?api
直接部署一个容器可能会更加容易,每一个容器都有不一样的配置和功能,k8s须要对这些容器进行管理(重启、检测等),那么为了不在容器这个实体上增长更多的属性,就产生了pod这个概念。app
而且,Pod中的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器的通讯问题,也很好的解决了它们之间的文件共享问题。ide
容器配置性能
pod能够由一个或多个容器组合而成,也就是说, 在建立pod时能够给一个pod配置多个container,通常状况下,建议将应用紧耦合的容器打包为一个pod,原则上一个容器一个进程。设计
共享Volume
同一个pod中的多个容器可以共享pod级别的存储卷Volume,多个容器各自挂载,将一个volume挂载为容器内部须要的目录。
Pod通讯
k8s为每一个pod都分配了惟一的IP地址,称之为pod IP,一个pod中的多个容器共享Pod IP地址,属于同一个pod的多个应用之间相互访问时仅经过localhost就能够通讯。
k8s底层支持集群内任意两个pod之间的TCP/IP直接通讯,所以,在k8s中,一个pod中的容器能够与另外主机上的pod里的容器直接通讯。
容器限制
须要注意的是:pod中长时间运行的容器需保证其主程序一直在前台运行。好比建立docker镜像时启动命令是经过nohup在后台运行的:
nohup ./start.sh &
那么kubelet建立了包含这个容器的pod以后运行完这个命令,则会根据配置发生两种状况:
若是没法前台执行,只能后端运行的话,该怎么办呢?
能够借助supervisor。
应用部署的一个最佳实践就是将配置信息和程序进行分离,在k8s中可使用configmap实现。
详细使用可参考:K8S configmap使用
在建立pod出错了,一般会看到pending状态,而你使用 kubectl get pods 时,也偶尔会看到重启这个字段,那么pod的生命周期和重启策略具体是怎么实现的呢?
一个pod的状态信息是保存在PodStatus对象中的,phase字段用来描述pod在其生命周期中的不一样状态,包括:
状态 | 说明 |
---|---|
Pending | 挂起。有一个或多个容器未被建立,能够经过kubectl get po ** 查看缘由。 |
running | 运行中。全部容器已被建立,至少有一个是运行状态,可经过kubectl logs -f ** 查看日志 |
succeeded | 成功。全部容器执行成功并终止,不会再次重启。 |
failed | 失败。全部容器都已终止,至少有一个容器以失败的方式终止。 |
unknown | 未知。通常是由于通讯问题没法获取pod的状态 |
Pod一般使用探针来检测容器内的应用是否正常,有两类探针:
在Pod发生故障时对Pod进行重启(仅在Pod所处的Node上操做),具体的方式包括:
操做方式 | 说明 |
---|---|
Always | 容器失效时,自动重启 |
OnFailure | 容器以不为0的状态码终止,自动重启 |
Never | 不管何种状态,都不会重启 |
其中,Pod的重启策略与控制方式息息相关,不一样的控制器对pod的重启策略要求不同:
在使用K8S时,咱们不多直接建立Pod,大多数状况都是会经过RC、Deployment、DaemonSet、Job等控制器来实现对一组Pod副本的建立、调度和全生命周期的自动控制。
官方建议:不该该使用底层的ReplicaSet来控制Pod副本,推荐直接使用管理ReplicaSet的Deployment对象来控制Pod副本。
Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,持续监控副本的数量,保证集群内始终维持指定的副本数量。建立的pod彻底由系统自动完成调度,pod各自运行在哪一个节点上,彻底由master scheduler计算出一个最佳的目标节点进行分配,用户没法干预。
举个例子:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.0 ports: - containerPort: 80
使用kubectl create -f **.yaml建立该Deployment。
使用kubectl get deployments,就会发现刚才建立的deployment有三个副本。
使用kubectl get rs和kubectl get pods可查看已建立的RS和pod,使用kubectl get pod -o wide能够查看pod的分配状况。
在实际应用中,常常会须要将Pod调度到指定的一些Node节点上,这时候可配置NodeSelector或者NodeAffinity来进行定向调度。
NodeSelector
具体的使用:
NodeAffinity(节点亲和力调度)
NodeSelector经过标签机制,简单的限制了Pod所在节点的方法,亲和力调度机制则更好扩展了Pod的调度能力,可使用软限制,支持In、NotIn、Exists、DoesNotExist、Gt、LT等操做符。
须要注意如下几点:
PodAffinity(Pod亲和与互斥调度)
根据节点上正在运行的Pod标签而非节点的标签进行判断和调度,对节点和Pod两个条件进行匹配。
具体的使用:
DaemonSet
用于管理在集群的每一个Node上仅运行一份pod的副本实例。适用场景:日志采集、性能监控等。
为了提升资源利用率,咱们一般会采用优先级方案,即不一样类型的负载对应不一样的优先级,而且当发生资源不足时,系统能够选择释放一些不重要的负载,保障最重要的负载以获取足够的资源稳定运行。
优先级抢占调度策略的有两个核心点:
能够经过Job来定义并启动一个批处理任务(并行启动多个进程去处理一些工做项),处理完成后,整个批处理任务结束。
相似Linux Cron的定时任务Cron Job。
除此之外,你还能够自定义调度器。
为了保证服务的高可用,k8s提供了滚动升级功能。主要介绍下deployment。
升级
更新镜像名的话,有如下方法进行更新:
kubectl set image
命令设置新的镜像名kubectl edit
命令修改Deployment的配置,根据yaml的结构更新(好比:将spec.template.spec.containers[0].image从nginx:1.0改成nginx:1.1)。对于RC的滚动升级,可使用kubectl rolling-update
命令,该命令会建立一个新的RC,自动控制旧的RC中pod副本数量逐渐减小到0,新的RC中的Pod副本数量从0逐步增长到目标值。
一旦pod的定义发生了修改,则将触发系统完成Deployment中全部pod的滚动操做,可以使用kubectl rollout status
查看滚动更新过程。
在升级过程当中,deployment可以保证服务不中断,而且副本数量始终维持在用户指定数量。可在Deployment定义中,经过spec.strategy指定pod的更新策略,包括:
回滚
服务稳定性或者配置错误等缘由会使得咱们须要进行回滚,Deployment的全部发布历史记录都被保留在系统中,因此回滚是很方便的。具体操做:
对于相对复杂的配置修改,为了不频繁大量触发更新操做,可以使用kubectl rollout pause
命令暂停更新操做,而后进行配置修改,最后恢复deployment,一次性触发完整的更新操做。
伴随着资源的使用状况,常须要对pod进行扩缩容,能够利用Deployment/RC的Scale机制来实现,分为手动和自动两种模式。
手动
经过kubectl scale deployment *** --replicas 3
命令更新Pod副本数量,将--replicas设置比当前pod副本数量更小的数字的话,系统会kill一些正在运行的pod。
自动
用户指定pod副本的数量范围,设定依据的性能指标或者自定义业务指标,系统将自动的在这个范围内根据性能指标变化调整pod副本数量。
k8s 1.1版本开始新增了HPA控制器,基于Master的kube-controller-manager服务启动参数--horizontal-pod-autoscal-sync-period定义的探测周期,周期性检测目标pod的资源性能指标。并与设定的扩容条件进行对比,进行pod副本数量的自动调整。
以上。