一. 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文件中的AnnotationsLabel是什么,二者的区别。

答: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

​ 主要区别:

AnnotationsLabels
不用于选择和查询资源用于选择和查询资源
用于存储辅助信息,和配置管理用于组织和分类资源
命名规则相对宽松有严格的命名规范:key: value
相对静态,通常在资源创建时设置可以发生改变,用于反应资源状态
API基本上忽略内容,只存储被API服务器积极处理和验证

九. kubectl create 和 apply 二者操作的区别是什么?

答:

createapply
用于首次创建资源,如果资源存在,则报错用于创建和更新资源,如果资源不存在则创建;如果已存在则更新
命令式操作,直接告诉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,垃圾回收。

感觉还不错的话,点个赞吧^^。最新文章可以关注公众号:云原生传声!

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