Kubernetes(k8s)pod详解

锦通  金牌会员 | 2022-6-21 16:47:44 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 553|帖子 553|积分 1659

目录

一、简介

在Kubernetes集群中,Pod是所有业务类型的基础,也是K8S管理的最小单位级,它是一个或多个容器的组合。这些容器共享存储、网络和命名空间,以及如何运行的规范。在Pod中,所有容器都被统一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod是它们的逻辑主机,Pod包含业务相关的多个应用容器。
二、Pod实现机制与设计模式

每个Pod都有一个特殊的被称为"根容器"的Pause 容器(Pause容器,又叫Infrastructure容器)。 Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或者多个紧密相关的用户业务容器。

众所周知,容器之间是通过Namespace隔离的,Pod要想解决上述应用场景,那么就要让Pod里的容器之间高效共享。
具体分为两个部分:网络和存储


  • 共享网络
kubernetes的解法是这样的:会在每个Pod里先启动一个infra container小容器,然后让其他的容器连接进来这个网络命名空间,然后其他容器看到的网络试图就完全一样了,即网络设备、IP地址、Mac地址等,这就是解决网络共享问题。在Pod的IP地址就是infra container的IP地址。


  • 共享存储
比如有两个容器,一个是nginx,另一个是普通的容器,普通容器要想访问nginx里的文件,就需要nginx容器将共享目录通过volume挂载出来,然后让普通容器挂载的这个volume,最后大家看到这个共享目录的内容一样。
例如:
  1. # pod-write-read.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   name: my-pod
  6. spec:
  7.   containers:
  8.   - name: write
  9.     image: centos
  10.     command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
  11.     volumeMounts:
  12.       - name: data
  13.         mountPath: /data
  14.   - name: read
  15.     image: centos
  16.     command: ["bash","-c","tail -f /data/hello"]
  17.     volumeMounts:
  18.       - name: data
  19.         mountPath: /data
  20.    
  21.   volumes:
  22.   - name: data
  23.     emptyDir: {}
复制代码
上述示例中有两个容器,write容器负责提供数据,read消费数据,通过数据卷将写入数据的目录和读取数据的目录都放到了该卷中,这样每个容器都能看到该目录。
验证:
  1. $ kubectl apply -f pod-write-read.yaml
  2. $ kubectl logs my-pod -c read -f
复制代码
在Pod中容器分为以下几个类型:

  • Infrastructure Container:基础容器,维护整个Pod网络空间,对用户不可见
  • InitContainers:初始化容器,先于业务容器开始执行,一般用于业务容器的初始化工作
  • Containers:业务容器,具体跑应用程序的镜像
三、镜像拉取策略
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: pod001
  5. spec:
  6.   containers:
  7.     - name: busybox001
  8.       image: busybox
  9.       imagePullPolicy: IfNotPresent
复制代码
imagePullPolicy 字段有三个可选值:

  • IfNotPresent:镜像在宿主机上不存在时才拉取
  • Always:默认值,每次创建 Pod 都会重新拉取一次镜像
  • Never: Pod 永远不会主动拉取这个镜像
注意,这里的重启是指在Pod所在Node上面本地重启,并不会调度到其他Node上去。
四、资源限制

Pod资源配额有两种:
申请配额:调度时使用,参考是否有节点满足该配置

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
限制配额:容器能使用的最大配置

  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: pod002
  5. spec:
  6.   containers:
  7.   - name: busybox002
  8.     image: busybox
  9.     resources:
  10.       requests:
  11.         memory: "64Mi"
  12.         cpu: "250m"
  13.       limits:
  14.         memory: "128Mi"
  15.         cpu: "500m"
复制代码
其中cpu值比较抽象,可以这么理解:
1核=1000m
1.5核=1500m
那上面限制配置就是1核的二分之一(500m),即该容器最大使用半核CPU。
该值也可以写成浮点数,更容易理解:
半核=0.5
1核=1
1.5核=1.5
五、重启策略
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: pod003
  5. spec:
  6.   containers:
  7.   - name: busybox003
  8.     image: busybox
  9.   restartPolicy: Always
