一、Pod和容器的关系
理论上,一个Pod存在一组容器,并且这些容器拥有相同的域名、主机名以及网络接口。实现多个容器网络名称空间共享的是一个底层叫做pause的基础容器,结构如下图:
![89fd7f0530ff3cf2ff432ecc2d2ce7f8.png](https://img-blog.csdnimg.cn/img_convert/89fd7f0530ff3cf2ff432ecc2d2ce7f8.png)
实际上,除了一些特殊场景一般一个Pod只会运行一个容器,这样做的好处是:
- 多个应用部署到多个Pod,多个Pod可以被调度到不同的工作节点上运行,可以提高主机资源利用率
- Kubernetes可以对Pod进行自动伸缩,运行在不同Pod的多个应用可以按需独立进行规模变动,提供了系统的灵活性
上面所说的特殊场景(一个Pod运行多个容器)包括:
- Sidecar Pattern(边车模型或跨斗模型):为Pod的主容器提供协同的辅助容器。典型代表:
- 主应用容器中日志由agent收集到日志服务器,agent运行为辅助应用容器
- 为主应用容器中的数据库服务启用本地缓存
- Ambassador pattern(大使模型):为远程服务创建一个本地代理。
- Adapter pattern(适配器模型):用于将主应用容器中的内容进行标准化输出
- 日志数据或者指标数据的输出,有助于调用者统一接收数据的接口
二、管理Pod对象中的容器
容器的定义在spec.containers字段下面:
- name 容器名字,名称空间内全局唯一
- image 镜像名字
- imagePullPolicy 镜像拉取策略,值可选
- Always:每次都从指定的仓库中获取(镜像标签为'latest'时默认值)
- IfNotPresent:仅当本地镜像不存在时候从远程拉取(镜像标签不是'latest'时默认值)
- Never:禁止从仓库下载镜像
- ports 暴露端口
- containerPort:指定Pod对象的IP地址上暴露的容器端口
- name:端口名字
- protocol:端口协议
- hostPort:通过工作节点的IP和端口将集群内部的服务暴露到集群外部。注意:这种暴露方式与NodePort类型的Service对象暴露端口的方式不同。NodePort是通过所有工作节点暴露容器服务的,而这种方式是通过Pod对象所被调度的工作节点暴露的。
- command:指定不同于镜像默认运行的应用程序,并且同时使用args进行参数传递
- args:如果只配置了args,没有配置args,那么这个参数会传递给镜像默认运行的应用程序。如果只配置了command,则会以无参数的方式运行应用程序。
- env:设置镜像的环境变量
- spec.hostNetwork(注意这个不是spec.containers下的):共享节点的网络名称空间
三、标签及标签选择器
标签主要作用是将资源对象分组,在metadata.lables下定义。
标签选择器用于表达标签的查询条件,支持基于等值关系(key=value)和基于集合关系(key in(value1,value2...)、key notin(value1,value2...)、key(所有存在该键名标签的资源)、!key)。
- 同时指定多个选择器之间的逻辑关系是"与"
- 不使用标签选择器表示选择所有资源
- 标签选择器的值为空时无法选出任何资源
注意:为了避免shell解释器解析叹号!,必须要为标签选择器表达式使用单引号
有个标签选择器的应用:节点选择器 nodeSelector 用于指定Pod被调度到具有某种标签的节点上。如果再具体一点指定节点,可以使用spec.nodeName字段。
四、注解(Annotations)
注解一个比较实际的应用是在声明式配置命令apply创建时,会在注解中保存相关信息以便在一下资源变动时进行版本对比。
五、Pod的生命周期
1、Pod的相位(状态)
- Pending:API Server创建了Pod资源对象并且已经把资源对象信息存入etcd中,但是尚未调度至工作节点或者镜像还没从远程仓库完全拉下来。
- Running:Pod已经被调度到工作节点,并且所有容器都已经被kubectl创建成功。
- Succeeded:Pod所有容器都已经成功终止并且不会被重启。
- Failed:所有容器都已经终止,但至少有一个容器终止失败,即容器返回非0状态值
- Unknown:API Server无法获取Pod对象的状态信息,这种一般是由于无法和所在工作节点的Kubelet通信导致的
2、Pod的创建过程
![4828204f7b102a8ca42bb23e8286cacd.png](https://img-blog.csdnimg.cn/img_convert/4828204f7b102a8ca42bb23e8286cacd.png)
(1)用户通过Kubectl或者其他客户端提交创建Pod的请求
(2)API Server尝试将提交的Pod的信息存储到etcd,存储成功后会返回确认信息至客户端
(3)这个时候API Server开始反应etcd中的状态变化
(4)kubernetes中所有组件都通过"watch"机制来跟踪API Server上的相关变动
(5)kube-scheduler(调度器)通过watch监测到API Server创建了新的Pod并且尚未绑定到任何工作节点
(6)scheduler会为Pod对象选择一个工作节点并将结果更新到API Server
(7)API Server将信息更新至etcd中
(8)工作节点的kubelete通过watch检测到新的Pod被调度到自己这边,kubelete尝试在当前节点上执行docker run来运行容器,并将容器的结果状态返回给API Server
(9)API Server将Pod状态信息存入etcd中
(10)API Server将确认信息发送给相关的kubelete
3、Pod生命周期中的重要行为
(1)初始化容器:主容器启动之前要运行的容器,常用于为容器执行一些预置操作。使用到的配置字段:spec.initContainers 主容器必须在initContainers启动之后才能启动
(2)生命周期的钩子函数:lifecycle
- postStart:容器创建完成之后立即运行的钩子处理器
- preStop:容器终止操作之前立即运行的钩子处理器
钩子处理器的实现方式有"Exec"和"HTTP"两种,exec运行用户定义的命令,http向当前容器中发送HTTP请求
(3)容器探测:对容器健康状态进行诊断
- ExecAction:执行一个命令,返回状态为0表示成功
- TCPSocketAction:通过TCP端口尝试建立连接进行诊断
- HTTPGetAction:发送HTTP GET请求进行诊断
主要是存活性探测和就绪性探测,具体见六、七。
4、容器的重启策略
- Always:Pod对象终止就重启,这是默认值
- OnFailure:仅在Pod对象出现错误时才重启
- Never:从不重启
5、Pod的终止过程
![9e2680e228b6f6150ba8882e842bae9b.png](https://img-blog.csdnimg.cn/img_convert/9e2680e228b6f6150ba8882e842bae9b.png)
(1)首先,用户发送删除Pod对象的命令
(2)API服务其中的Pod对象会随着时间的推移而更新,在宽限期内(默认是30s)Pod被视为Dead
(3)将Pod标记为"Terminating"状态,与此同时kubelet在监控到Pod对象转为"Terminating"状态时会启动关闭Pod过程。另外,端点控制器也会将Pod对象从所有匹配到此端点的Servie资源的端点列表中移除
(4)如果当前Pod对象定义了preStop钩子处理器,则在其被标记为"Terminating"后会立即以同步的方式执行钩子函数。如果宽限时间结束后,preStop仍未执行结束,则第2步会被重新执行并额外获取一个时长为2秒的小宽限期
(5)Pod对象的容器进程收到TERM信号
(6)宽限期结束后,若存在任何一个仍在运行的进程,Pod对象即会收到SIGKILL信号
(7)Kubelete请求API Server将此Pod资源的宽限期设置为0从而完成删除操作
(8)最后,默认所有操作的宽限都是30s,不过kubelete delete命令可以使用--grace-period=<seconds>自定义时长
六、Pod存活性探测 livenessProbe
存活性探测是容器级别的配置,kubelete可基于此判定何时需要重启一个容器。通过ExecAction、TCPSocketAction、HTTPGetAction三种方式判断容器是否还运行,配合重启策略触发后续的行为。
- ExecAction:自定义命令,命令返回状态码0表示通过测试
- HTTPGetAction:向目标容器发送HTTP Get请求,返回200表示测试通过
- TCPSocketAction:向容器的特定端口发起TCP请求,连接建立成功表示测试通过
存活性探测行为属性:
- initialDelaySeconds<int>:容器启动多久后开始存活性探测,默认为0
- timeoutSeconds<int>:存活性探测的超时时长
- periodSeconds<int>:存活性探测的频率
- successThreshold:处于失败状态时,探测操作至少连续多少次的成功才被认为是检测通过,默认是1
- failureThreshold:处于成功状态时,探测操作至少连续多次此失败才被认为是检测不通过,默认是3
七、Pod就绪性探测 readinessProbe
就绪性探测用来判断容器是否已经初始化完成并可服务于客户端请求,于存活性探测一样也支持ExecAction、TCPSocketAction、HTTPGetAction三种检测方式。和存活性探测不同的是,探测失败时就绪性探测不会杀死或者重启容器,而是通知其尚未就绪,并触发依赖于其就绪状态的操作以确保不会有客户端请求接入此Pod对象。
八、资源需求与限制
这里的资源指的是CPU和内存资源,资源隔离属于容器级别。requests属性定义请求的确保可用值,即容器运行时可能用不到这么多的资源,但是用到时必须确保有如此多的的资源可用。limits属性则用于限制资源可用的最大值
1、资源需求requests
2、资源限制limits
3、Pod的服务质量类别
在内存资源非常紧张时,应该以何种先后终止哪些Pod对象呢?Kubernetes会借助于Pod对象的优先级完成判定。服务质量按照配置的Pod对象的requests和limits属性划分为三种:
- Guaranteed:每个容器都为CPU资源和内存资源设置了具有相同值得requests和limits属性,这种Pod资源具有最高优先级,也就是最后被终止
- Burstable:至少有一个容器设置了CPU或内存资源的requests属性,这种具有中等优先级
- BestEffort:任何一个容器都没有设置requests或者limits属性,这些资源优先级最低,系统资源不足是首先被终止掉
另外,同一优先级下的Pod资源在OOM时,与自身的requests属性相比,其内存占用比例最大的Pod对象将被首先杀死。比如同属于Burstable优先级别的Pod A已使用的内存占用比例比Pod B高,那么A会比B先被终止掉。需要特别说明的是OOM是内存耗尽时的处理机制,与可压缩型资源CPU无关,所以CPU资源的需求无法得到满足时,Pod仅仅是暂时获取不到相应的资源而已。