Pod详细介绍以及调度 (自我总结篇)

由于官网翻译不准确,需要自己总结一下

Pod概念

Pod(豆荚) 是Kubernetes集群管理与调度的最小单元

一个Pod可以封装一个容器或多个容器(主容器或sidecar边车容器)

用户pod默认会被调度运行在node节点之上(不运行在master节点上,但也有例外情况)

pod内的IP不是固定的,集群外不能直接访问pod

Pod带来的好处

Pod做为一个可以独立运行的服务单元,简化了应用部署的难度,以更高的抽象层次为应用部署管提供了极大的方便。

Pod做为最小的应用实例可以独立运行,因此可以方便的进行部署、水平扩展和收缩、方便调度管理与资源的分配。

Pod中的容器共享相同的数据和网络地址空间,Pod之间也进行了统一的资源管理与分配。

容器设计是单进程模型,pod是多进程模型

Pod是一组容器的逻辑概念,根据容器的设计理念一个容器里边只运行一个主进程,也就是说容器的本质就是进程,Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume。

其实在创建容器的时候,k8s会默认创建一个中间容器,这个容器叫作 Infra 容器,这个容器永远都是第一个被创建的,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起。这样的组织关系,可以用下面这样一个示意图来表达:

Pod详细介绍以及调度 (自我总结篇)_第1张图片
image.png

Pod 生命周期

执行初始化容器init container,其实在这之上还有一个infra container,pod 的生命周期是跟infra container一致的,然后才开始 init container, init container 可以定义多个, 依次执行,只有当前 init container 创建成功完成退出之后再执行下一个 init container(Pod中可以包含一到多个Init Container,在其他容器之前开始运行。Init Container 只能是运行到完成状态,即不能够一直存在。Init Container必须依次执行。在App Container运行前,所有的Init Container必须全部正常结束)

开始初始化main container,再初始化main container 如果用户设置了 hook 则会执行hook的操作 post start hook, 然后开始执行初始化main container

main container 创建成功之后 如果用户设置了容器的探活设置(livenessProbe 和 readinessProbe), kubelet 会根据 设置的类型来访问Pod容器,根据返回的结果决定是否重启或者是否能被访问到。

Pod 对象是k8s 最基础的原子单位,它里边可以运行多个容器,多个容器之间的网络是存储都是共享的,做到共享的实现方式是引用了一个中间容器 infra container, 在创建Pod 之前首先创建infra container, 然后然后再创建Pod里的容器,如果有init container 那么先创建init container 再创建main container,创建好的container 则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起, Pod 的生命周期与Infra 是一致的。

pod的YAML资源清单格式

# yaml格式的pod定义文件完整内容:
apiVersion: v1 #必选,api版本号,例如v1
kind: Pod #必选,Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #Pod所属的命名空间,默认在default的namespace
labels: # 自定义标签
name: string #自定义标签名字
annotations: #自定义注释列表
name: string
spec: #必选,Pod中容器的详细定义(期望)
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] #获取
镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,
否则下载镜像,Nerver表示仅使用本地镜像
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 #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker
run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用
于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存清求,容器启动的初始可用数量
livenessProbe: #对Pod内个容器健康检查的设置,当探测无响
应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对
一个容器只需设置其中一种方法即可
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 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure] # Pod的重启
策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,
OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector: obeject # 设置NodeSelector表示将该Pod调度
到包含这个label的node上,以key:value的格式指定
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork:false #是否使用主机网络模式,默认为false,
如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与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

YAML创建Pod

[root@master1 ~]# vim pod1.yml
apiVersion: v1 # api版本
kind: Pod # 资源类型为Pod
metadata:
name: pod-stress # 自定义pod的名称
spec:
containers: # 定义pod里包含的容器
- name: c1 # 自定义pod中的容器名
image: polinux/stress # 启动容器的镜像名
command: ["stress"] # 自定义启动容器时要执行的命令
(类似dockerfile里的CMD)
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang",
"1"] # 自定义启动容器执行命令的参数
# polinux/stress这个镜像用于压力测试,在启动容器时传命令与参数就是
相当于分配容器运行时需要的压力

[root@master1 ~]# kubectl apply -f pod1.yml
pod/pod-stress created

对pod里的容器进行操作

不用交互直接执行命令
格式为: kubectl exec pod名 -c 容器名 -- 命令
注意:
-c 容器名为可选项,如果是1个pod中1个容器,则不用指定;
如果是1个pod中多个容器,不指定默认为第1个。