复制代码
restartPolicy字段有三个可选值:

  • Always:当容器终止退出后,总是重启容器,默认策略
  • OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。适于job
  • Never:当容器终止退出,从不重启容器。适于job
六、 健康检查

默认情况下,kubelet 根据容器状态作为健康依据,但不能容器中应用程序状态,例如程序假死。这就会导致无法提供服务,丢失流量。因此引入健康检查机制确保容器健康存活。
健康检查有两种类型:

  • livenessProbe
如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。


  • readinessProbe
如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
这两种类型支持三种检查方法:

  • httpGet
发送HTTP请求,返回200-400范围状态码为成功。


  • exec
执行Shell命令返回状态码是0为成功。


  • tcpSocket
发起TCP Socket建立成功。
  1. # health-check.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   labels:
  6.     test: liveness
  7.   name: liveness-exec
  8. spec:
  9.   containers:
  10.   - name: liveness
  11.     image: busybox
  12.     args:
  13.     - /bin/sh
  14.     - -c
  15.     - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
  16.     livenessProbe:
  17.       exec:
  18.         command:
  19.         - cat
  20.         - /tmp/healthy
  21.       initialDelaySeconds: 5
  22.       periodSeconds: 5
复制代码
上述示例:启动容器第一件事在容器内创建文件,停止30s,删除该文件,再停止60s,确保容器还在运行中。
验证现象:容器启动正常,30s后异常,会restartPolicy策略自动重建,容器继续正常,反复现象。
  1. $ kubectl apply -f health-check.yaml
  2. $ kubectl describe pod liveness-exec
  3. $
复制代码
七、调度策略

先看下创建一个Pod的工作流程: create pod -> apiserver -> write etcd -> scheduler -> bind pod to node -> write etcd -> kubelet( apiserver get pod) -> dcoekr api,create container -> apiserver -> update pod status to etcd -> kubectl get pods

Pod根据调度器默认算法将Pod分配到合适的节点上,一般是比较空闲的节点。但有些情况我们希望将Pod分配到指定节点,该怎么做呢?
这里给你介绍调度策略:nodeName、nodeSelector和污点
1)nodeName

nodeName用于将Pod调度到指定的Node名称上。
例如:下面示例会绕过调度系统,直接分配到k8s-node1节点。
  1. # SchedulePolicy-nodeName.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   labels:
  6.     run: busybox
  7.   name: busyboxnn
  8.   namespace: default
  9. spec:
  10.   nodeName: k8s-node1
  11.   containers:
  12.   - image: busybox
  13.     name: bs
  14.     command:
  15.     - "ping"
  16.     - "baidu.com"
复制代码
执行&查看
  1. $ kubectl apply -f SchedulePolicy-nodeName.yaml
  2. $ kubectl get pod busyboxnn -o wide
复制代码

2)nodeSelector

nodeSelector用于将Pod调度到匹配Label的Node上。先给规划node用途,然后打标签,例如将两台node划分给不同团队使用:
  1. $ kubectl label nodes k8s-node1 team=a
  2. $ kubectl label nodes k8s-node2 team=b
复制代码
后在创建Pod只会被调度到含有team=a标签的节点上。
  1. # SchedulePolicy-nodeSelector.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   name: busyboxsn
  6.   namespace: default
  7. spec:
  8.   nodeSelector:
  9.     team: b
  10.   containers:
  11.   - image: busybox
  12.     name: bs
  13.     command:
  14.     - "ping"
  15.     - "baidu.com"
复制代码
执行&查看
  1. $ kubectl apply -f SchedulePolicy-nodeSelector.yaml
  2. $ kubectl get pod busyboxsn -o wide
复制代码

3)taint(污点)与tolerations(容忍)


  • 污点应用场景:节点独占,例如具有特殊硬件设备的节点,如GPU
    设置污点命令:
    kubectl taint node [node] key=value[effect]
其中[effect] 可取值:

  • NoSchedule :一定不能被调度。
  • PreferNoSchedule:尽量不要调度。
  • NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。
