# 工作负载异常：实例调度失败
#### 问题定位
当Pod状态为"Pending"，事件中出现"实例调度失败"的信息时，可根据具体事件信息确定具体问题原因。事件查看方法请参见[工作负载状态异常定位方法](https://support.huaweicloud.com/cce_faq/cce_faq_00134.html)。
#### 排查思路
根据具体事件信息确定具体问题原因，如[表1]所示。
 表1实例调度失败 
| 事件信息                                                                                                                                                        | 问题原因与解决方案                                                                                                                         |
|:---|:---|
| no nodes available to schedule pods.                                                                                                                       | 集群中没有可用的节点。 [排查项一：集群内是否无可用节点]                                   |
| 0/2 nodes are available: 2 Insufficient cpu. 0/2 nodes are available: 2 Insufficient memory.                                  | 节点资源（CPU、内存）不足。 [排查项二：节点资源（CPU、内存等）是否充足]                 |
| 0/2 nodes are available: 1 node(s) didn't match node selector, 1 node(s) didn't match pod affinity rules, 1 node(s) didn't match pod affinity/anti-affinity. | 节点与Pod亲和性配置互斥，没有满足Pod要求的节点。 [排查项三：检查工作负载的亲和性配置]                 |
| 0/2 nodes are available: 2 node(s) had volume node affinity conflict.                                                                                         | Pod挂载云硬盘存储卷与节点不在同一个可用区。 [排查项四：挂载的存储卷与节点是否处于同一可用区]          |
| 0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.                                                                                  | 节点存在污点Tanits，而Pod不能容忍这些污点，所以不可调度。 [排查项五：检查Pod污点容忍情况]           |
| 0/7 nodes are available: 7 Insufficient ephemeral-storage.                                                                                                    | 节点临时存储不足。 [排查项六：检查临时卷使用量]                                   |
| 0/1 nodes are available: 1 everest driver not found at node                                                                                                 | 节点上everest-csi-driver不在running状态。 [排查项七：检查everest插件是否工作正常] |
| Failed to create pod sandbox: ... Create more free space in thin pool or use dm.min_free_space option to change behavior     | 节点thinpool空间不足。 [排查项八：检查节点thinpool空间是否充足]                     |
| 0/1 nodes are available: 1 Too many pods.                                                                                                                     | 该节点调度的Pod超出上限。 [检查项九：检查节点上调度的Pod是否过多]                         |
| UnexpectedAdmissionError Allocate failed due to not enough cpus available to satisfy request, which is unexpected.                                           | 由于已知社区问题导致kubelet静态绑核异常。 [排查项十：kubelet静态绑核异常]                  |
   
 #### 排查项一：集群内是否无可用节点
登录CCE控制台，检查节点状态是否为可用。或使用如下命令查看节点状态是否为Ready。
```
$ kubectl get node
NAME           STATUS   ROLES    AGE   VERSION
192.168.0.37   Ready    <none>   21d   v1.19.10-r1.0.0-source-121-gb9675686c54267
192.168.0.71   Ready    <none>   21d   v1.19.10-r1.0.0-source-121-gb9675686c54267
```
如果状态都为不可用（Not Ready），则说明集群中无可用节点。
**解决方案：**
- 新增节点，若工作负载未设置亲和策略，pod将自动迁移至新增的可用节点，确保业务正常。
- 排查不可用节点问题并修复，排查修复方法请参见[集群可用但节点状态为"不可用"如何解决？](https://support.huaweicloud.com/cce_faq/cce_faq_00120.html)。
- 重置不可用的节点，详情请参见[重置节点](https://support.huaweicloud.com/usermanual-cce/cce_10_0003.html)。
 
 #### 排查项二：节点资源（CPU、内存等）是否充足
**0/2 nodes are available: 2 Insufficient cpu.** CPU不足。
**0/2 nodes are available: 2 Insufficient memory.** 内存不足。
当"实例资源的申请量"超过了"实例所在节点的可分配资源总量"时，节点无法满足实例所需资源要求导致调度失败。
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002194828022.png "点击放大")
如果节点可分配资源小于Pod的申请量，则节点无法满足实例所需资源要求导致调度失败。
**解决方案：**
资源不足的情况主要解决办法是扩容，建议在集群中增加节点数量。
 #### 排查项三：检查工作负载的亲和性配置
当亲和性配置出现如下互斥情况时，也会导致实例调度失败：
例如：
workload1、workload2设置了工作负载间的反亲和，如workload1部署在Node1，workload2部署在Node2。
workload3部署上线时，既希望与workload2亲和，又希望可以部署在不同节点如Node1上，这就造成了工作负载亲和与节点亲和间的互斥，导致最终工作负载部署失败。
0/2 nodes are available: 1 node(s) didn't match **node selector** , 1 node(s) didn't match **pod affinity rules** , 1 node(s) didn't match **pod affinity/anti-affinity**.
- **node selector** 表示节点亲和不满足。
- **pod affinity rules** 表示Pod亲和不满足。
- **pod affinity/anti-affinity** 表示Pod亲和/反亲和不满足。
**解决方案：**
- 在设置"工作负载间的亲和性"和"工作负载和节点的亲和性"时，需确保不要出现互斥情况，否则工作负载会部署失败。
- 若工作负载配置了节点亲和性，需确保亲和的节点标签中supportContainer设置为true，否则会导致pod无法调动到节点上，查看事件提示如下错误信息：
  ```
  No nodes are available that match all of the following predicates: MatchNode Selector, NodeNotSupportsContainer
  ```
  节点标签为false时将会调度失败。
  
 
 #### 排查项四：挂载的存储卷与节点是否处于同一可用区
**0/2 nodes are available: 2 node(s) had volume node affinity conflict.** 存储卷与节点之间存在亲和性冲突，导致无法调度。
这是因为云硬盘不能跨可用区挂载到节点。例如云硬盘存储卷在可用区1，节点在可用区2，则会导致无法调度。
CCE中创建云硬盘存储卷，默认带有亲和性设置，如下所示：
```
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pvc-c29bfac7-efa3-40e6-b8d6-229d8a5372ac
spec:
  ...
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: failure-domain.beta.kubernetes.io/zone
              operator: In
              values:
                - cn-east-3a
```
**解决方案：**
重新创建存储卷，可用区选择与节点同一分区，或重新创建工作负载，存储卷选择自动分配。
 #### 排查项五：检查Pod污点容忍情况
**0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.**是因为节点打上了污点，不允许Pod调度到节点上。
查看节点的上污点的情况。如下则说明节点上存在污点。
```
$ kubectl describe node 192.168.0.37
Name:               192.168.0.37
...
Taints:             key1=value1:NoSchedule
...
```
在某些情况下，系统会自动给节点添加一个污点。当前内置的污点包括：
- node.kubernetes.io/not-ready：节点未准备好。
- node.kubernetes.io/unreachable：节点控制器访问不到节点。
- node.kubernetes.io/memory-pressure：节点存在内存压力。
- node.kubernetes.io/disk-pressure：节点存在磁盘压力，此情况下您可通过[节点磁盘空间不足](https://support.huaweicloud.com/cce_faq/cce_faq_00015.html#cce_faq_00015__section165209286116)的方案进行解决。
- node.kubernetes.io/pid-pressure：节点的 PID 压力，此情况下您可通过[修改节点进程 ID数量上限kernel.pid_max](https://support.huaweicloud.com/usermanual-cce/cce_10_0401.html)进行解决。
- node.kubernetes.io/network-unavailable：节点网络不可用。
- node.kubernetes.io/unschedulable：节点不可调度。
- node.cloudprovider.kubernetes.io/uninitialized：如果kubelet启动时指定了一个"外部"云平台驱动， 它将给当前节点添加一个污点将其标志为不可用。在cloud-controller-manager初始化这个节点后，kubelet将删除这个污点。
**解决方案：**
要想把Pod调度到这个节点上，有两种方法：
- 若该污点为用户自行添加，可考虑删除节点上的污点。若该污点为[系统自动添加]，解决相应问题后污点会自动删除。
- Pod的定义中容忍这个污点，如下所示。详细内容请参见[污点和容忍](https://kubernetes.io/zh/docs/concepts/scheduling-eviction/taint-and-toleration/)。
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx
  spec:
    containers:
    - name: nginx
      image: nginx:alpine
    tolerations:
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
  ```
  
 
 #### 排查项六：检查临时卷使用量
**0/7 nodes are available: 7 Insufficient ephemeral-storage.** 节点临时存储不足。
检查Pod是否限制了临时卷的大小，如下所示，当应用程序需要使用的量超过节点已有容量时会导致无法调度，修改临时卷限制或扩容节点磁盘可解决此问题。
```
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  volumes:
    - name: ephemeral
      emptyDir: {}
```
您可以通过**kubectl describe node**命令查询节点临时卷的容量（Capacity）和可使用量（Allocatable），并可查询节点已分配的临时卷申请值和限制值。
返回示例如下：
```
...
Capacity:
  cpu:                4
  ephemeral-storage:  61607776Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  localssd:           0
  localvolume:        0
  memory:             7614352Ki
  pods:               40
Allocatable:
  cpu:                3920m
  ephemeral-storage:  56777726268
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  localssd:           0
  localvolume:        0
  memory:             6180752Ki
  pods:               40
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests      Limits
  --------           --------      ------
  cpu                1605m (40%)   6530m (166%)
  memory             2625Mi (43%)  5612Mi (92%)
  ephemeral-storage  0 (0%)        0 (0%)
  hugepages-1Gi      0 (0%)        0 (0%)
  hugepages-2Mi      0 (0%)        0 (0%)
  localssd           0             0
  localvolume        0             0
Events:              <none>
```
 #### 排查项七：检查everest插件是否工作正常
**0/1 nodes are available: 1 everest driver not found at node**。集群everest插件的everest-csi-driver 在节点上未正常启动。
检查kube-system命名空间下名为everest-csi-driver的守护进程，查看对应Pod是否正常启动，若未正常启动，删除该Pod，守护进程会重新拉起该Pod。
 #### 排查项八：检查节点thinpool空间是否充足
节点在创建时会绑定一个供kubelet及容器运行时使用的专用数据盘，详情请参见[数据盘空间分配说明](https://support.huaweicloud.com/usermanual-cce/cce_10_0341.html)。若数据盘空间不足，将导致实例无法正常创建。
**方案一：清理镜像**
您可以执行以下步骤清理未使用的镜像：
- 使用containerd容器运行时的节点：
  1. 查看节点上的本地镜像。
     ```
     crictl images -v
     ```
     
  
  2. 确认镜像无需使用，并通过镜像ID删除无需使用的镜像。
     ```
     crictl rmi {镜像ID}
     ```
     
   
- 使用docker容器运行时的节点：
  1. 查看节点上的本地镜像。
     ```
     docker images
     ```
     
  
  2. 确认镜像无需使用，并通过镜像ID删除无需使用的镜像。
     ```
     docker rmi {镜像ID}
     ```
     
   
![](https://support.huaweicloud.com/cce_faq/public_sys-resources/note_3.0-zh-cn.png)
请勿删除cce-pause等系统镜像，否则可能导致无法正常创建容器。
**方案二：扩容磁盘**
扩容磁盘的操作步骤如下：
1. 在EVS控制台扩容数据盘。详情请参见[扩容云硬盘容量](https://support.huaweicloud.com/usermanual-evs/evs_01_0007.html)。
   
   在EVS控制台扩容成功后，仅扩大了云硬盘的存储容量，还需要执行后续步骤扩容逻辑卷和文件系统。
   
   
2. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，进入集群，在左侧选择"节点管理"，单击节点后的"同步云服务器"。
3. 登录目标节点。
4. 使用**lsblk** 命令查看节点块设备信息。
   
   这里存在两种情况，根据容器存储Rootfs而不同。
   **Overlayfs：**没有单独划分thinpool，在dockersys空间下统一存储镜像相关数据。
   1. 查看设备的磁盘和分区大小。
      ```
      # lsblk
      NAME                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      sda                   8:0    0   50G  0 disk 
      └─sda1                8:1    0   50G  0 part /
      sdb                   8:16   0  150G  0 disk      # 数据盘已扩容至150G，存在50G空间仍未分配
      ├─vgpaas-dockersys  253:0    0   90G  0 lvm  /var/lib/containerd
      └─vgpaas-kubernetes 253:1    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
   
   2. 扩容磁盘。 将新增的磁盘容量加到容器运行时使用的dockersys逻辑卷上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/sdb* 为dockersys逻辑卷所在的物理卷。
         ```
         pvresize /dev/sdb
         ```
         回显如下：
         ```
         Physical volume "/dev/sdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/dockersys* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/dockersys
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/dockersys changed from <90.00 GiB (23039 extents) to 140.00 GiB (35840 extents).
         Logical volume vgpaas/dockersys successfully resized.
         ```
         
      
      3. 调整文件系统的大小。其中*/dev/vgpaas/dockersys* 为容器运行时的文件系统路径。
         ```
         resize2fs /dev/vgpaas/dockersys
         ```
         回显如下：
         ```
         Filesystem at /dev/vgpaas/dockersys is mounted on /var/lib/containerd; on-line resizing required
         old_desc_blocks = 12, new_desc_blocks = 18
         The filesystem on /dev/vgpaas/dockersys is now 36700160 blocks long.
         ```
         
       
   
   3. 检查是否扩容成功。
      ```
      # lsblk
      NAME                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      sda                   8:0    0   50G  0 disk 
      └─sda1                8:1    0   50G  0 part /
      sdb                   8:16   0  150G  0 disk
      ├─vgpaas-dockersys  253:0    0   140G  0 lvm  /var/lib/containerd
      └─vgpaas-kubernetes 253:1    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
    
   **Devicemapper：**单独划分了thinpool存储镜像相关数据。
   1. 查看设备的磁盘和分区大小。
      ```
      # lsblk
      NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
      vda                                   8:0    0   50G  0 disk 
      └─vda1                                8:1    0   50G  0 part /
      vdb                                   8:16   0  200G  0 disk 
      ├─vgpaas-dockersys                  253:0    0   18G  0 lvm  /var/lib/docker    
      ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
      │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm                   # thinpool空间
      │   ...
      ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
      │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
      │   ...
      └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
      ```
      
   
   2. 扩容磁盘。
      **选项一：**将新增的磁盘容量加到thinpool盘上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/vdb* 为thinpool空间所在的物理卷。
         ```
         pvresize /dev/vdb
         ```
         回显如下：
         ```
         Physical volume "/dev/vdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/thinpool* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/thinpool
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/thinpool changed from <67.00 GiB (23039 extents) to <167.00 GiB (48639 extents).
         Logical volume vgpaas/thinpool successfully resized.
         ```
         
      
      3. 由于thinpool未挂载到设备，因此无需调整文件系统的大小。
      
      4. 检查是否扩容成功。使用lsblk命令查看设备的磁盘和分区大小，若新增的磁盘容量已经加到thinpool盘，则表示扩容成功。
         ```
         # lsblk
         NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
         vda                                   8:0    0   50G  0 disk 
         └─vda1                                8:1    0   50G  0 part /
         vdb                                   8:16   0  200G  0 disk 
         ├─vgpaas-dockersys                  253:0    0   18G  0 lvm  /var/lib/docker    
         ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
         │ └─vgpaas-thinpool                 253:3    0   167G  0 lvm             # 扩容后的thinpool空间
         │   ...
         ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
         │   ...
         └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
         ```
         
       
      **选项二：**将新增的磁盘容量加到dockersys盘上。
      1. 扩容物理卷PV，让LVM识别EVS新增的容量。其中*/dev/vdb* 为dockersys逻辑卷所在的物理卷。
         ```
         pvresize /dev/vdb
         ```
         回显如下：
         ```
         Physical volume "/dev/vdb" changed
         1 physical volume(s) resized or updated / 0 physical volume(s) not resized
         ```
         
      
      2. 将空闲容量100%扩容到逻辑卷LV。其中*vgpaas/dockersys* 为容器运行时使用的逻辑卷。
         ```
         lvextend -l+100%FREE -n vgpaas/dockersys
         ```
         回显如下：
         ```
         Size of logical volume vgpaas/dockersys changed from <18.00 GiB (4607 extents) to <118.00 GiB (30208 extents).
         Logical volume vgpaas/dockersys successfully resized.
         ```
         
      
      3. 调整文件系统的大小。其中*/dev/vgpaas/dockersys* 为容器运行时的文件系统路径。
         ```
         resize2fs /dev/vgpaas/dockersys
         ```
         回显如下：
         ```
         Filesystem at /dev/vgpaas/dockersys is mounted on /var/lib/docker; on-line resizing required
         old_desc_blocks = 3, new_desc_blocks = 15
         The filesystem on /dev/vgpaas/dockersys is now 30932992 blocks long.
         ```
         
      
      4. 检查是否扩容成功。使用lsblk命令查看设备的磁盘和分区大小，若新增的磁盘容量已经加到dockersys盘，则表示扩容成功。
         ```
         # lsblk
         NAME                                MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
         vda                                   8:0    0   50G  0 disk 
         └─vda1                                8:1    0   50G  0 part /
         vdb                                   8:16   0  200G  0 disk 
         ├─vgpaas-dockersys                  253:0    0   118G  0 lvm  /var/lib/docker     # 扩容后的dockersys盘
         ├─vgpaas-thinpool_tmeta             253:1    0    3G  0 lvm                   
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm             
         │   ...
         ├─vgpaas-thinpool_tdata             253:2    0   67G  0 lvm  
         │ └─vgpaas-thinpool                 253:3    0   67G  0 lvm  
         │   ...
         └─vgpaas-kubernetes                 253:4    0   10G  0 lvm  /mnt/paas/kubernetes/kubelet
         ```
         
        
    
   
   
 
 #### 检查项九：检查节点上调度的Pod是否过多
**0/1 nodes are available: 1 Too many pods.**表示节点上调度的Pod过多，超出可调度的最大实例数。
创建节点时，在"高级配置"中可选择设置"最大实例数"参数，设置节点上可以正常运行的容器 Pod 的数目上限。该数值的默认值随节点规格浮动，您也可以手动设置。
图1最大实例数   
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002194825598.png "点击放大")
您可以在"节点管理"页面，查看节点的"Pod(已分配/可用地址总数/总额度)"参数列，检查节点已调度的容器是否达到上限。若已达到上限，可通过添加节点或修改最大实例数的方式解决。
您可通过以下方式修改"最大实例数"参数：
- 默认节点池中的节点：通过重置节点时修改"最大实例数"。
- 自定义节点池中的节点：可修改节点池配置参数中的max-pods参数。详情请参见[节点池配置管理](https://support.huaweicloud.com/usermanual-cce/cce_10_0652.html)。
图2查看容器数   
![](https://support.huaweicloud.com/cce_faq/zh-cn_image_0000002194666862.png "点击放大")
 #### 排查项十：kubelet静态绑核异常
当kubelet开启静态绑核（cpuManagerPolicy设置为static），且Pod的QoS类型为Guaranteed时，如果该Pod同时配置了整数CPU Request值的初始化容器（init container），且初始化容器的CPU Request值与主容器的CPU Request值不一样，会有概率泄漏导致Pod调度失败，出现UnexpectedAdmissionError报错。
社区相关issue：<https://github.com/kubernetes/kubernetes/issues/112228>
**解决方案：**
设置init容器CPU为小数，不绑定核心，但需保证Request值等于Limit值。
例如：主容器：{"limits":{"cpu":"7","memory":"60G"},"requests":{"cpu":"7","memory":"60G"}}，init容器{"limits":{"cpu":"6.9","memory":"60G"},"requests":{"cpu":"6.9","memory":"60G"}}
