一. k8s中所说的对象,资源是什么意思?
答:
对象:是你在k8s集群中能看到,能管理的实物,称之为对象。例如:Pod,Deployment,Service等。
资源:是k8s集群中定义的一系列,可以被创建,被使用,被查询等的事物,称之为资源。例如:上述的对象,无形的规则和配置等。
如果说k8s中的资源有哪些,你可以说:有Pod,Depolyment,Configmap等,因为这些是能够被使用的;
如何说k8s集群中Pod对象有哪些,可能是通过kubectl命令创建出来多个副本的Pod,每一个Pod都是Pod资源的对象,或者是持久化的实例。
二. Pod每次被创建,都会伴随一个Pause的容器产生,该容器的作用是什么?[1]
答:Pause容器:又称Infra容器,Pause表面意思为暂停,即该容器是一个处于暂停状态的容器。
作用1:
Pod是一个容器组,其中至少包含一个容器,Pod才能够被创建运行出来,若容器数为0,则Pod被当成销毁。Pause容器保证了Pod的存活,在意外情况下,即使Pod中的业务容器都被删除,因Pause一直是暂停容器,Pod也不会被当成销毁。除非手动删除Pod。
作用2:
Pod是一个容器组,其中的容器都共享网络空间,而网络空间的创建,是由Pause去做的,其它容器只需要加入到Pause所在的网络空间中即可。
作用3:
同网络空间一样,Pod中的容器需要共用进程空间,即PID名称空间,也是由Pause创建,并作为Pod中,其它容器的第一个进程,即init进程。接管,回收各个容器所产生的僵尸进程。
三. Pod健康检查的三种探针策略,以及各自的区别是什么?
答:Liveness Probe:存活探针。
目的:确定Pod中的容器是否正在运行。
行为:根据探测的条件,如果探针探测失败,kubelet会杀死该容器,但是会受到容器的restartPolicy的影响。
Readiness Probe:就绪探针。
目的:确定Pod中的容器是否准备好接受流量,或者说容器中的服务是否准备就绪。
行为:根据探测的条件,如果探针探测失败,endpoint控制器会将从与Pod匹配的所有Service的endpoint中删除该Pod的IP地址。
通过 kubectl get pod 查看,Pod的状态为Ready列:0/1,不就绪的状态。
Startup Porbe:启动探针。
目的:确定容器中的服务是否已经启动。
行为:如果配置了启动探针,则会禁用掉其它所有的探针,直到它探测成功为止,如果探测失败,kubelet会杀死该容器,
但同样会受到容器的restartPolicy的影响。
Yaml示例:
spec:
containers:
- name: my-container
image: my-image
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
四. Pod中定义容器的restartPolicy三种重启策略,各自的区别,以及与探针的互相影响有哪些?
答:三种重启策略:Always,OnFailure,Never
Always:论容器是因为什么原因退出,都会自动重启。
OnFailure:只有当容器以非0状态码退出时,发生错误时,才会重启。
Never:容器退出后,无论是什么原因,都不会重启。
对探针的影响:
如果是Liveness Probe探针失败导致容器需要重启:
如果RestartPolicy是 Always 或 OnFailure,容器会被重启;
如果是Never,容器不会重启,Pod将会保持在失败状态(但是由于受控制器的影响,保持期待,会再创建新的Pod来运行)。
Yaml示例:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
restartPolicy: OnFailure
containers:
- name: my-container
image: my-image
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
五. Qos服务质量是什么?[2]
答:Qos服务质量:是根据是否对Pod设置了资源的请求(request)和限制(limit),来去给Pod进行分类的机制。
说人话就是:给Pod进行分类,这些Pod是一类,那些Pod是另一类,分类的标准:是否限制了Pod使用多少的内存/CPU。有限制的Pod是一类,没有限制的是另一类。根据分类,会去他们区别对待,有限制的好比是VIP客户,没有限制的是普通客户,当节点上资源不够时,要对他们进行驱离,则会先对最低类型的Pod动手。
Qos的类型有:
Guaranteed(SVIP客户):最高类型,在资源压力下,该类型的Pod是最后考虑驱逐的。
划分标准:Pod定义了资源限制:即request和limit,且二者的值必须相等,这意味着该Pod分配了一个固定的资源值。
只有在Pod自身超过了限制的资源,或者没有更低优先级的Pod,才会考虑进行驱逐。
Burstable(VIP客户):一般类型,在资源压力下,该类型的Pod会在BestEffort类型Pod之后驱逐。
划分标准:Pod至少定义了request资源请求,但没有设置limit限制。或者不符合Guaranteed和BestEffort划分标准的。
这样类型的Pod,由于没有limit限制,可以无限制使用节点资源,故也有隐患,在驱逐时,考虑倒数第二驱逐。
BestEffort(普通客户):最低级别,在资源压力下,该类型的Pod会首先被驱逐。
划分标准:Pod没有设置 requests 和 limits。
要查看Pod属于哪一类型,可以使用
kubectl describe pod <pod名> -n 命名空间
查看:
$ kubectl describe pod test-7955cf7657-qh4wq -n test
......
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
......
六. Pod驱逐行为产生的原因,行为,影响都有哪些?[3]
答:驱逐 字面意思是赶走;
Pod驱逐:将Pod从所在的节点上赶走。
产生的原因:一般是由于节点压力导致的驱逐,即节点上的
内存
,存储空间
,进程可用进程数
的不足,为了保证核心程序,Pod,系统正常运行,不至于暴死,kubelet做的Pod销毁,释放资源空间的行为。 行为:kubelet根据节点资源的使用情况,通过cgroup获取值,并与驱逐条件进行对比,超过阈值则产生驱逐行为。
条件分为硬驱逐 和 软驱逐。
- 硬驱逐:达到限制,kubelet会立即杀死Pod,且不会正常终止Pod,回收资源。类似kill -9
- 软驱逐:达到限制,kubelet不会立即杀死Pod,会给要“枪毙”的Pod一段时间,去做自己的善后事情,即正常终止Pod,回收资源。
Pod的驱逐顺序:
1. 识别资源压力,确定需要释放的资源量
2. 考虑资源使用超过请求的 Pods:
* 所有 BestEffort Pods
* 使用超过请求的 Burstable Pods,在这个组内,按 Pod 优先级排序,低优先级先驱逐
3. 如果仍需要更多资源,考虑资源使用未超过请求的 Pods:
* 使用未超过请求的 Burstable Pods,在这个组内,按 Pod 优先级排序,低优先级先驱逐
* Guaranteed Pods(只有在极端情况下) 同样在这个组内,按 Pod 优先级排序,低优先级先驱逐
4. 在整个过程中,kubelet 会持续评估是否已释放足够的资源
七. Pod终止的相关时间有哪些?[4]
答:Pod终止受到:体面终止周期时间的影响。
体面终止周期:即给Pod中的所有容器在被杀死之前,做好自己的善后工作,比如请求的处理/连接的关闭,数据的清理等,的时间。默认是30s。
如果终止周期/宽限期设置为0,则会立即终止,发生的行为会是ApiServer上会删除Pod的相关信息,但是Pod实现在在节点上运行的容器可能还在一直的运行着。
且如果要强制终止/删除Pod,可以这样操作:
kubectl delete pod <pod-name> --grace-period=0 --force
# --grace-period:设置宽限时间
八. Yaml文件中的Annotations和Label是什么,二者的区别。
答:Annotations(注解):是一种声明被创建的
资源
(例如Pod)元数据的机制。 通俗的讲,就是你创建了一个Pod,那这个Pod的是谁创建的,什么时间创建的,使用的仓库地址是多少等一系列的信息,可以通过注解的方式去记录。这样做的好处,是能够让其它人一眼了解这个Pod的属性信息。
通过注解可以实现这样的目的。例如:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-website
annotations:
kubernetes.io/change-cause: "Initial deployment of my website"
owner: "marketing-team@company.com"
git-commit: "abc123"
deployment-date: "2023-07-29"
spec:
replicas: 3
selector:
matchLabels:
app: my-website
template:
metadata:
labels:
app: my-website
spec:
containers:
- name: my-website
image: my-website:1.0
ports:
- containerPort: 80
类似添加描述信息的作用,功能(以上的owner等名称都可以自定义)。但这只是注解功能的其一。
另一个重要的功能是:配置管理/注入。
思考一下,如果我们在传统方式下,想要将nginx能接收的最大请求体大小为50M,这种情况,我们直接修改nginx.conf配置文件即可,但是在Pod中如何去做呢?
通过注解的方式,例如:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
注解的组成:前缀/名称:值。
前缀规则:可选,如果使用,格式要符合有效的DNS域名格式(不会解析,只是要求格式要与DNS格式一致,结尾要有一个/)。
名称:必须存在,必须字母/数字开头和结尾,最多63个字符。
Label:主要用来对创建的集群
资源
进行一个筛选的功能。 例如:你创建了10个pod,5个Pod是nginx,5个Pod是http。这个时候你如何只过滤去nginx的呢:可以给nginx Pod打标签,这样进行查询的使用,可以通过
kubectl get pod -n <名称空间名称> -l 标签名
去进行过滤查询。如下所示:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod-1
labels:
app: nginx
environment: production
kuebctl get pod -l app=nginx
主要区别:
Annotations | Labels |
---|---|
不用于选择和查询资源 | 用于选择和查询资源 |
用于存储辅助信息,和配置管理 | 用于组织和分类资源 |
命名规则相对宽松 | 有严格的命名规范:key: value |
相对静态,通常在资源创建时设置 | 可以发生改变,用于反应资源状态 |
API基本上忽略内容,只存储 | 被API服务器积极处理和验证 |
九. kubectl create 和 apply 二者操作的区别是什么?
答:
create | apply |
---|---|
用于首次创建资源,如果资源存在,则报错 | 用于创建和更新资源,如果资源不存在则创建;如果已存在则更新 |
命令式操作,直接告诉K8S创建一个资源,简单暴力 | 声明式操作,描述系统的期望状态,让系统决定如何达到这个状态 |
适用于快速创建 | 适用于管理复杂的应用部署,更新,版本控制 |
适用一次性操作或调试 | 适用于生产环境 |
十. 如何将一个不可用的节点设置成为不可调度,排空,并下线?
答:流程如下:
第一步:将节点设置为不可调度。防止新的Pod调度到该节点上。
kubectl cordon <节点名>
第二步:排空节点上的Pod。
kubectl drain <节点名> --ignore-daemonsets --delete-emptydir-data
# --ignore-daemonsets:允许跳过DaemonSet管理的Pod
# --delete-emptydir-data:允许删除使用emptyDir卷的Pod注:你也完全可以直接执行kubectl drain操作,而省略cordon步骤。原因是:drain会先cordon之后,再尝试优雅地终止该节点上地Pod(排空)。
第三步:确定节点已排空。
# 检查节点状态
kubectl describe node <节点名>
# 重点关注部分:
# Unschedulabel:应该显示为true
# Taints:包含node.kubernetes.io/unschedulable:NoSchedule这个污点。
# Non-terminated Pods:这里应该只列出DaemonSet管理的Pod(如果有的话),其它类型都已驱逐。
# 检查Pod都已排空,处理DaemonSet类型的Pod
Kubectl get pod -A -o wide | grep <节点IP>第四步:从集群中删除节点。
kubectl delete node <节点名>
第五步:后续该节点的DaemonSet类型的Pod,会由于该Pod的控制器监控到节点不存在,会强制终止该类型的Pod,垃圾回收。
参考链接
[1].https://www.51cto.com/article/767383.html
[2].https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-qos/
[4].https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/