示例:
先给节点设置污点,说明这个节点不是谁都可以调度过来的:
  1. $ kubectl taint node k8s-node1  abc=123:NoSchedule
复制代码
查看污点:
  1. $ kubectl describe node k8s-node1 |grep Taints
复制代码
然后在创建Pod只有声明了容忍污点(tolerations),才允许被调度到abc=123污点节点上
  1. # SchedulePolicy-tolerations.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   labels:
  6.     run: busybox
  7.   name: busybox3
  8.   namespace: default
  9. spec:
  10.   tolerations:
  11.   - key: "abc"
  12.     operator: "Equal"
  13.     value: "123"
  14.     effect: "NoSchedule"
  15.   containers:
  16.   - image: busybox
  17.     name: bs
  18.     command:
  19.     - "ping"
  20.     - "baidu.com"
复制代码
如果不配置容忍污点,则永远不会调度到k8s-node1。(也可以叫做反亲和性
去掉污点:
kubectl taint node k8s-node1  abc=123:NoSchedule
  1. $ kubectl taint node k8s-node1 abc:NoSchedule-
复制代码
master节点默认是打了污点标记,不调度的,去掉污点标记
  1. #添加 尽量不调度 PreferNoSchedule
  2. kubectl taint nodes k8s-master node-role.kubernetes.io/master:PreferNoSchedule
  3. #去除污点NoSchedule,最后一个"-"代表删除
  4. kubectl taint nodes k8s-master node-role.kubernetes.io/master:NoSchedule-
复制代码
八、Pod状态

1)Pod常见状态

1、Pending:等待中
Pod已经被创建,但还没有完成调度,或者说有一个或多个镜像正处于从远程仓库下载的过程。处在这个阶段的Pod可能正在写数据到etcd中、调度、pull镜像或启动容器。
2、Running:运行中
该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
3、Succeeded:正常终止
Pod中的所有的容器已经正常的执行后退出,并且不会自动重启,一般会是在部署job的时候会出现。
4、Failed:异常停止
Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
5、Terminating 或 Unknown 状态
从 v1.5 开始,Kubernetes 不会因为 Node 失联而删除其上正在运行的 Pod,而是将其标记为 Terminating 或 Unknown 状态。
6、Error 状态
通常处于 Error 状态说明 Pod 启动过程中发生了错误。常见的原因包括:


  • 依赖的 ConfigMap、Secret 或者 PV 等不存在
  • 请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等
  • 违反集群的安全策略,比如违反了 PodSecurityPolicy 等
  • 容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定。
7、Completed状态
状态由ContainerCreating变为Completed再变为CrashLoopBackOff,原因是command: 或args 参数错误无法正常执行。
用一张图来表示Pod的各个状态

2)Pod 其它状态详细说明

状态描述ContainerCreating容器创建中PodInitializing        pod初始化中CrashLoopBackOff容器曾经启动了,但可能又异常退出了,kubelet正在将它重启InvalidImageName无法解析镜像名称ImageInspectError无法校验镜像ErrImageNeverPull策略禁止拉取镜像ImagePullBackOff正在重试拉取RegistryUnavailable连接不到镜像中心ErrImagePull通用的拉取镜像出错CreateContainerConfigError不能创建kubelet使用的容器配置CreateContainerError创建容器失败m.internalLifecycle.PreStartContainer执行hook报错RunContainerError启动容器失败PostStartHookError执行hook报错ContainersNotInitialized容器没有初始化完毕ContainersNotRead容器没有准备完毕DockerDaemonNotReadydocker还没有完全启动NetworkPluginNotReady网络插件还没有完全启动pod启动后停止问题总结(ContainerCreating-》Completed-》CrashLoopBackOff):
pod 是否能持续运行,是由执行命令决定的,执行命令如果一执行就停止,控制台也停止持续输出,pod生命周期就结束,pod状态就会变成CrashLoopBackOff。

来源:https://www.cnblogs.com/liugp/p/16366688.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

锦通

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表