Kubernetes-4.Pods
- docker version:19.03.14
- kubernetes version:1.19.4
** 已了解Kubernetes的组成、安装、以及kubectl基本命令使用
本文概述Kubernetes中workloads资源控制器基本信息以及Pods资源的介绍。
workloads
工作负载(workloads)是在Kubernetes上运行的应用程序。无论负载是单一组件还是有多个一同工作的组件构成,在Kubernetes中均可以在一组Pods中运行它。
在Kubernetes中,Pod代表的是集群上处于运行状态的一组容器。
Pods有确定的生命周期,使用中通常并不需要直接管理每个Pod。可以使用负载资源来管理一组Pods。这些资源配置控制器(controllers)来确保合适类型的、处于运行状态的Pod个数是正确的且与指定状态是相一致的。
资源控制器
Kubernetes常用资源、对象:
- Pods
- workloads资源
- 服务发现及均衡
- 配置与存储
- 集群级资源
- 元数据型资源
基础介绍
workload主要包含以下资源:
- Deployment和ReplicaSet(替换ReplicationController)。Deployment很适合用来管理集群上的无状态应用。
- StatefulSet。运行有状态应用控制器。
- DaemonSet。定义提供节点本地支撑设施的Pods。
- Job和Cronjob。定义一些一直运行到结束并停止的任务。Job为一次性任务,Cronjob为重复性任务。
服务发现及均衡资源:
- Service
- Ingress
存储与配置资源:
- Volume
- CSI(容器存储接口)
- ConfigMap、Secret
- DownwardAPI
集群级资源:
- Namespace
- Node
- Role,ClusterRole
- RoleBinding,ClusterRoleBinding
元数据型资源:
- HPA
- PodTamplate
- LimitRange
Pods
Pods是在kubernetes中最小可部署的计算单元。
Pod是一组(一个或多个)容器。这些容器共享存储、网络、以及容器运行声明。
Pod类似于共享名称空间和文件系统卷的一组Docker容器。
每个Pod都运行给定应用程序的单个实例,希望横向扩展应用程序,则应该使用多个Pod,每个实例使用一个Pod,其被称为副本(Replication)。通常使用一种workload资源控制器来创建和管理一组Pod副本。
通过命令行使用的Pod操作基础
# 创建一个名称为nginx的pod,镜像为nginx:latest,默认存在于default名称空间
kubectl run nginx --image=nginx
# 查看;使用-O wide可查看详细信息;pod可简写为po
kubectl get po -o wide
# 为其创建一个服务(暴露端口);--type可指为ClusterIP、NodePort,默认ClusterIP;--port即服务端口;--target-port即后端端口,--protocol即协议、默认TCP;--name即为此service指定名称,可选
kubectl expose po webapp --type=ClusterIP --port=30080 --target-port=80 --protocol=TCP --name=websvc
# 查看service可以看到刚才expose的服务端口;service可简写为svc;集群内任意主机可以通过ClusterIP:Port进行访问
kubectl get svc
# 删除此pod
kubectl delete po
清单文件
通常使用时很少通过命令行进行创建,一般使用清单文件创建。
清单文件格式
通常使用yaml格式
- 在文件中字典可使用花括号,或换行缩进
- 在文件中列表数据可使用中括号或中划线
- 在一个文件中有多个yaml配置段使用三个中划线对其分隔
示例:
---
json:
- rigid
- better for data interchange
yaml:
- slim and flexible
- better for configuration
object:
key: value
array:
- null_value:
- boolean: true
- integer: 1
paragraph: |
Blank lines denote
paragraph breaks
content: |-
Or we
can auto
convert line breaks
to save space
通过清单文件创建Pod
示例:
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
namespace: default
spec:
containers:
- name: webapp
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: web-port
containerPort: 80
restartPolicy: Never
创建此文件保存至demo-pod.yaml文件,通过命令行创建:
# 当第一次创建此资源可以使用create,当已有该名称的资源存在则不能使用create
kubectl create -f demo-pod.yaml
# 使用apply则资源不存在则创建,资源已存在则更新资源状态为文件中的配置
kubectl apply -f demo-pod.yaml
大部分清单文件的的字段:
apiVersion:使用Kubernetes的哪个API资源
kind:资源类别
metadata:元数据
spec:期望状态
status:当前状态;该字段由集群维护
以上示例解释:
apiVersion:指定API资源;Pod控制器使用的api为v1
kind:指定资源类别;Pod资源属于Pod类别
metadata.name:指定此Pod的名称
metadata.namespace:指定此Pod所属的名称空间
spec.containers.name:为容器指定名称
spec.containers.image:指定容器的镜像
spec.containers.imagePullPolicy:指定容器的镜像拉取策略;可使用值为Always、Never、IfNotPresent;
如果镜像的tag是latest则默认值是Always,非latest标签则默认为IfNotPresent;指定Always表示已存在镜像且标签且为latest则总是拉取最新的latest,指定为Never表示永不拉取镜像,指定为IfNotPresent表示不存在则拉取镜像
spec.containers.ports:声明容器要公开的端口列表
spec.containers.ports.name:声明容器要公开的端口的名称
spec.containers.ports.name.containerPort:容器要暴露的端口
spec.restartPolicy:重启策略;Always(默认)、OnFailure、Never
explain
列出支持的资源的字段,此命令描述每个支持的API资源的字段。
通过此命令可以查看清单文件定义时可以使用的资源、字段等详细内容。
kubectl explain RESOURCE [options]
# 列出pod资源spec字段下的子字段
kubectl explain pods.spec
# 列出secret资源支持的字段
kubectl explain secret
# 列出pod资源spec字段中containers下livenessProbe字段支持的字段
kubectl explain pod.spec.containers.livenessProbe
Pod的生命周期
Pod中创建一个容器可能会包含一些初始化容器(辅助容器),初始化容器完成工作后退出,而后主要容器启动,启动容器后可能会需要postStart等操作,结束过程前可能会需要preStop等操作;其生命周期中可能需要持续保持着livenessProbe及readinessProbe操作。
Pod阶段
Pod的status字段是一个PodStatus对象,其中包含一个phase字段。
Pod的阶段(Phase)是Pod在其生命周期中所处位置的简单宏观概述。
取值 | 描述 |
---|---|
Pending | Pod 已被Kubernetes系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待Pod被调度的时间和通过网络下载镜像的时间, |
Running | Pod已经绑定到了某个节点,Pod中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。 |
Succeeded | Pod中的所有容器都已成功终止,并且不会再重启。 |
Failed | Pod中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。 |
Unknown | 因为某些原因无法取得Pod的状态。这种情况通常是因为与Pod所在主机通信失败。 |
容器状态
Kubernetes会跟踪Pod中每个容器的状态,就像它跟踪Pod总体上的阶段(Phase)一样。
一旦调度器将Pod分配给某个节点,kubelet就通过容器运行时开始为Pod创建容器。容器的状态有三种:Waiting、Running、Terminated。
检查Pod中容器的状态,可使用kubectl describe pod <pod-name>
容器重启策略
Pod的spec
字段中restartPolicy
字段控制容器重启策略;其值为Always、OnFailure、Never,默认是Always。restartPolicy
适用于Pod中的所有容器。
Pod状况
Pod的PodStatus对象,其中包含一个PodConditions属组。Pod可能通过也可能未通过其中的一些状况测试。
PodScheduled:Pod已经被调度到某节点;
ContainersReady:Pod中所有容器都已就绪;
Initialized:所有的Init容器都已成功启动;
Ready:Pod可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。
字段名称 | 描述 |
---|---|
type | Pod状况的名称 |
status | 表明该状况是否使用,可能的值为True、False、Unknown |
lastProbeTime | 上次探测Pod状况时的时间戳 |
lastTransitionTime | Pod上次从一种状态转换到另一种状态时的时间戳 |
reason | 机器刻度的驼峰编码(UpperCamelCase)的文字,表述上次状况变换的原因 |
message | 人类可读的消息,给出上次状况转换的详细 |
Pod的终止
终止Pod的过程:
-
发送删除Pod请求,Pod的优雅终止期限默认值30秒。
-
更新API服务器中的Pod对象,记录涵盖优雅终止限期在内Pod的最终死期。超出所计算时间则认为Pod已死(dead)。在Pod运行的节点上,kubelet一旦检测到Pod被标记为正在终止(Terminating ),则开始关闭在本节点上此Pod的进程。
1 如果Pod中的任一容器定义了preStop回调,则开始运行此回调逻辑。如果超出了优雅终止限期,preStop仍在运行,则会给予该Pod一次性的宽限期(2秒)。如果preStop回调需要较长的时间,可以通过更改
terminationGracePeriodSeconds
属性值使其正常工作。
2 kubelet发送TERM信号给每个容器中pid为1的进程 -
从对应的端点列表、工作负载资源中移除该Pod,ReplicaSets不再将其视为能够提供服务的副本。
-
超出终止宽限期限时,kubelet会触发强制关闭过程。容器运行时会向Pod中所有容器内仍在运行的进程发送SIGKILL信号。 kubelet也会清理隐藏的pause容器(如果有)。
-
kubelet触发强制从API服务器上删除Pod对象的逻辑,并将优雅终止期限设置为0(意味着马上删除)。
-
API服务器删除Pod的API对象。
强制终止Pod
默认情况下,所有的删除操作都会附有30秒钟的宽限期限。 kubectl delete
命令支持--grace-period=<seconds>
选项,允许重载默认值,设定自己希望的期限值。
将宽限期限强制设置为0意味着立即从API服务器删除Pod。
必须在设置--grace-period=0
的同时额外设置--force
参数才能发起强制删除请求。
执行强制删除操作时,API服务器不再等待来自kubelet的、关于Pod已经在原来运行的节点上终止执行的确认消息。API服务器直接删除Pod对象,这样新的与之同名的Pod即可以被创建。在节点侧,被设置为立即终止的Pod仍然会在被强行杀死之前获得一点点的宽限时间。
失效Pod的垃圾收集
对于已失败的Pod而言,对应的API对象仍然会保留在集群的API服务器上,直到用户或者控制器进程显式地将其删除。
控制面组件会在Pod个数超出所配置的阈值(根据kube-controller-manager的 terminated-pod-gc-threshold设置)时删除已终止的Pod(阶段值为Succeeded或Failed)。这一行为会避免随着时间演进不断创建和终止Pod而引起的资源泄露问题。
容器探针
Probe是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler(处理程序)。有三种类型的处理程序:
ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
TCPSocketAction:对容器的IP地址上的指定端口执行TCP检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction:对容器的IP地址上指定端口和路径执行HTTP Get请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
Success:容器通过了诊断。
Failure:容器未通过诊断。
Unknown:诊断失败,因此不会采取任何行动。
针对运行中的容器,kubelet可以选择是否执行一下三种探针,以及如何针对探测结果作出反应:
livenessProbe:存活状态探测;指示容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据其重启策略决定未来。如果不指定存活状态探针,则默认状态为Success
。
readinessProbe:就绪状态探测;指示容器是否准备好为请求提供服务。如果探测失败,端点控制器将从与Pod匹配的所有服务的端点列表中删除该Pod的IP地址(即未准备就绪不会将其加入到service的后端)。初始延迟之前的就绪状态值默认为Failure
。如果容器不提供就绪状态探针,则默认状态为Success
。
startupProbe:启动状态探测;指示容器中的应用是否已经启动。如果提供了启动探针,则所有其它探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet将杀死容器,以其重启策略重启。如果容器没有提供启动探测探针,则默认状态为Success
。
存活状态探针
如果容器因为进程遇到问题的情况下自行崩溃,则不一定需要存活状态探针。
如果希望的是容器在探测失败时被杀死并重启,这种情况下就应当使用存活状态探针,并且指定容器重启策略。
常用参数:
pod.spec.containers.livenessProbe:启用livenessProbe
pod.spec.containers.livenessProbe.exec:使用命令方式探测,见#容器探针#ExecAction内容
pod.spec.containers.livenessProbe.httpGet:使用http get方式探测,见#容器探针#HTTPGetAction内容
pod.spec.containers.livenessProbe.tcpSocket:使用TCP Socket方式探测,见#容器探针#TCPSocketAction内容
pod.spec.containers.livenessProbe.initialDelaySeconds:延迟探测时间
pod.spec.containers.livenessProbe.periodSeconds:探测时间间隔,默认10s
pod.spec.containers.livenessProbe.successThreshold:成功N次则将状态装换为成功,默认1,最小1
pod.spec.containers.livenessProbe.failureThreshold:失败N次则将状态装换为失败,默认1,最小1
pod.spec.containers.livenessProbe.timeoutSeconds:探测超时时间(秒),默认1,最小1
示例:
使用存活探针探测某个文件是否存在,不存在则视为故障,使其重启且生成此文件。
根据清单文件创建此pod,观察其信息(kubectl describe po liveness-exec pod)中的Events,经过一定次数的探测后,其会提示Liveness probe failed,而后重启此Pod中的容器。
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "touch /tmp/healthy; sleep 60; rm -f /tmp/healthy; sleep 3600"]
livenessProbe:
exec:
command: ["test", "-e", "/tmp/healthy"]
initialDelaySeconds: 3
periodSeconds: 5
restartPolicy: OnFailure
就绪状态探针
就绪状态探针的存在意味着Pod将在启动阶段不接收任何数据,并且只有在就绪状态探针探测成功后才开始接收数据。
假如容器需要在启动时加载大量数据、配置文件或应用初始化等操作,则应当使用就绪状态探针。
常用参数:
pod.spec.containers.readinessProbe:启用readinessProbe
其它参数同livenessProbe
示例:
使用就绪状态探针探测Web服务是否准备就绪,就绪后才开始接受请求。
创建此Pod,观察其READY状态(kubelet get po readiness-httpget-pod),在指定的就绪状态检测次数总和判定为成功之前和之后,其状态变化,则是readinessProbe探针状态的变化。
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: nginx
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
initialDelaySeconds: 3
periodSeconds: 5
restartPolicy: Never
启动状态探针
对于所包含的容器需要较长时间才能启动就绪的Pod而言,则应当使用启动探针。如果容器启动时间通常超出initialDelaySeconds + failureThreshold × periodSeconds总值,则应该设置一个启动探测。
periodSeconds的默认值是10秒。应该将其failureThreshold设置得足够高,以便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。这一设置有助于减少死锁状况的发生。
常用参数:
pod.spec.containers.startupProbe: 启用startupProbe
其它参数同livenessProbe
lifecycle
在Pod的生命周期中,还存在postStart和preStop两个处理函数。
postStart:当一个容器启动后,立即执行postStart事件
preStop:在容器被终结之前,执行preStop事件
postStart
注意:spec.containers.command执行顺序优先于postStart中的exec.command
常用参数:
pod.spec.containers.lifecycle.postStart:启用postStart
pod.spec.containers.lifecycle.postStart.exec:使用命令行执行事件
pod.spec.containers.lifecycle.postStart.httGet:使用http get方法执行事件
pod.spec.containers.lifecycle.postStart.tcpSocket:使用TCP Socket方法执行事件
示例:
创建一个postStart事件,在容器启动后做一些操作
创建此Pod,而后访问其/hello.html文件,则证实postStart处理的事件
apiVersion: v1
kind: Pod
metadata:
name: poststart-pod
namespace: default
spec:
containers:
- name: poststart-pod
image: nginx
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /hello.html
initialDelaySeconds: 3
periodSeconds: 5
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo HelloWebServer >>/usr/share/nginx/html/hello.html"]
restartPolicy: Never
preStop
pod.spec.containers.lifecycle.preStop:启用preStop
其它同postStart