一、什么是POD
Pod是Kubernetes最重要的基本概念,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。
二、POD的生命周期
三、pause容器
用"kubernetes/pause"镜像为每个Pod都创建一个容器。该Pause容器用于接管Pod中所有其他容器的网络。每创建一个新的Pod,kubelet都会先创建一个Pause容器, 然后创建其他容器。"kubernetes/pause"镜像大概有270KB,是个非常小的容器镜像。
四、初始化容器initContainers
因为init容器具有与应用容器分离的单独镜像,所以它们启动相关代码有具有如下优势:
- 它们可以包含并运行实用工具,但是出去安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
- 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具。
- 应用程序镜像可以分离出创建和部署的角色,而没必要联合它们构建一个单独镜像。
- Init容器使用Linux namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它能够访问secret的权限,而应用程序则不能。(分权限治理)
- 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
注意事项:
- 在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。
- 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的RestartPolicy指定的策略进行重试。如果是Never,它不会重新启动。
- 如果Pod重启,则Init容器会重启执行。
- init container不能设置readinessProbe探针,因为必须在它们成功运行后才能继续运行在Pod中定义的普通容器。
五、POD重启策略
当某个容器异常退出或者健康检查失败, kubelet将根据RestartPolicy的设置来进行相应的操作, 重启策略有Always , OnFailure, Never。
Always:Pod一旦终止运行,无论容器是如何终止的,kubelet都将重启它。
OnFailure:当容器终止运行非零退出时,由kubelet自动重启该容器。
Never:不论容器运行状态如何,kubelet都不会重启该容器。
六、imagePullPolicy镜像拉取策略
Always: 表示每次都尝试重新拉取镜像
IfNotPresent: 表示如果本地有镜像, 则使用本地的镜像, 本地不存在时拉取镜像
Never: 表示仅使用本地镜像
七、三种探针startupProbe、livenessProbe和readinessProbe
startupProbe探针:用于判断容器内应用程序是否已经启动,如果配置了startuprobe,优先于其它两种探测支行,直到它成功为止,成功后将不再进行startupProbe探测。
LivenessProbe探针:用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做相应的处理。
如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
ReadinessProbe探针:用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系
也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回
后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。
包括三种探测方式:
- ExecAction:在容器内部执行一个命令,如果该命令的返回码为0,则表明容器健康。
livenessProbe: exec: command: ['test', '-e', '/tmp/live'] initialDelaySeconds: 1 # 启动容器后进行首次健康检查的等待时间 periodSeconds: 3 # 检测失败后重试时间
- TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。
readinessProbe: tcpSocket: port: 80 initialDelaySeconds: 5 # 启动容器后进行首次健康检查的等待时间 failureThreshold: 30 # 检测失败后重试时间 periodSeconds: 10 # 执行探测的间隔时间
- HTTPGetAction:通过容器的IP地址、 端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。
livenessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 1 periodSeconds: 3
一些可选参数
timeoutSeconds:探测超时的秒数。默认为1秒。
initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s
periodSeconds:检测失败后重试时间3秒
failureThreshold:失败的容忍次数失败几次 判断为彻底失败,放弃检查并重启
successThreshold:失败后探测成功的最小成功次数。默认为1。最小值为1。
八、资源限制requests和limits
- Request工作原理
Request 的值并不代表给容器实际分配的资源大小,用于提供给调度器。调度器会检测每个节点可用于分配的资源(可分配资源减 request 之和),同时记录每个节点已经被分配的资源(节点上所有 Pod 中定义的容器 request 之和)。如发现节点剩余的可分配资源已小于当前需被调度的 Pod 的 request,则该 Pod 就不会被调度到此节点。反之,则会被调度到此节点。
- 避免 request 与 limit 值过大
若服务使用单副本或少量副本,且 request 及 limit 的值设置过大,使服务可分配到足够多的资源去支撑业务。则某个副本发生故障时,可能会给业务带来较大影响。当 Pod 所在节点发生故障时,由于 request 值过大,且集群内资源分配的较为碎片化,其余节点无足够可分配资源满足该 Pod 的 request,则该 Pod 无法实现漂移,无法自愈,会加重对业务的影响。
建议尽量减小 request 及 limit,通过增加副本的方式对服务支撑能力进行水平扩容,使系统更加灵活可靠。
resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m # 1000m=1核CPU memory: 2048Mi
九、command 容器的启动命令
创建 Pod 时,可以为其下的容器设置启动时要执行的命令及其参数。如果要设置命令,就填写在配置文件的 command 字段下,如果要设置命令的参数,就填写在配置文件的 args 字段下。一旦 Pod 创建完成,该命令及其参数就无法再进行更改了。参数会覆盖docker镜像中的启动命令。
# 用shell脚本的方式执行命令 command: ["/bin/sh"] args: ["-c", "while true; do echo hello; sleep 10;done"] # 或者只写一条---------------------------------------------- command: ["sh", "-c", "/startup.sh"] # 使用环境变量来设置参数 env: - name: MESSAGE value: "hello world" command: ["/bin/echo"] args: ["$(MESSAGE)"]
十、env环境变量
env: - name: MESSAGE value: "hello world" command: ["/bin/echo"] args: ["$(MESSAGE)"] env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name
十一、POD的调度
在Kubernetes平台上, 我们很少会直接创建一个Pod, 在大多数情况下会通过RC、 Deployment、 DaemonSet、 Job等控制器完成对一组Pod副本的创建、 调度及全生命周期的自动控制任务。
- 11.1 Deployment或者ReplicaSet
主要功能之一就是自动部署一个容器应用的多份副本, 以及持续监控副本的数量, 在集群内始终维持用户指定的副本数量。
# cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi
- 11.2 NodeSelector:定向调度
NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法。
# kubectl label node k8s-node01 app=nginx # 为k8s-node01节点打上app=nginx的标签 # kubectl get node --show-labels |grep app=nginx k8s-node01 Ready <none> 13d v1.19.0 app=nginx,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,
kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node01,kubernetes.io/os=linux # cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # 选择node标签为app=nginx的标签进行调度 app: nginx containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi # kubectl apply -f nginx-deployment.yaml # kubectl get pod -o wide # 所有的pod都调度到了k8s-node01节点上 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-7cc69bccbc-ffn88 1/1 Running 0 45s 10.244.85.205 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-mmqgw 1/1 Running 0 42s 10.244.85.207 k8s-node01 <none> <none> nginx-deployment-7cc69bccbc-t45gg 1/1 Running 0 43s 10.244.85.206 k8s-node01 <none> <none>
- 11.3 NodeAffinity Node亲和性调度
是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。
RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上( 功能与nodeSelector很像,但是使用的是不同的语法),相当于硬限制。
PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上, 但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。
# 举例
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性,要求pod在amd64节点上运行 nodeSelectorTerms: - matchExpressions: - key: beta.kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性,尽量运行在磁盘类型为ssd的节点上 - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: with-node-affinity image: k8s.gcr.io/pause:2.0
NodeAffinity语法支持的操作符包括In、 NotIn、 Exists、 DoesNotExist、 Gt、 Lt。
NodeAffinity规则设置的注意事项如下:
如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node上。
如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。
如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod
- 11.4 PodAffinity POD亲和性
和节点亲和相同, Pod亲和与互斥的条件设置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。
# 举例pod亲和性,三个pod在运行在同一个k8s节点上 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname # 同一个node为一个拓扑域 containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m memory: 2048Mi # 举例,pod反亲和性三个pod尽量运行在不同的k8s同节点上 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 1000m memory: 2048Mi
十二、污点(Taint)与容忍(Toleration)
Taint需要和Toleration配合使用,让Pod避开那些不合适的Node。在Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点, 否则无法在这些Node上运行。Toleration是Pod的属性, 让Pod能够(注意, 只是能够, 而非必须)运行在标注了Taint的Node上。
污点(Taint)
使用`kubectl taint `命令可以给革个Node节点设置污点,Node被设置上污点之后就和Pod之间存在一种相斥的关系,可以让Node拒绝Pod的高度执行,甚至将Node上已经存在的Pod驱逐出去。
# 每个污点的组成如下 key=vavlue:effect # 每个污点有一个key和value作为污点标签,其中value可以为空,effec描述污点的作用。当前tain effect支持以下三个选项: NoSchedule: 表示K8s不会将Pod调度到具有该污点的Node上 PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上 NoExecute:表示K8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去。
注:使用noexecute,k8s会直接杀死节点上的所有的pod,并在其它节点上面重新pod,如果业务都在这一个节点上业务可能会出现同时不可用的情况,建议使用for循环来杀pod。
例:for i in `kubectl get pod -n default -l app=nginx | awk {'print $1'}`; do kubectl delete pod $i -n default; done
命令设置
# 设置污点 kubectl taint node k8s-node01 key=value:NoSchedule # 查看污点 # kubectl describe node k8s-node01 | grep Taints Taints: key=value:NoSchedule # 移出污点 kubectl taint node k8s-node01 key=value:NoSchedule-
容忍(Tolerations)
设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,pod将在一定程度上不会调度到Node上,但我们可以在Pod上设置容忍,意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。
系统允许在同一个Node上设置多个Taint,也可以在Pod上设置多个Toleration。 Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为: 首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分, 剩下的没有忽略的Taint就是对Pod的效果了。
一般来说, 如果给Node加上effect=NoExecute的Taint, 那么在该Node上正在运行的所有无对应Toleration的Pod都会被立刻驱逐, 而具有相应Toleration的Pod永远不会被驱逐。 不过, 系统允许给具有NoExecute效果的Toleration加入一个可选的tolerationSeconds字段, 这个设置表明Pod可以在Taint添加到Node之后还能在这个Node上运行多久(单位为s) :
# cat nginx19.yaml apiVersion: v1 kind: Pod metadata: name: pod-3 labels: app: pod-3 spec: containers: - name: pod-3 image: nginx:1.18.0 tolerations: - key: "key" # 要与Node上设置的taint保持一致 operator: "Equal" value: "value" # 要与Node上设置的taint保持一致 effect: "NoExecute" # 要与Node上设置的taint保持一致 tolerationSeconds: 3600
十三、固定节点调度nodeName
Pod.spec.nodeName将pod直接调度到指定的node节点上,会跳过schedule的调度策略,该匹配规则是强制匹配。
# cat nginx8.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 5 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeName: k8s-node01 containers: - name: mynginx image: nginx:1.18.0 ports: - containerPort: 80 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1024Mi