Kubernetes Pod详解
一、Pod介绍1.Pod的结构每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:用户程序所在的容器,数量可多可少。Pause容器,这是每个Pod都会有的一个根容器,他的作用有两个:.1.可以以他为依据,评估整个Pod的健康状态。2.可以在根容器上设置ip地址,其他容器都依赖此ip(Pod IP),以实现Pod内部的网络通信。(这里是Pod内部的通讯,Pod之间的通讯是采用虚拟二层网络技
一、Pod介绍
1.Pod的结构
每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类:
- 用户程序所在的容器,数量可多可少。
- Pause容器,这是每个Pod都会有的一个根容器,他的作用有两个:
. 1.可以以他为依据,评估整个Pod的健康状态。
2.可以在根容器上设置ip地址,其他容器都依赖此ip(Pod IP),以实现Pod内部的网络通信。(这里是Pod内部的通讯,Pod之间的通讯是采用虚拟二层网络技术来实现,我们当前的环境用的是Flannel)
2.Pod的定义
下面是Pod的资源清单(配置yaml)
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #Pod所属的命名空间,默认为“default”
labels: #Pod自定义的标签列表
- name: string #标签名和值
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中的容器列表
- name: string #必选,容器名字
image: string #必选,容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略
command: [string] #容器启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器启动的命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用Pod定义的共享存储卷的名称,需用volumes[]部分定义的卷名
mountPath: string #存储卷在容器内部mount的绝对路径,应少于512字符
readOnly: boolean #是否只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: int #容器监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境列表
- name: string #环境变量名称
value: string #环境变量的值
resource: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #CPU的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #CPU 请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内各个容器健康检查方式设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对pod内各个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认1秒
successThreshold: 0
failureThreshold: 0
sucurityContext:
privileged: false
restartPolicy: [Always|Never|OnFailure] #对Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定名称的node节点上
nodeSelector: object #设置NodeSelector表示将该pod调度到包含这个label的Node上
imagePullSecurets: #pull镜像时使用的secret名称,以key:secretKey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称
emptyDir: {} #类型为emptyDir的存储卷,与pod同生命周期的一个临时目录,为空值
hostPath: string #类型为hostPath的存储卷,表示挂载pod所在宿主机目录
path: string #pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
小提示:
可以通过一个命令来查看各种资源的可配置项
#查看某种资源可以配置的一级属性
kubectl explain 资源类型
#查看属性的子属性
kubectl explain 资源类型 属性
#常用的资源类型为Pod Service Namespace Deployment
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5个部分:
属性 | 类型 | 作用 |
apiVersion | string | 版本,由kubernetes内部定义,版本号必须可以用kubectl api-versions查询到 |
kind | string | 类型,由kubernetes内部定义,版本号必须可以用kubectl api-resources 查询到 |
metadata | Object | 元数据,主要是资源标识和说明,常用的有name、namespace、labels等 |
spec | Object | 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述 |
status | Object | 状态信息,里面的内容不需要定义,由kubernetes自动生成 |
在上面的属性中,spec是研究的重点,他常见的紫属性有:
属性 | 类型 | 作用 |
containers | []Object | 容器列表看,用于定义容器的详细信息 |
nodeName | string | 根据nodeName的值将pod调度到指定的Node节点上 |
nodeSelector | map[] | 根据nodeSelector中定义的信息选择将该Pod调度到包含这些label的Node上 |
hostNetwork | boolean | 是否使用主机网络模式,默认是false,如果设置为true,表示使用宿主机网络 |
volumes | []Object | 存储卷,用于定义Pod上面挂载的存储信息 |
restartPolicy | string | 重启策略,表示Pod在遇到故障的时候的处理策略 |
二、Pod 配置
主要研究pod.spec.containers属性,这也是pod配置中最为关键的一项配置。
[root@master ~]#kubectl explain pod.spec.containers
KIND: Pod
VERSION: v1
RESOURCE: containers <[]Object>
FIELDS:
name <string> #容器名称必要配置
image <string> #容器需要的镜像
imagePullPolicy <string> #镜像拉取策略
command <[]string> #容器启动命令
args <[]string> #容器启动命令参数
env <[]Object> #容器环境变量的配置
ports <[]Object> #容器需要暴露的端口号列表
resources <Object> #资源限制和资源请求的设置
1. 基本配置
创建pod-base.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: dev
labels:
user: axiba
spec:
containers:
- name: nginx
image: nginx:1.17.1
- name: busybox
image: busybox:1.30
上面定义了一个比较简单的Pod的配置,里面有两个容器:
- nginx:用1.17.1版本的nginx镜像创建
- busybox:用1.30版本的busybox镜像创建
可以使用kubectl describe命令查看events
kubectl describe pod pod-base -n dev
2.镜像拉取策略
编写pod-imagepullpolicy.yaml,内容如下
apiVersion: v1
kind: Pod
metadata:
name: pod-imagepullpolicy
namespace: dev
labels:
user: axiba
spec:
containers:
- name: nginx
image: nginx:1.17.1
imagePullPolicy: Always
- name: busybox
image: busybox:1.30
imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:
- Always:总是从远程仓库拉取镜像
- IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
- Never:只使用本地镜像,从不去远程仓库拉取
默认值说明:
1.如果镜像tag为具体版本号,则默认策略时IfNotPresent
2.如果镜像tag为:lastest(最近版本),默认策略是Always
查看pod详情的events可以看出,当拉取策略设置为Always时,有从远程仓库拉取镜像的过程
当拉取策略设置为Never的时候
1.镜像已经存在
2.镜像不存在,这时直接报错
3.容器启动命令
在前面busybox容器一直没有成功运行,那么到底是什么原因呢?
是因为busybox并不是一个程序,而是类似一个工具类集合,kubernetes集群启动管理后,他会自动关闭。解决方法就是让其一直在运行,这就用到了command配置。
创建pod-command.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-command
namespace: dev
labels:
user: axiba
spec:
containers:
- name: nginx
image: nginx:1.17.1
- name: busybox
image: busybox:1.30
command: ['/bin/sh','-c','touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;']
command用于在pod中的容器初始化完毕之后运行的一个命令。
特别说明:kubernetes中的command和args其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
- 如果command和args均没有写,那么用Dockerfile的配置。
- 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command。
- 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数。
- 如果command和args都写了,那么Dockerfile的配置会被忽略,执行command并追加args参数。
4.环境变量
创建pod-env.yaml文件,内容如下
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: dev
spec:
containers:
- name: busybox
image: busybox:1.30
command: ['/bin/sh','-c','while true;do /bin/echo $(date +%T); sleep 60; done;']
env:
- name: "username"
value: "admin"
- name: "password"
value: "123456"
env,环境变量,用于pod中的容器设置环境变量
这种方式不是很推荐,推荐将这些配置单独存储在配置文件中。
5.端口设置
首先查看一下ports支持的子选项
name <string> #端口名称,如果指定,必须保证name和pod中是唯一的。
containerPort <integer> #容器要监听的端口
hostPort <integer> #容器在主机上公开的端口,如果设置,主机只能运行容器一个副本(一般省略)
hostIP <string> #要将外部端口绑定到的主机ip(一般省略)
protocol <string> #端口协议。必须是UDP,TCP或者SCTP。默认TCP
创建pod-ports.yaml,内容如下
apiVersion: v1
kind: Pod
metadata:
name: pod-ports
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
访问容器中的程序需要使用的是podIp:containerPort 访问
6.资源配额
容器中的程序要运行,肯定要占用一定的资源,比如CPU和内存等,如果不对某个容器的资源做限制,就可能吃掉大量资源,导致其他容器无法运行。针对这种情况,kubernetes提供了对内存和CPU的资源进行配额的机制,这种机制主要通过resources选项实现,他有两个子选项:
- limits:用于限制运行时容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启。
- requests:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动。
可以通过上面两个选项设置资源的上下限。
创建pod-resources.yaml,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-resource
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
resources:
limits:
cpu: "2"
memory: "10Gi"
requests:
cpu: "1"
memory: "10Gi"
在这里对cpu和memory的单位做一个说明:
- cpu:core数,可以为整数或者小数
- memory:内存大小,可以使用Gi、Mi、G、M等形式
可以看到,需要10G的内存,所以pod无法启动,状态一直是pending。
三、Pod的调度
在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就需要了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:
- 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出。
- 定向调度:NodeName、NodeSelector
- 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
- 污点(容忍)调度:Taints、Toleration
1.定向调度
定向调度,指的是利用Pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。
1.1.NodeName:用于强制约束将Pod调度到指定Name的Node节点上,这种方式,其实是直接跳过Scheduler的调度逻辑,直接写入PodList列表。
创建一个pod-nodename.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodename: node1
1.2.NodeSelector用于将Pod调度到添加指定标签的node节点上,他通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束,如果NodeSelector指定的node标签不存在,则创建Pod失败。
#给node节点添加标签
#这里给node1节点添加标签nodeenv并且值为pro
kubectl label nodes node1 nodeenv=pro
#这里给node2节点添加标签nodeenv并且值为test
kubectl label nodes node2 nodeenv=test
创建一个pod-nodeselector.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-nodename
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodeSelector:
nodeenv: pro
2.亲和性调度
定向调度使用非常方便,但是存在一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用Node列表也不行,这就限制了他的使用场景。
基于上面的问题,kubernetes还提供了一种亲和性调度(Affinity)。他在NodeSelector的基础上进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。
Affinity主要分为三类:
- nodeAffinity(node亲和性):以node为目标,解决pod可以调度到哪些node的问题。
- podAffinity(pod亲和性):以pod为目标,解决pod可以和哪些已存在的pod部署在同一拓扑域中的问题。
- podAntiAffinity(pod反亲和性):以pod为目标,解决pod不能和哪些已存在的pod部署在同一个拓扑域中的问题。
使用场景说明:
- 亲和性:如果两个应用频繁交互,那就有必要利用亲和性让两个应用尽可能的靠近,这样可以减少因网络通信而带来的性能损耗。
- 反亲和性:当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性。
1.NodeAffinity
NodeAffinity的可配置项:
pod.spec.affinity.nodeAffinity
requiredDuringSchedulingIgnoredDuringException # Node节点必须满足指定的所有规则才可以,相当于硬限制
nodeSelectorTerms #节点选择列表
matchFields #按节点字段列出的节点选择器要求列表
matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
key #键
values #值
operator #关系符 支持Exists,DoesNotExist,In,NotIng,Gt,Lt
preferredDuringSchedulingIgnoredDuringException # 优先调度到满足指定的规则的Node,相当于软限制(倾向)
preference #一个节点选择器项,与相应的权重相关联
matchFields #按节点字段列出的节点选择器要求列表
matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
key #键
values #值
operator #关系符 支持Exists,DoesNotExist,In,NotIn,Gt,Lt
weight #倾向权重,在范围1-100
关系符的使用说明:
- matchExpressions:
- key: nodeenv #匹配存在标签的key为nodeenv的节点
operator: Exists
- key: nodeenv #匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
operator: In
values: ["xxx","yyy"]
- key: nodeenv #匹配标签的key为nodeenv,且value大于"xxx"的节点
operator: Gt
values: "xxx"
案例1:演示requiredDuringSchedulingIgnoredDuringExecution 硬限制
创建pod-nodeaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringException:
nodeSelectorTerms:
- matchExpressions:
- key: nodeenv
operator: In
values: ["pro","test"]
案例2:演示preferredDuringSchedulingIgnoredDuringException 软限制
创建pod-nodeaffinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-preferred
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringException:
- weight: 1
preference:
- matchExpressions:
- key: nodeenv
operator: In
values: ["pro","test"]
NodeAffinity规则设置的注意事项:
- 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能运行在指定的Node上。
- 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可。
- 如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点中必须满足所有的才能匹配成功。
- 如果一个pod所在的Node在Pod运行期间其标签发生了变化,不再符合该Pod的节点亲和性需求,则系统将忽略此变化。
2.PodAffinity
PodAffinity主要实现以运行的Pod为参照,实现让新建的Pod跟参照Pod在一个区域的功能。
PodAffinity的可配置项:
pod.spec.affinity.podAffinity
requiredDuringSchedulingIgnoredDuringException # 硬限制
namespaces #指定参照pod的namespace
topologyKey #指定调度作用域
labelSelector #标签选择器
matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
key #键
values #值
operator #关系符 支持Exists,DoesNotExist,In,NotIng
matchLabels #指多个matchExpressions映射的内容
preferredDuringSchedulingIgnoredDuringException # 软限制(倾向)
PodAffinityTerm #选项
namespaces #指定参照pod的namespace
topologyKey #指定调度作用域
labelSelector #标签选择器
matchExpressions #按节点标签列出的节点选择器要求列表(推荐)
key #键
values #值
operator #关系符 支持Exists,DoesNotExist,In,NotIng
matchLabels #指多个matchExpressions映射的内容
weight: #倾向权重,在范围1-100
topologyKey用于指定调度时作用域,例如:
- 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围。
- 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。
案例1 演示requiredDuringSchedulingIgnoredDuringException
首先创建一个参照Pod,创建pod-podaffinity-target.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-podaffinity-target
namespace: dev
labels:
podenv: prod #设置标签
spec:
containers:
- name: nginx
image: nginx:1.17.1
nodeName: node1
创建pod-podaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-podaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringException
- labelSelector
matchExpressions
- key: podenv
values: ["prod","test"]
operator: In
topologyKey: kubernetes.io/hostname
配置的意思是新pod必须要与拥有标签podenv=prod或者podenv=test在同一Node上。
3.PodAntiAffinity
主要实现以运行的Pod为参照,让新创建的Pod跟参照Pod不再一个区域中的功能。
配置方式和选项跟PodAffinity一样。
继续使用pod-antifinity-target作为目标Pod,创建pod-podantiaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-podantiaffinity-required
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringException
- labelSelector
matchExpressions
- key: podenv
values: ["prod"]
operator: In
topologyKey: kubernetes.io/hostname
配置的意思是新pod必须要与拥有标签podenv=prod不在同一Node上。
3.污点和容忍
污点(Taints)
前面的调度方式都是站在Pod的角度上,通过Pod上添加属性,来确定是否要调度到指定的Node上,其实我们也可以站在Node的角度上,通过Node上的污点属性,来决定是否允许Pod调度过来。
Node被设置上污点之后,就和Pod之间存在了一种相斥关系,进而拒绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去。
污点的格式为:key=value:effect,key和value是污点的标签,effect描述污点的作用,支持如下三个选项:
- PreferNoSchedule:kubernetes将尽量避免把Pod调度到具有该污点的Node上,除非没有其他的节点可调度。
- NoSchedule:kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前的Node上已存在的Pod。
- NoExecute:kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已存在的Pod驱离。
使用kubectl设置和去除污点的命令示例如下:
#设置污点
kubectl taint nodes node1 key=value:effect
#去除污点
kubectl taint nodes node1 key:effect-
#去除所有污点
kubectl taint nodes node1 key-
演示污点的效果:
1.准备节点node1(为了演示效果,暂时停止node2节点)
2.为node1节点设置一个污点:tag=ifun:PreferNoSchedule,然后创建pod1 (pod1正常)
3.修改node1节点,设置一个污点:tag=ifun:NoSchedule,然后创建pod2 (pod1正常 pod2失败)
4.修改node1节点,设置一个污点:tag=ifun:NoExecute,然后创建pod3 (都失败)
#为node1设置污点
kubectl taint nodes node1 tag=ifun:PreferNoSchedule
#创建pod1
kubectl run taint1 --image=nginx:1.17.1 -n dev
#去除node1污点PreferNoSchedule,设置NoSchedule
kubectl taint nodes node1 tag:PreferNoSchedule-
kubectl taint nodes node1 tag=ifun:NoSchedule
#创建pod2
kubectl run taint2 --image=nginx:1.17.1 -n dev
#去除node1污点NoSchedule,设置NoExecute
kubectl taint nodes node1 tag:NoSchedule-
kubectl taint nodes node1 tag=ifun:NoExecute
#创建pod3
kubectl run taint3 --image=nginx:1.17.1 -n dev
小提示:使用kubernetes搭建集群,默认就会给master节点添加一个污点标记,所以pod不会调度到master节点上。
容忍(Toleration)
我们可以在Node上添加污点来拒绝pod调度上来,但是如果就是想将pod调度到一个有污点的node上去,这时候就要使用到容忍。
污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,pod通过容忍忽略污点。
容忍的配置项
tolerations #添加容忍
key #对应要容忍污点的key,空意味着匹配所有的键
value #对应要容忍污点的value
operator #key-value的运算符,支持Equal和Exists(默认)
effect #对应污点的effect,空意味着匹配所有
tolerationSeconds #容忍时间,当effect为NoExecute时失效,表示pod在Node上的停留时间
创建一个pod-toleration.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-toleration
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
tolerations: #添加容忍
- key: "tag" #污点的key
value: "ifun" #污点的value
operator: "Equal" #操作符
effect: "NoExecute" #添加容忍的规则,这里必须和标记的污点规则相同
更多推荐
所有评论(0)