共计 6856 个字符,预计需要花费 18 分钟才能阅读完成。
Kubernetes 中,容器总是以 Pod(容器组)的形式进行调度与运行。因而对 Pod 的了解与把握是学习 Kubernetes 的根底。
了解 Pod
Pod(容器组)是 Kubernetes 中最小的调度单元,每一个 Pod 都是某个应用程序的一个运行实例。以前咱们的 Web 利用都是以 Tomcat 等 Web 容器过程的模式运行在操作系统中,在 Kubernetes 中,咱们须要将 Web 利用打成镜像,以容器的形式运行在 Pod 中。
Kubernetes 不会间接治理容器,而是通过 Pod 来治理。一个 Pod 蕴含如下内容:
- 一个或多个容器,个别是一个,除非多个容器严密耦合共享资源才放在一个 Pod 中;
- 共享的存储资源(如数据卷),一个 Pod 中的容器是能够共享存储空间的;
- 一个共享的 IP 地址,Pod 中容器之间能够通过 localhost:port 彼此拜访;
- 定义容器该如何运行的选项。
Pod 中的容器可包含两种类型:
- 工作容器:就是咱们通常运行服务过程的容器
- 初始化容器:实现一些初始化操作的容器,初始化容器在工作容器之前运行,所有的初始化容器胜利执行后,才开始启动工作容器
治理 Pod
创立 Pod
在 Kubernetes 中,咱们个别不间接创立 Pod,而是通过控制器来调度治理(Deployment,StatefulSet,DaemonSet 等),这里为了便于理解,先通过 yaml 配置文件的形式定义 Pod 来间接创立 Pod。定义配置文件 pod-test.yaml 如下,
apiVersion: v1
kind: Pod
metadata:
name: pod-test # pod 名称
namespace: default # pod 创立的 namespace
spec:
containers: # pod 中容器定义
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
hostPort: 8081
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
restartPolicy: OnFailure # 重启策略
volumes: # 数据卷定义
- name: workdir
hostPath:
path: /tmp
type: Directory
其中 spec 局部的 containers 定义了该 Pod 中运行的容器,从 containers 的复数模式也能够看出一个 Pod 中是能够运行多个容器的。
执行 kubectl create
或 kubectl apply
命令创立 Pod,
[root@kmaster test]# kubectl create -f pod-test.yaml
或
[root@kmaster test]# kubectl apply -f pod-test.yaml
该 Pod 创立后将会拉取一个最新的 nginx 镜像,运行一个 nginx 容器,并将容器的 80 端口映射到宿主机的 8081 端口。
查看 Pod
可应用 kubectl get pods
命令查看以后 namesapce 下的所有 Pod,加 Pod 名称查看具体某个 Pod。如果须要查看 Pod 调度到了哪个节点,可加 -o wide
选项,如果查看 yaml 文件信息则可加 -o yaml
选项,如下所示
[root@kmaster test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-test 1/1 Running 0 116s
[root@kmaster test]# kubectl get pods pod-test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-test 1/1 Running 0 2m19s 10.244.1.42 knode2 <none> <none>
[root@kmaster test]# kubectl get pods pod-test -o yaml
如果要查看更多的信息,可应用 kubectl describe
命令,
[root@kmaster test]# kubectl describe pod pod-test
该命令输入内容如下图,
各局部阐明:
- Status: Pending,示意 Pod 的整体状态,以后处于 Pending 状态;
- State: Waiting,Pod 中每个容器都有一个本人的状态 State,以后容器 nginx 处于 Waiting 状态,Reason: ContainerCreating 示意容器还处于创立中,Ready:False 表明容器还未就绪,还不能对外提供服务;
- Conditions,这部分聚合了一些状态,第一个 Initialized:True,表明曾经实现了初始化;而第二个 Ready:False,表明 Pod 还未就绪;ContainersReady:False,表明容器还未就绪;PodScheduled:True,表明 Pod 曾经被调度到某个具体的节点上了;
- 3 中不同的状态之间的转换都会产生相应的事件,事件类型包含 Normal 与 Warning 两种,从上图可看到一个 Pulling image 的 Normal 事件,示意以后正在拉取 Pod 中容器的镜像。
当 Pod 在调度或运行中呈现问题时,咱们都能够应用 kubectl describe
命令来进行排查,通过其中的状态及事件来判断问题产生的可能起因。
进入 Pod 容器
通过 kubectl exec
命令可进入 Pod,相似于 docker exec
,如
# 如果 Pod 中只有一个容器
[root@kmaster test]# kubectl exec -it pod-test bash
root@pod-test:/#
# 如果 Pod 中有多个容器
kubectl exec -it pod-name -c container-name /bin/bash
如果一个 Pod 中有多个容器,则须要通过 -c
指定进入哪个容器。
更新 / 删除 Pod
Kubernetes 对 Pod 的更新做了限度,除了更改 Pod 中容器(包含工作容器与初始化容器)的镜像,以及 activeDeadlineSeconds(对 Job 类型的 Pod 定义失败重试的最大工夫),tolerations(Pod 对污点的容忍),批改其它局部将不会产生作用,如咱们能够尝试在后面 Pod 定义文档 pod-test.yaml 中将宿主机端口 8081 改为 8082,从新执行 kubectl apply
,将提醒如下谬误,
[root@kmaster test]# kubectl apply -f pod-test.yaml
The Pod "pod-test" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)
通过 kubectl delete
命令可删除一个 Pod
[root@kmaster test]# kubectl delete pod pod-test
在 Kubernetes 中,个别不间接创立,更新或删除单个 Pod,而是通过 Kubernetes 的 Controller(控制器)来治理 Pod,包含 ReplicSet(个别也不间接用,举荐 Deployment 形式),Deployment,StatefulSet,DaemonSet 等。
控制器提供如下性能:
- 程度伸缩,管制运行 Pod 指定个数的正本
- rollout,即版本更新
- 故障复原,当一个节点呈现故障,或资源不够,或进入保护中,控制器会主动在另一个适合的节点调度一个一样的 Pod,以保障 Pod 以肯定的正本数运行
Pod 状态
Pod 状态并不是容器的状态,容器的状态个别包含:
Waiting:容器的初始状态,处于 Waiting 状态的容器,示意依然有对应的操作在执行,例如:拉取镜像、利用 Secrets 等
Running:容器处于失常运行的状态
Terminated:容器处于完结运行的状态
而 Pod 的状态个别包含:
- Pending:Kubernetes 曾经创立并确认该 Pod,可能两种状况:1. Pod 还未实现调度(例如没有适合的节点);2. 正在从 docker registry 下载镜像
- Running:该 Pod 曾经被绑定到一个节点,并且该 Pod 所有的容器都曾经胜利创立,其中至多有一个容器正在运行,或者正在启动 / 重启
- Succeeded:Pod 中的所有容器都曾经胜利终止,并且不会再被重启
- Failed:Pod 中的所有容器都曾经终止,至多一个容器终止于失败状态:容器的过程退出码不是 0,或者被零碎 kill
- Unknown:因为某些未知起因,不能确定 Pod 的状态,通常的起因是 master 与 Pod 所在节点之间的通信故障
状态之间的变迁关系如图
Pod 刚开始处于 Pending 的状态,接下来可能会转换到 Running,也可能转换到 Unknown,甚至可能转换到 Failed。而后,当 Running 执行了一段时间之后,它能够转换到相似像 Successded 或者是 Failed。当呈现 Unknown 这个状态时,可能因为一些状态的复原,它会从新复原到 Running 或者 Successded 或者是 Failed。
重启策略
定义 Pod 或工作负载时,能够指定 restartPolicy,可选的值有:
- Always:默认值,只有退出就重启
- OnFailure:失败退出时(exit code 不为 0)才重启
- Never:永远不重启
restartPolicy 作用于 Pod 中的所有容器。kubelete 将在五分钟内,依照递延的工夫距离(10s, 20s, 40s …)尝试重启已退出的容器,并在十分钟后再次启动这个循环,直到容器胜利启动,或者 Pod 被删除。在控制器 Deployment/StatefulSet/DaemonSet 中,只反对 Always 这一个选项,不反对 OnFailure 和 Never 选项。
健康检查
进步应用服务的可用性与稳定性,个别可从两个方面来进行:
- 首先是进步利用的可观测性,如对利用的衰弱状态,资源的应用状况,利用日志等可进行实时的观测
- 第二是进步利用的可恢复能力,在利用呈现故障时,能通过主动重启等形式进行复原
Kubernetes 中对 Pod 的健康检查提供了两种形式:
- Readiness probe,就绪探测,用来判断一个 Pod 是否处于就绪状态,是否能对外提供相应服务了。当 Pod 处于就绪状态时,负载均衡器才会将流量打到这个 Pod,否则将把流量从这个 Pod 下面摘除。
- Liveness probe,存活探测,用来判断一个 Pod 是否处于存活状态,如果一个 Pod 被探测到不处于存活状态,则由下层判断机制来解决,如果下层配置重启策略为 restart always 的话,Pod 就会被重启。
Liveness probe 实用场景是反对那些能够从新拉起的利用,而 Readiness probe 次要应答的是启动之后无奈立刻对外提供服务的利用。
就绪探测、存活探测目前反对三种不同的探测形式:
- httpGet,通过发送 http Get 申请来判断,返回状态码在 200-399 之间,认为是探测胜利
- Exec,通过执行容器中的一个命令来判断服务是否失常,如果命令的退出状态码为 0,示意胜利
- tcpSocket,通过容器的 IP,端口来进行 TCP 连贯查看,如果 TCP 连贯能被失常建设,则认为胜利
以 httpGet 为例,示例配置文件如下,
apiVersion: v1
kind: Pod
metadata:
name: pod-test
spec:
containers:
- # ... 与前同
- name: workdir
mountPath: /usr/share/nginx/html
livenessProbe:
httpGet:
path: /
port: 80
httpHeaders: # 此处 header 无意义,仅作示例
- name: purpose
value: for-test
initialDelaySeconds: 2
periodSeconds: 5
# ... 与前同
删除之前的 Pod,从新创立,应用 kubectl describe
查看,可看到 Events 局部如下图,
Http 存活探测失败,状态码返回 403,导致容器重启。呈现这个谬误的起因是后面做目录挂载时将 nginx 的 html 目录挂载到了宿主机的 /tmp 目录,而 /tmp 目录没有 index.html 文件,导致申请返回 403,在 Pod 调度到的宿主机 /tmp 目录下创立 index.html 文件即可。
echo '<h1>Hello, K8s!</h1>' > /tmp/index.html
其它 Exec,tcpSocket 探测的配置示例如下(配置在 containers 元素下),
# exec
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
# tcpSocket
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
反对的参数阐明:
- initialDelaySeconds:提早探测工夫,示意 Pod 启动提早多久后进行一次查看,比方某个利用启动工夫如果较长的话,能够设置该值为略大于启动工夫;
- periodSeconds:探测频率,示意探测的工夫距离,失常默认的这个值是 10 秒;
- timeoutSeconds:超时工夫,示意探测的超时工夫,当超时工夫之内没有检测胜利,那会认为失败;
- successThreshold:衰弱阈值,示意当这个 Pod 从探测失败到再一次判断探测胜利,所须要的阈值次数,默认状况下是 1 次。如果之前探测失败,接下来的一次探测胜利了,就会认为这个 Pod 是处在一个失常的状态;
- failureThreshold:不衰弱阈值,与 successThreshold 绝对,示意认为探测失败须要重试的次数,默认值是 3。意思是当从一个衰弱的状态间断探测到 3 次失败,就会认为 Pod 的状态处在一个失败的状态。
readinessProbe 配置与 livenessProbe 相似。阿里云上配置就绪查看如图所示:
健康检查的后果分为三种:
- Success,示意 container 通过了健康检查,也就是 Liveness probe 或 Readiness probe 是失常的一个状态;
- Failure,示意 container 没有通过健康检查。针对 Readiness probe,service 层就会将没有通过 Readiness probe 的 pod 进行摘除,不再散发申请到该 Pod;针对 Liveness probe,就会将这个 pod 进行从新拉起,或者是删除。
- Unknown,示意以后的执行机制没有进行残缺的一个执行,可能是因为相似像超时或者像一些脚本没有及时返回,此时 Readiness probe 或 Liveness probe 不做任何操作,会期待下一次的机制来进行查看。
健康检查的一些实际倡议:
- 如果容器中的过程在碰到问题时能够本人 crash,就不须要执行存活探测,因为 kubelet 能够主动的依据 Pod 的 restartPolicy(重启策略)来执行对应的动作;
- 如果心愿在容器的过程无响应后,将容器重启,则指定一个存活探测 livenessProbe,并同时指定 restartPolicy(重启策略)为 Always 或者 OnFailure;
- 如果心愿在 Pod 的确就绪之后才向其散发服务申请,就指定一个就绪查看 readinessProbe;
- 适当调大 exec 探测的超时阈值,因为在容器外面执行一个 shell 脚本,它的执行时长是十分长的,平时在一台虚机上执行可能 3 秒返回的一个脚本在容器外面可能须要 30 秒。能够适当调大超时阈值,来避免因为容器压力比拟大的时候呈现偶发的超时;
- 调整失败判断的次数,3 次的默认值有时候可能不肯定是最佳实际,适当调整一下判断的次数也是一个比拟好的形式;
- 应用 tcpSocket 形式进行判断的时候,如果遇到了 TLS 的服务,那可能会造成后边 TLS 外面有很多这种未鉴权的 tcp 连贯,这时候须要本人针对业务场景判断这种连贯是否会对业务造成影响。
总结
本文对 Pod 的概念与根本的治理操作,Pod 的状态变迁机制与重启策略进行了介绍,对 Pod 的健康检查进行了具体的理解。但在 Kubernetes 中,咱们个别不间接创立 Pod,而是通过控制器,如 Deployment,StatefulSet,DaemonSet,因为控制器能为咱们提供程度伸缩,rollout(版本更新),self-healing(故障复原)等能力。咱们将在接下来的文章理解控制器。
[转载请注明出处]
作者:雨歌
欢送关注作者公众号:半路雨歌,查看更多技术干货文章