一、序言
pod作为k8s中运行的最小单元可通过配置生命的方式进行创建,Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。
二、pod
一、什么是pod
Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。
pod处于逻辑理解的层面,在衍生出来的同时pod会自动生产一个pause容器,对pod内部的容器进行通信管理。
二、使用pod
pod在常规的两种使用方法
1、运行单个容器的pod:等于直接在容器上面套了一层pod,满足k8s运行资源的基本要求。
2、运行多个有协作功能的容器:od 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的“边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
pod模板
简单样例
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
在生产或者正式环境中,工作负载资源(Deployment、StatefulSet、DaemonSet、Cornjob)的控制器通常使用 Pod 模板(Pod Template)来创建 Pod 并管理。
优点在于:pod在某个节点调度失败,他就会被kubelet上的上报组件Cadvisor监测到,获取非running状态上报给controller-manager,controller-manager内部根据不同控制器算法重新分配调度信息搭配restart的设定,直到pod处于running状态。
Pod资源yaml模板
apiVersion: v1 # 【必须】版本号
kind: Pod # 【必选】Pod
metadata: # 【必选-Object】元数据
name: String # 【必选】 Pod的名称
namespace: String # 【必选】 Pod所属的命名空间
labels: # 【List】 自定义标签列表
- name: String
annotations: # 【List】 自定义注解列表
- name: String
spec: # 【必选-Object】 Pod中容器的详细定义
containers: # 【必选-List】 Pod中容器的详细定义
- name: String # 【必选】 容器的名称
image: String # 【必选】 容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] # 【String】 镜像拉取策略
command: [String] # 【List】 容器的启动命令列表,如果不指定,则使用镜像打包时使用的启动命令
args: [String] # 【List】 容器的启动命令参数列表
workingDir: String # 容器的工作目录
volumeMounts: # 【List】 挂载到容器内部的存储卷配置
- name: String # 引用Pod定义的共享存储卷的名称,需使用volumes[]部分定义的共享存储卷名称
mountPath: Sting # 存储卷在容器内mount的绝对路径,应少于512个字符
readOnly: Boolean # 是否为只读模式,默认为读写模式
ports: # 【List】 容器需要暴露的端口号列表
- name: String # 端口的名称
containerPort: Int # 容器需要监听的端口号
hostPort: Int # 容器所在主机需要监听的端口号,默认与containerPort相同。设置hostPort时,同一台宿主机将无法启动该容器的第二份副本
protocol: String # 端口协议,支持TCP和UDP,默认值为TCP
env: # 【List】 容器运行前需设置的环境变量列表
- name: String # 环境变量的名称
value: String # 环境变量的值
resources: # 【Object】 资源限制和资源请求的设置
limits: # 【Object】 资源限制的设置
cpu: String # CPU限制,单位为core数,将用于docker run --cpu-shares参数
memory: String # 内存限制,单位可以为MB,GB等,将用于docker run --memory参数
requests: # 【Object】 资源限制的设置
cpu: String # cpu请求,单位为core数,容器启动的初始可用数量
memory: String # 内存请求,单位可以为MB,GB等,容器启动的初始可用数量
# 【Object】 对Pod内各容器健康检查的设置,当探测无响应几次之后,系统将自动重启该容器。
# 可以设置的方法包括:exec、httpGet和tcpSocket。对一个容器只需要设置一种健康检查的方法
livenessProbe:
exec: # 【Object】 对Pod内各容器健康检查的设置,exec方式
command: [String] # exec方式需要指定的命令或者脚本
httpGet: # 【Object】 对Pod内各容器健康检查的设置,HTTGet方式。需要指定path、port
path: String
port: Number
host: String
scheme: String
httpHeaders:
- name: String
value: String
tcpSocket: # 【Object】 对Pod内各容器健康检查的设置,tcpSocket方式
port: Number
initialDelaySeconds: Number # 容器启动完成后首次探测的时间,单位为s
timeoutSeconds: Number # 对容器健康检查的探测等待响应的超时时间设置,单位为s,默认值为1s。
periodSeconds: Number # 对容器健康检查的定期探测时间设置,单位为s,默认10s探测一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: Boolean
# Pod的重启策略 一旦终止运行,都将重启 | 终止后kubelet将报告给master,不会重启
# 只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常终止(退出码为0),则不会重启。
restartPolicy: [Always | Never | OnFailure]
nodeSelector: object # 设置Node的Label,以key:value格式指定,Pod将被调度到具有这些Label的Node上
imagePullSecrets: # 【Object】 pull镜像时使用的Secret名称,以name:secretkey格式指定
- name: String
# 是否使用主机网络模式,默认值为false。设置为true表示容器使用宿主机网络,不再使用docker网桥,该Pod将无法在同一台宿主机上启动第二个副本
hostNetwork: Boolean
volumes: # 【List】 在该Pod上定义的共享存储卷列表
- name: String # 共享存储卷的名称,volume的类型有很多emptyDir,hostPath,secret,nfs,glusterfs,cephfs,configMap
emptyDir: {} # 【Object】 类型为emptyDir的存储卷,表示与Pod同生命周期的一个临时目录,其值为一个空对象:emptyDir: {}
hostPath: # 【Object】 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: String # Pod所在主机的目录,将被用于容器中mount的目录
secret: # 【Object】类型为secret的存储卷,表示挂载集群预定义的secret对象到容器内部
secretName: String
items:
- key: String
path: String
configMap: # 【Object】 类型为configMap的存储卷,表示挂载集群预定义的configMap对象到容器内部
name: String
items:
- key: String
path: String
pod创建过程
1.kubectl提交创建pod命令,api响应命令,通过一系列认证授权,把pod数据存储到etcd,创建deployment资源并初始化.
2.controller通过list-watch机制,监测发现新的deployment,将该资源加入到内部工作队列,发现该资源没有关联的pod和replicaset,启用deployment controller创建replicaset资源,再启用replicaset controller创建pod.
3.所有controller正常后.将deployment,replicaset,pod资源更新存储到etcd.
4.scheduler通过list-watch机制,监测发现新的pod,经过主机过滤主机打分规则,将pod绑定(binding)到合适的主机.
5.将绑定结果存储到etcd.
6.kubelet每隔 20s(可以自定义)向kube-apiserver通过NodeName 获取自身Node上所要运行的pod清单.通过与自己的内部缓存进行比较,新增加pod.
7.启动pod启动容器.
8.把本节点的容器信息pod信息同步到etcd.
pod终止过程
1)用户向 apiServer 发送删除 pod 对象的命令
2)apiServcer 中的 pod 对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod 被视为 dead
3)将 pod 标记为 terminating 状态
4)kubelet 在监控到 pod 对象转为 terminating 状态的同时启动 pod 关闭过程
5)端点控制器监控到 pod 对象的关闭行为时将其从所有匹配到此端点的 service 资源的端点列表中移除
6)如果当前 pod 对象定义 了preStop 钩子处理器,则在其标记为 terminating 后即会以同步的方式启动执行
7)pod 对象中的容器进程收到停止信号
8)宽限期结束后,若 pod 中还存在仍在运行的进程,那么 pod 对象会收到立即终止的信号
9)kubelet 请求 apiServer 将此 pod 资源的宽限期设置为0从而完成删除操作,此时 pod 对于用户已不可见
pod生命周期
Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者 被终止。
过程如下:
pod 创建过程
运行初始化容器(init container)过程
运行主容器(main container)
容器启动后钩子(post start)、容器终止前钩子(pre stop)
容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
pod终止过程
生命周期内的五种状态:
挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成(如:nodeName: node3 指定调度到 node3 节点上,而这个 node3 节点不存在,就会出现 Pending 状态)或者仍处于下载镜像的过程中
运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
pod 底层网络和数据存储
pod 内部的容器也是一个独立的沙箱环境,因此也有自己的 ip 和 端口。如果内部容器还是通过 ip:port 来通信,相当于还是远程访问,这样的话性能会受到一定的影响。如何提高内部容器之间访问的性能呢?
pod 底层
pod 内部容器创建之前,必须先创建 pause 容器。pause 有两个作用:共享网络和共享存储。
每个服务容器共享 pause 存储,不需要自己存储数据,都交给 pause 维护。
pause 也相当于这三个容器的网卡,因此他们之间的访问可以通过 localhost 方式访问,相当于访问本地服务一样,性能非常高(就像本地几台虚拟机之间可以 ping 通)
pod命令
查看 Pod 状态
#kubectl get pods <pod-name> -n <namespace> -o wide
[root@localhost docker]# kubectl get pods -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-6c5f44f974-bmnk8 1/1 Running 0 139m 172.30.0.3 192.168.52.129 <none> <none>
kube-system coredns-6c5f44f974-cn4mb 1/1 Running 0 139m 172.30.0.2 192.168.52.129 <none> <none>
kube-system kube-flannel-ds-7q4ws 1/1 Running 0 139m 192.168.52.129 192.168.52.129 <none> <none>
kube-system kube-flannel-ds-bpkkc 1/1 Running 0 139m 192.168.52.130 192.168.52.130 <none> <none>
查看 Pod 的 yaml /json配置
#kubectl get pods <pod-name> -n <namespace> -o yaml
#kubectl get pods <pod-name> -n <namespace> -o json
查看 Pod 的事件
#kubectl describe pods <pod-name> -n <namespace>
查看 Pod 容器日志
#kubectl logs -n <namespace> <pod-name> [-c <container-name>]
# 可以 tailf 该 Pod 的日志观察进度
#kubectl logs kibana-logging-7445dc9757-pvpcv -n kube-system -f
[root@localhost docker]# kubectl logs coredns-6c5f44f974-bmnk8 -n kube-system
.:53
[INFO] plugin/reload: Running configuration MD5 = 41c01b5c37f0e477723c54b29a389895
CoreDNS-1.8.6
linux/amd64, go1.17.1, 13a9191
查看 kube-system 命名空间下的所有service
#kubectl get svc -n kube-system
[root@localhost docker]# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.254.0.2 <none> 53/UDP,53/TCP,9153/TCP 148m
生产中应用部署(pod 发布)的注意事项
1)集群节点设置(lable 和 taint)
2)创建密钥文件(secret)
3)配置文件(configmap)
4)对于有状态的应用,还需要创建存储(pv和pvc)
5)资源限制(resources)
6)亲和性设置(affinity)
7)容忍设置(tolerations)
8)定向调度(nodeSelector)
9)探针设置(livenessProbe和readinessProbe)
pod健康检查
可以去看下三大探针
启动探针(Startup Probe):判断容器内的应用是否启动完成(在启动探针判断成功前,就绪探针和存活探针将不会执行)
就绪探针(Readiness Probe):判断容器是否已经就绪,若未就绪,容器将会处于未就绪,未就绪的容器,不会进行流量的调度。
存活探针(Liveness Probe):判断容器内的应用程序是否正常,若不正常,K8s 将会重新重启容器
Pod 的重启策略(restartPolicy)
Always:无论因何种原因、以何种方式终止,kubelet 都将重启该 Pod,默认设置
OnFailure:仅在 Pod 对象以非 0 方式退出时才将其重启
Never:不再重启 Pod
restartPolicy 适用于 Pod 对象中的所有容器,而且它仅用于控制在同一个节点上重新启动 Pod 对象的相关容器,首次需要重启的容器,其重启操作会立即执行,而再次重启操作将由 kubelet 延迟一段时间后进行,反复的重启操作的延迟时间依次为 10秒、20秒、40秒、80秒、160秒和300秒,300秒是最大延迟时间。