[root@master1 ~]# kubectl exec pod-stress4 -c c2 -- touch
/111
[root@master1 ~]# kubectl exec pod-stress4 -c c2 -- ls
/111
/111

和容器交互操作

和docker exec几乎一样

[root@master1 ~]# kubectl exec -it pod-stress4 -c c1 --
/bin/bash
bash-5.0# touch /333
bash-5.0# ls
222 bin etc lib mnt proc run srv
tmp var
333 dev home media opt root sbin sys
usr
bash-5.0# exit
exit

pod的标签

  1. 查看pod的标签
[root@master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-stress 1/1 Running 0 7m25s 

  1. 打标签,再查看
[root@master1 ~]# kubectl label pod pod-stress
region=huanai zone=A env=test bussiness=game
pod/pod-stress labeled
[root@master1 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-stress 1/1 Running 0 8m54s
bussiness=game,env=test,region=huanai,zone=A

  1. 通过等值关系标签查询
[root@master1 ~]# kubectl get pods -l zone=A
NAME READY STATUS RESTARTS AGE
pod-stress 1/1 Running 0 9m22s
  1. 通过集合关系标签查询
[root@master1 ~]# kubectl get pods -l "zone in (A,B,C)"
NAME READY STATUS RESTARTS AGE
pod-stress 1/1 Running 0 9m55s
  1. 删除标签后再验证
[root@master1 ~]# kubectl label pod pod-stress regionzone-
env- bussinesspod/
pod-stress labeled
[root@master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-stress 1/1 Running 0 16m 

小结:

  • pod的label与node的label操作方式几乎相同
  • node的label用于pod调度到指定label的node节点
  • pod的label用于controller关联控制的pod

Pod删除

单个pod删除

[root@master1 ~]# kubectl delete pod pod-stress
pod "pod-stress" deleted

多个pod删除

[root@master1 ~]# kubectl delete pod pod名1 pod名2 pod名3
[root@master1 ~]# kubectl get pods |awk 'NR>1 {print $1}'
|xargs kubectl delete pod

资源限制

[root@master1 ~]# vim pod3.yml
apiVersion: v1
kind: Namespace
metadata:
name: namespace1
---
apiVersion: v1
kind: Pod
metadata:
name: pod-stress3
namespace: namespace1
spec:
containers:
- name: c1
image: polinux/stress
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "200Mi"
requests:
memory: "150Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang","1"]

[root@master1 ~]# kubectl apply -f pod3.yml
namespace/namespace1 unchanged
pod/pod-stress3 created

[root@master1 ~]# kubectl get pod -n namespace1
NAME READY STATUS RESTARTS AGE
pod-stress2 1/1 Running 0 2m2s
pod-stress3 0/1 OOMKilled 4 115s

查看会发现pod-stress3这个pod状态变为OOMKilled,因为它是内存不足所
以显示Container被杀死

说明: 一旦pod中的容器挂了,容器会有重启策略, 如下:
Always:表示容器挂了总是重启,这是默认策略
OnFailures:表容器状态为错误时才重启,也就是容器正常终止时才重启
Never:表示容器挂了不予重启
对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推

Pod 状态

像单独的容器应用一样,Pod并不是持久运行的。Pod创建后,Kubernetes为其分配一个UID,并且通过Controller调度到Node中运行,然后Pod一直保持运行状态直到运行正常结束或者被删除。在Node发生故障时,Controller负责将其调度到其他的Node中。Kubernetes为Pod定义了几种状态,分别如下:

Pending,Pod已创建,正在等待容器创建。经常是正在下载镜像,因为这一步骤最耗费时间。

Running,Pod已经绑定到某个Node并且正在运行。或者可能正在进行意外中断后的重启。

Succeeded,表示Pod中的容器已经正常结束并且不需要重启。

Failed,表示Pod中的容器遇到了错误而终止。

Unknown,因为网络或其他原因,无法获取Pod的状态。

Pod详细介绍以及调度 (自我总结篇)_第2张图片
image
Pod详细介绍以及调度 (自我总结篇)_第3张图片
image

POD的生命周期

容器启动

1. pod中的容器在创建前,有初始化容器(init container)来进行初始化环境

2. 初化完后,主容器(main container)开始启动

3. 主容器启动后,有一个post start的操作(启动后的触发型操作,或者叫启动后钩子)

4. post start后,就开始做健康检查,第一个健康检查叫存活状态检查(liveness probe ),用来检查主容器存活状态的

5. 第二个健康检查叫准备就绪检查(readiness probe),用来检查主容器是否启动就绪

容器终止

1. 可以在容器终止前设置pre stop操作(终止前的触发型操作,或者叫终止前钩子)

2. 当出现特殊情况不能正常销毁pod时,大概等待30秒会强制终止

3. 终止容器后还可能会重启容器(视容器重启策略而定)。

回顾容器重启策略

Always:表示容器挂了总是重启,这是默认策略

OnFailures:表容器状态为错误时才重启,也就是容器正常终止时不重启

Never:表示容器挂了不予重启

对于Always这种策略,容器只要挂了,就会立即重启,这样是很耗费资源的。所以Always重启策略是这么做的:第一次容器挂了立即重启,如果再挂了就要延时10s重启,第三次挂了就等20s重启...... 依次类推

HealthCheck健康检查

当Pod启动时,容器可能会因为某种错误(服务未启动或端口不正确)而无法访问等。

容器探测的类型

ExecAction:在容器中执行命令,状态码为0表示成功,否则即为不健康状态。

TCPSocketAction:与容器TCP端口建立连接进行诊断,端口能够成功即为正常,否则为不健康状态

HTTPGetAction: 向容器内指定IP 和 端口发送 http 请求,响应码为2xx 或者 3xx即为成功

livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器进行重启。如果容器不提供存活探针,则默认状态为Success。

readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。

当Pod 被删除的时候 如果用户设置了 hook 则会执行hook的操作 post stop hook, 执行完毕之后删除Pod

POD调度流程

Pod详细介绍以及调度 (自我总结篇)_第4张图片
image.png

1.用户使用create yaml创建pod,请求给apiseerver,apiserver.将yaml中的属性信息(metadata)写入etcd
2.apiserver触发watch机制准备创建pod,信息转发给调度器,调度器使用调度算法选择node,调度器将node信息给apiserver,apiserver_将绑定的node信息写入etcd
3.apiserver又通过watch机制,调用kubelet,指定pod信息,触发docker run命 令创建容器
4.创建完成之后反馈给kubelet, kubelet又将pod的状态信息给apiserver,
5.apiserver又将pod的状态信息写入etcd。
6.其中kubectl get pods命令调用的时etcd_的信息

Pod详细介绍以及调度 (自我总结篇)_第5张图片
image.png

nodename

[root@master1 ~]# vim pod-nodename.yml 
apiVersion: v1 
kind: Pod 
metadata: 
      name: pod-nodename 
spec: nodeName: 192.168.122.13 
# 通过 nodeName调度到192.168.122.13(node1)节点 
containers:
      - name: nginx 
      image: nginx:1.15-alpine

nodeselector

[root@master1 ~]# kubectl label nodes 192.168.122.14 bussiness=game 
node/192.168.122.14 labeled
[root@master ~]# vim pod-nodeselector.yml 
apiVersion: v1 
kind: Pod 
metadata:
       name: pod-nodeselect
spec:
     nodeSelector: # nodeSelector节点 选择器
     bussiness: game # 指定调度到标签为 bussiness=game的节点
     containers: 
      - name: nginx 
             image: nginx:1.15-alpine

官方案例:liveness-exec

[root@master ~]# vim pod-liveness-exec.yml
apiVersion: v1
kind: Pod
metadata:
    name: liveness-exec
    namespace: default
spec:
    containers:
    - name: liveness
    image: busybox
    imagePullPolicy: IfNotPresent
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy;
sleep 600
    livenessProbe:
      exec:
          command:
          - cat
          - /tmp/healthy
      initialDelaySeconds: 5 # pod启动延迟5秒后探测
      periodSeconds: 5 # 每5秒探测1

      ```

启动参数中:执行以下命令 创建一个文件,等了30秒删除掉,又等600秒,

Initial delay seconds: 初始延迟等5秒之后才开始检测.

PeriodSeconds: 5    每隔5秒去检测

根据以上逻辑检测5-6次,在这期间是可以运行的,之后就按重启策略来。sleep 600秒为了确定检测出问题。

### POD的故障排除

![image.png](https://upload-images.jianshu.io/upload_images/6487552-bb5df49f85219c8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


## 排错命令
kubectl describe pod pod名
kubectl logs pod [-c CONTAINER]
kubectl exec POD [-c CONTAINER] --COMMAND [args...]



你可能感兴趣的:(Pod详细介绍以及调度 (自我总结篇))