Kubernetes集群管理经验

Kubernetes Management Experience

Posted by Zeusro on January 25, 2019
👈🏻 Select language

Kubernetes 集群管理经(教)验(训)

2020-02-26 更新:本文再更新,请移步 Kubernetes集群管理经验

节点问题

删除节点的正确步骤

1
2
3
4
5
# SchedulingDisabled,确保新的容器不会调度到该节点
kubectl cordon $node
# 驱逐除了ds以外所有的pod
kubectl drain $node   --ignore-daemonsets
kubectl delete $node

维护节点的正确步骤

1
2
3
4
5
6
# SchedulingDisabled,确保新的容器不会调度到该节点
kubectl cordon $node
# 驱逐除了ds以外所有的pod
kubectl drain $node --ignore-daemonsets --delete-local-data
# 维护完成,恢复其正常状态
kubectl uncordon $node

–delete-local-data 是忽略 emptyDir这类的临时存储的意思

ImageGCFailed

kubelet 可以清除未使用的容器和镜像。kubelet 在每分钟和每五分钟分别回收容器和镜像。

配置 kubelet 垃圾收集

但是 kubelet 的垃圾回收有个问题,它只能回收那些未使用的镜像,有点像 docker system prune,然而观察发现,那些死掉的容器不是最大的问题,正在运行的容器才是更大的问题.如果ImageGCFailed一直发生,而容器使用的ephemeral-storage/hostpath(宿主目录)越发增多,最终将会导致更严重的DiskPressure问题,波及节点上所有容器.

建议:

  1. 高配机器(4核32G以上)的docker目录配置100G SSD以上空间
  2. 配置ResourceQuota限制整体资源限额
  3. 容器端禁用ephemeral-storage(本地文件写入),或者使用spec.containers[].resources.limits.ephemeral-storage限制,控制宿主目录写入

节点出现磁盘压力(DiskPressure)

1
--eviction-hard=imagefs.available<15%,memory.available<300Mi,nodefs.available<10%,nodefs.inodesFree<5%

kubelet在启动时指定了磁盘压力,以阿里云为例,imagefs.available<15%意思是说容器的读写层少于15%的时候,节点会被驱逐.节点被驱逐的后果就是产生DiskPressure这种状况,并且节点上再也不能运行任何镜像,直至磁盘问题得到解决.如果节点上容器使用了宿主目录,这个问题将会是致命的.因为你不能把目录删除掉,但是真是这些宿主机的目录堆积,导致了节点被驱逐.

所以,平时要养好良好习惯,容器里面别瞎写东西(容器里面写文件会占用ephemeral-storage,ephemeral-storage过多pod会被驱逐),多使用无状态型容器,谨慎选择存储方式,尽量别用hostpath这种存储

出现状况时,真的有种欲哭无泪的感觉.

1
2
3
4
5
6
7
8
9
10
11
12
13
Events:
  Type     Reason                 Age                   From                                            Message
  ----     ------                 ----                  ----                                            -------
  Warning  FreeDiskSpaceFailed    23m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 5182058496 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  ImageGCFailed          18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Warning  ImageGCFailed          13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Normal   NodeHasNoDiskPressure  10m (x5 over 47d)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasNoDiskPressure
  Normal   Starting               10m                   kube-proxy, node.xxxx1  Starting kube-proxy.
  Normal   NodeHasDiskPressure    10m (x4 over 42m)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasDiskPressure
  Warning  EvictionThresholdMet   8m29s (x19 over 42m)  kubelet, node.xxxx1     Attempting to reclaim ephemeral-storage
  Warning  ImageGCFailed          3m4s                  kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4920913920 bytes, but freed 0 bytes

ImageGCFailed 是很坑爹的状态,出现这个状态时,表示 kubelet 尝试回收磁盘失败,这时得考虑是否要手动上机修复了.

建议:

  1. 镜像数量在200以上时,采购100G SSD存镜像
  2. 少用临时存储(empty-dir,hostpath之类的)

参考链接:

  1. Eviction Signals
  2. 10张图带你深入理解Docker容器和镜像

节点CPU彪高

有可能是节点在进行GC(container GC/image GC),用describe node查查.我有次遇到这种状况,最后节点上的容器少了很多,也是有点郁闷

1
2
3
4
Events:
  Type     Reason                 Age                 From                                         Message
  ----     ------                 ----                ----
  Warning  ImageGCFailed          45m                 kubelet, cn-shenzhen.xxxx  failed to get image stats: rpc error: code = DeadlineExceeded desc = context deadline exceeded

参考:

kubelet 源码分析:Garbage Collect

节点失联(unknown)

1
2
3
4
5
6
  Ready                False   Fri, 28 Jun 2019 10:19:21 +0800   Thu, 27 Jun 2019 07:07:38 +0800   KubeletNotReady              PLEG is not healthy: pleg was last seen active 27h14m51.413818128s ago; threshold is 3m0s

Events:
  Type     Reason             Age                 From                                         Message
  ----     ------             ----                ----                                         -------
  Warning  ContainerGCFailed  5s (x543 over 27h)  kubelet, cn-shenzhen.xxxx                    rpc error: code = DeadlineExceeded desc = context deadline exceeded

ssh登录主机后发现,docker服务虽然还在运行,但docker ps卡住了.于是我顺便升级了内核到5.1,然后重启.

后来发现是有个人上了一个问题镜像,无论在哪节点运行,都会把节点搞瘫,也是醉了。

unknown 是非常严重的问题,必须要予以重视.节点出现 unknown ,kubernetes master 自身不知道节点上面的容器是死是活,假如有一个非常重要的容器在 unknown 节点上面运行,而且他刚好又挂了,kubernetes是不会自动帮你另启一个容器的,这点要注意.

参考链接:

Node flapping between Ready/NotReady with PLEG issues 深度解析Kubernetes Pod Disruption Budgets(PDB)

SystemOOM

SystemOOM 并不一定是机器内存用完了.有一种情况是docker 在控制容器的内存导致的.

默认情况下Docker的存放位置为:/var/lib/docker/containers/$id

这个目录下面有个重要的文件: hostconfig.json,截取部分大概长这样:

1
2
3
4
5
6
7
8
9
	"MemorySwappiness": -1,
	"OomKillDisable": false,
	"PidsLimit": 0,
	"Ulimits": null,
	"CpuCount": 0,
	"CpuPercent": 0,
	"IOMaximumIOps": 0,
	"IOMaximumBandwidth": 0
}

"OomKillDisable": false, 禁止了 docker 服务通过杀进程/重启的方式去和谐使用资源超限的容器,而是以其他的方式去制裁(具体的可以看这里)

docker daemon 卡住

这种状况我出现过一次,原因是某个容器有毛病,坑了整个节点.

出现这个问题要尽快解决,因为节点上面所有的 pod 都会变成 unknown .

1
2
3
systemctl daemon-reexec
systemctl restart docker(可选视情况定)
systemctl restart kubelet

严重时只能重启节点,停止涉事容器.

建议: 对于容器的liveness/readiness 使用tcp/httpget的方式,避免 高频率使用exec

pod

pod频繁重启

原因有多种,不可一概而论

有一种情况是,deploy配置了健康检查,节点运行正常,但是因为节点负载过高导致了健康检查失败(load15长期大于2以上),频繁Backoff.我调高了不健康阈值之后,降低节点负载之后,问题解决

1
2
3
4
5
6
7
8
9
10
          livenessProbe:
            # 不健康阈值
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 8080
            timeoutSeconds: 1

资源达到limit设置值

调高limit或者检查应用

Readiness/Liveness connection refused

Readiness检查失败的也会重启,但是Readiness检查失败不一定是应用的问题,如果节点本身负载过重,也是会出现connection refused或者timeout

这个问题要上节点排查

pod被驱逐(Evicted)

  1. 节点加了污点导致pod被驱逐
  2. ephemeral-storage超过限制被驱逐
    1. EmptyDir 的使用量超过了他的 SizeLimit,那么这个 pod 将会被驱逐
    2. Container 的使用量(log,如果没有 overlay 分区,则包括 imagefs)超过了他的 limit,则这个 pod 会被驱逐
    3. Pod 对本地临时存储总的使用量(所有 emptydir 和 container)超过了 pod 中所有container 的 limit 之和,则 pod 被驱逐

ephemeral-storage是一个pod用的临时存储.

1
2
3
4
5
resources:
       requests: 
           ephemeral-storage: "2Gi"
       limits:
           ephemeral-storage: "3Gi"

节点被驱逐后通过get po还是能看到,用describe命令,可以看到被驱逐的历史原因

Message: The node was low on resource: ephemeral-storage. Container codis-proxy was using 10619440Ki, which exceeds its request of 0.

参考:

  1. Kubernetes pod ephemeral-storage配置
  2. Managing Compute Resources for Containers

kubectl exec 进入容器失败

这种问题我在搭建codis-server的时候遇到过,当时没有配置就绪以及健康检查.但获取pod描述的时候,显示running.其实这个时候容器以及不正常了.

1
2
3
~ kex codis-server-3 sh
rpc error: code = 2 desc = containerd: container not found
command terminated with exit code 126

解决办法:删了这个pod,配置livenessProbe

pod的virtual host name

Deployment衍生的pod,virtual host name就是pod name.

StatefulSet衍生的pod,virtual host name<pod name>.<svc name>.<namespace>.svc.cluster.local.相比Deployment显得更有规律一些.而且支持其他pod访问

pod接连Crashbackoff

Crashbackoff有多种原因.

沙箱创建(FailedCreateSandBox)失败,多半是cni网络插件的问题

镜像拉取,有中国特色社会主义的问题,可能太大了,拉取较慢

也有一种可能是容器并发过高,流量雪崩导致.

比如,现在有3个容器abc,a突然遇到流量洪峰导致内部奔溃,继而Crashbackoff,那么a就会被service剔除出去,剩下的bc也承载不了那么多流量,接连崩溃,最终网站不可访问.这种情况,多见于高并发网站+低效率web容器.

在不改变代码的情况下,最优解是增加副本数,并且加上hpa,实现动态伸缩容.

DNS 效率低下

容器内打开nscd(域名缓存服务),可大幅提升解析性能

严禁生产环境使用alpine作为基础镜像(会导致dns解析请求异常)

deploy

MinimumReplicationUnavailable

如果deploy配置了SecurityContext,但是api-server拒绝了,就会出现这个情况,在api-server的容器里面,去掉SecurityContextDeny这个启动参数.

具体见Using Admission Controllers

service

建了一个服务,但是没有对应的po,会出现什么情况?

请求时一直不会有响应,直到request timeout

参考

  1. Configure Out Of Resource Handling

service connection refuse

原因可能有

  1. pod没有设置readinessProbe,请求到未就绪的pod
  2. kube-proxy宕机了(kube-proxy负责转发请求)
  3. 网络过载

service没有负载均衡

检查一下是否用了headless service.headless service是不会自动负载均衡的…

1
2
3
4
5
kind: Service
spec:
# clusterIP: None的即为`headless service`
  type: ClusterIP
  clusterIP: None

具体表现service没有自己的虚拟IP,nslookup会出现所有pod的ip.但是ping的时候只会出现第一个pod的ip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.31.10.94 172-31-10-94.consul.default.svc.cluster.local
Address 2: 172.31.10.95 172-31-10-95.consul.default.svc.cluster.local
Address 3: 172.31.11.176 172-31-11-176.consul.default.svc.cluster.local

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.973 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.170 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.170/0.571/0.973 ms

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.206 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.178 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.178/0.192/0.206 ms

普通的type: ClusterIP service,nslookup会出现该服务自己的IP

/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.30.15.52 consul.default.svc.cluster.local

ReplicationController不更新

ReplicationController不是用apply去更新的,而是kubectl rolling-update,但是这个指令也废除了,取而代之的是kubectl rollout.所以应该使用kubectl rollout作为更新手段,或者懒一点,apply file之后,delete po.

尽量使用deploy吧.

StatefulSet

pod 更新失败

StatefulSet是逐一更新的,观察一下是否有Crashbackoff的容器,有可能是这个容器导致更新卡住了,删掉即可.

unknown pod

如果 StatefulSet 绑定 pod 状态变成 unknown ,这个时候是非常坑爹的,StatefulSet不会帮你重建pod.

这时会导致外部请求一直失败.

综合建议,不用 StatefulSet ,改用 operator 模式替换它.

kube-apiserver

kube-apiserver 是一组运行在 master 上面的特殊容器。以 阿里云 kubernetes 为例 (kubeadm创建的 kubernetes 同理)

/etc/kubernetes/manifests/ 下面定义了三个文件

  1. kube-apiserver.yaml
  2. kube-controller-manager.yaml
  3. kube-scheduler.yaml

master 节点会自动监视这个目录里面文件的变化,视情况自动重启。

所以修改 api server 的设置只需要修改kube-apiserver.yaml,保存退出,相应的容器就会重启。同理,如果你改错了配置,api server 就会启动失败,修改之前务必仔细看清楚文档

阿里云Kubernetes问题

修改默认ingress

新建一个指向ingress的负载均衡型svc,然后修改一下kube-systemnginx-ingress-controller启动参数.

1
2
3
4
5
6
7
8
        - args:
            - /nginx-ingress-controller
            - '--configmap=$(POD_NAMESPACE)/nginx-configuration'
            - '--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services'
            - '--udp-services-configmap=$(POD_NAMESPACE)/udp-services'
            - '--annotations-prefix=nginx.ingress.kubernetes.io'
            - '--publish-service=$(POD_NAMESPACE)/<自定义svc>'
            - '--v=2'

LoadBalancer服务一直没有IP

具体表现是EXTERNAL-IP一直显示pending.

1
2
3
~ kg svc consul-web
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
consul-web   LoadBalancer   172.30.13.122   <pending>     443:32082/TCP   5m  

这问题跟Alibaba Cloud Provider这个组件有关,cloud-controller-manager有3个组件,他们需要内部选主,可能哪里出错了,当时我把其中一个出问题的pod删了,就好了.

清理Statefulset动态PVC

目前阿里云Statefulset动态PVC用的是nas。

  1. 对于这种存储,需要先把容器副本将为0,或者整个Statefulset删除。
  2. 删除PVC
  3. 把nas挂载到任意一台服务器上面,然后删除pvc对应nas的目录。

升级到v1.12.6-aliyun.1之后节点可分配内存变少

该版本每个节点保留了1Gi,相当于整个集群少了N GB(N为节点数)供Pod分配.

如果节点是4G的,Pod请求3G,极其容易被驱逐.

建议提高节点规格.

1
Server Version: version.Info{Major:"1", Minor:"12+", GitVersion:"v1.12.6-aliyun.1", GitCommit:"8cb561c", GitTreeState:"", BuildDate:"2019-04-22T11:34:20Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}

新加节点出现NetworkUnavailable

RouteController failed to create a route

看一下kubernetes events,是否出现了

1
timed out waiting for the condition -> WaitCreate: ceate route for table vtb-wz9cpnsbt11hlelpoq2zh error, Aliyun API Error: RequestId: 7006BF4E-000B-4E12-89F2-F0149D6688E4 Status Code: 400 Code: QuotaExceeded Message: Route entry quota exceeded in this route table  

出现这个问题是因为达到了VPC的自定义路由条目限制,默认是48,需要提高vpc_quota_route_entrys_num的配额

访问LoadBalancer svc随机出现流量转发异常

[bug]阿里云kubernetes版不检查loadbalancer service port,导致流量被异常转发 简单的说,同SLB不能有相同的svc端口,不然会瞎转发。

官方说法:

复用同一个SLB的多个Service不能有相同的前端监听端口,否则会造成端口冲突。

控制台显示的节点内存使用率总是偏大

Docker容器内存监控

原因在于他们控制台用的是usage_in_bytes(cache+buffer),所以会比云监控看到的数字大

Ingress Controller 玄学优化

修改 kube-system 下面名为 nginx-configuration 的configmap

1
2
3
4
5
6
7
8
9
10
11
proxy-connect-timeout: "75" 
proxy-read-timeout: "75" 
proxy-send-timeout: "75" 
upstream-keepalive-connections: "300" 
upstream-keepalive-timeout: "300" 
upstream-keepalive-requests: "1000" 
keep-alive-requests: "1000" 
keep-alive: "300"
disable-access-log: "true" 
client-header-timeout: "75" 
worker-processes: "16"

注意,是一个项对应一个配置,而不是一个文件. 格式大概这样

1
2
3
4
5
6
7
8
9
➜  ~ kg cm nginx-configuration -o yaml
apiVersion: v1
data:
  disable-access-log: "true"
  keep-alive: "300"
  keep-alive-requests: "1000"
  proxy-body-size: 20m
  worker-processes: "16"
  ......

pid 问题

1
Message: **Liveness probe failed: rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:262: starting container process caused "process_linux.go:86: adding pid 30968 to cgroups caused \"failed to write 30968 to cgroup.procs: write /sys/fs/cgroup/cpu,cpuacct/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podfe4cc065_cc58_11e9_bf64_00163e08cd06.slice/docker-0447a362d2cf4719ae2a4f5ad0f96f702aacf8ee38d1c73b445ce41bdaa8d24a.scope/cgroup.procs: invalid argument\""

阿里云初始化节点用的 centos 版本老旧,内核是3.1, Centos7.4的内核3.10还没有支持cgroup对于pid/fd限制,所以会出现这类问题.

建议:

  1. 手动维护节点,升级到5.x的内核(目前已有一些节点升级到5.x,但是docker版本还是 17.6.2 ,持续观察中~)
  2. 安装 NPD + eventer ,利用事件机制提醒管理员手动维护

OSS PVC FailedMount

可以通过PV制定access key,access secret +PVC的方式使用OSS.某天某个deploy遇到 FailedMount 的问题,联系到阿里云的开发工程师,说是 flexvolume 在初次运行的节点上面运行会有问题,要让他”重新注册”

影响到的版本: registry-vpc.cn-shenzhen.aliyuncs.com/acs/flexvolume:v1.12.6.16-1f4c6cb-aliyun

解决方案:

1
touch /usr/libexec/kubernetes/kubelet-plugins/volume/exec/alicloud~oss/debug

参考(应用调度相关):

  1. Kubernetes之健康检查与服务依赖处理
  2. kubernetes如何解决服务依赖呢?
  3. Kubernetes之路 1 - Java应用资源限制的迷思
  4. Control CPU Management Policies on the Node
  5. Reserve Compute Resources for System Daemons
  6. Configure Out Of Resource Handling

Kubernetes Cluster Management Experience (Lessons)

2020-02-26 Update: This article has been updated again, please go to Kubernetes Cluster Management Experience

Node Issues

Correct Steps to Delete a Node

1
2
3
4
5
# SchedulingDisabled, ensure new containers won't be scheduled to this node
kubectl cordon $node
# Evict all pods except daemonsets
kubectl drain $node   --ignore-daemonsets
kubectl delete $node

Correct Steps to Maintain a Node

1
2
3
4
5
6
# SchedulingDisabled, ensure new containers won't be scheduled to this node
kubectl cordon $node
# Evict all pods except daemonsets
kubectl drain $node --ignore-daemonsets --delete-local-data
# After maintenance is complete, restore its normal state
kubectl uncordon $node

–delete-local-data means ignoring temporary storage like emptyDir

ImageGCFailed

kubelet can clean up unused containers and images. kubelet recycles containers and images every minute and every five minutes respectively.

Configure kubelet garbage collection

But kubelet’s garbage collection has a problem: it can only recycle unused images, somewhat like docker system prune. However, observation shows that dead containers are not the biggest problem; running containers are the bigger problem. If ImageGCFailed keeps occurring, and container usage of ephemeral-storage/hostpath (host directories) keeps increasing, it will eventually lead to more serious DiskPressure problems, affecting all containers on the node.

Recommendations:

  1. For high-spec machines (4 cores 32G and above), configure 100G+ SSD space for the docker directory
  2. Configure ResourceQuota to limit overall resource quotas
  3. Disable ephemeral-storage (local file writes) on the container side, or use spec.containers[].resources.limits.ephemeral-storage to limit and control host directory writes

Node Disk Pressure (DiskPressure)

1
--eviction-hard=imagefs.available<15%,memory.available<300Mi,nodefs.available<10%,nodefs.inodesFree<5%

kubelet specifies disk pressure at startup. Taking Alibaba Cloud as an example, imagefs.available<15% means when the container’s read-write layer is less than 15%, the node will be evicted. The consequence of node eviction is the occurrence of DiskPressure, and the node can no longer run any images until the disk problem is resolved. If containers on the node use host directories, this problem will be fatal. Because you can’t delete the directories, but it’s really the accumulation of these host directories that caused the node to be evicted.

So, develop good habits: don’t write things randomly in containers (writing files in containers will occupy ephemeral-storage, too much ephemeral-storage will cause pods to be evicted), use stateless containers more, choose storage methods carefully, try not to use hostpath storage.

When this happens, it really feels like wanting to cry but having no tears.

1
2
3
4
5
6
7
8
9
10
11
12
13
Events:
  Type     Reason                 Age                   From                                            Message
  ----     ------                 ----                  ----                                            -------
  Warning  FreeDiskSpaceFailed    23m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 5182058496 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  ImageGCFailed          18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Warning  ImageGCFailed          13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Normal   NodeHasNoDiskPressure  10m (x5 over 47d)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasNoDiskPressure
  Normal   Starting               10m                   kube-proxy, node.xxxx1  Starting kube-proxy.
  Normal   NodeHasDiskPressure    10m (x4 over 42m)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasDiskPressure
  Warning  EvictionThresholdMet   8m29s (x19 over 42m)  kubelet, node.xxxx1     Attempting to reclaim ephemeral-storage
  Warning  ImageGCFailed          3m4s                  kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4920913920 bytes, but freed 0 bytes

ImageGCFailed is a very problematic state. When this state appears, it means kubelet tried to reclaim disk but failed. At this point, consider whether to manually go on the machine to fix it.

Recommendations:

  1. When the number of images is above 200, purchase 100G SSD to store images
  2. Use less temporary storage (empty-dir, hostpath, etc.)

Reference links:

  1. Eviction Signals
  2. 10 Diagrams to Deeply Understand Docker Containers and Images

Node CPU Spikes

It’s possible the node is performing GC (container GC/image GC). Check with describe node. I encountered this situation once, and in the end, there were many fewer containers on the node, which was a bit frustrating.

1
2
3
4
Events:
  Type     Reason                 Age                 From                                         Message
  ----     ------                 ----                ----
  Warning  ImageGCFailed          45m                 kubelet, cn-shenzhen.xxxx  failed to get image stats: rpc error: code = DeadlineExceeded desc = context deadline exceeded

Reference:

kubelet Source Code Analysis: Garbage Collect

Node Disconnection (unknown)

1
2
3
4
5
6
  Ready                False   Fri, 28 Jun 2019 10:19:21 +0800   Thu, 27 Jun 2019 07:07:38 +0800   KubeletNotReady              PLEG is not healthy: pleg was last seen active 27h14m51.413818128s ago; threshold is 3m0s

Events:
  Type     Reason             Age                 From                                         Message
  ----     ------             ----                ----                                         -------
  Warning  ContainerGCFailed  5s (x543 over 27h)  kubelet, cn-shenzhen.xxxx                    rpc error: code = DeadlineExceeded desc = context deadline exceeded

After SSHing into the host, I found that although the docker service was still running, docker ps was stuck. So I upgraded the kernel to 5.1 and restarted.

Later it was discovered that someone deployed a problematic image that would crash any node it ran on, no matter which node. That was frustrating.

unknown is a very serious problem and must be taken seriously. When a node becomes unknown, the kubernetes master itself doesn’t know whether containers on the node are alive or dead. If there’s a very important container running on an unknown node, and it happens to crash, kubernetes won’t automatically start another container for you. This is something to note.

Reference links:

Node flapping between Ready/NotReady with PLEG issues In-depth Analysis of Kubernetes Pod Disruption Budgets (PDB)

SystemOOM

SystemOOM doesn’t necessarily mean the machine’s memory is exhausted. One situation is docker controlling container memory.

By default, Docker’s storage location is: /var/lib/docker/containers/$id

There’s an important file in this directory: hostconfig.json, a partial excerpt looks like this:

1
2
3
4
5
6
7
8
9
	"MemorySwappiness": -1,
	"OomKillDisable": false,
	"PidsLimit": 0,
	"Ulimits": null,
	"CpuCount": 0,
	"CpuPercent": 0,
	"IOMaximumIOps": 0,
	"IOMaximumBandwidth": 0
}

"OomKillDisable": false, prevents the docker service from harmonizing containers that exceed resource limits by killing processes/restarting, but instead sanctions them in other ways (details can be seen here)

docker daemon stuck

I encountered this situation once. The reason was a problematic container that affected the entire node.

This problem needs to be resolved quickly, because all pods on the node will become unknown.

1
2
3
systemctl daemon-reexec
systemctl restart docker (optional, depending on situation)
systemctl restart kubelet

In severe cases, only restarting the node and stopping the involved container works.

Recommendation: For container liveness/readiness, use tcp/httpget methods, avoid high-frequency use of exec

pod

pod Frequent Restarts

There are many reasons, cannot generalize

One situation is: deploy configured health checks, node runs normally, but because node load is too high, health checks fail (load15 consistently above 2), frequent Backoff. After I raised the unhealthy threshold and reduced node load, the problem was resolved.

1
2
3
4
5
6
7
8
9
10
          livenessProbe:
            # Unhealthy threshold
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 8080
            timeoutSeconds: 1

Resources Reached Limit Setting

Raise limit or check application

Readiness/Liveness connection refused

Readiness check failures will also restart, but Readiness check failure isn’t necessarily an application problem. If the node itself is overloaded, connection refused or timeout can also occur.

This problem needs to be investigated on the node.

pod Evicted

  1. Node added taint causing pod to be evicted
  2. ephemeral-storage exceeded limit and was evicted
    1. If EmptyDir usage exceeds its SizeLimit, then this pod will be evicted
    2. If Container usage (log, and if there’s no overlay partition, includes imagefs) exceeds its limit, then this pod will be evicted
    3. If Pod’s total usage of local temporary storage (all emptydir and container) exceeds the sum of all container limits in the pod, then the pod is evicted

ephemeral-storage is temporary storage used by a pod.

1
2
3
4
5
resources:
       requests: 
           ephemeral-storage: "2Gi"
       limits:
           ephemeral-storage: "3Gi"

After a node is evicted, you can still see it through get po. Use the describe command to see the historical reason for eviction.

Message: The node was low on resource: ephemeral-storage. Container codis-proxy was using 10619440Ki, which exceeds its request of 0.

References:

  1. Kubernetes pod ephemeral-storage configuration
  2. Managing Compute Resources for Containers

kubectl exec Entering Container Failed

I encountered this problem when setting up codis-server. At that time, readiness and health checks were not configured. But when getting pod description, it showed running. Actually, at this point, the container was already abnormal.

1
2
3
~ kex codis-server-3 sh
rpc error: code = 2 desc = containerd: container not found
command terminated with exit code 126

Solution: Delete this pod, configure livenessProbe

pod’s virtual host name

For pods derived from Deployment, virtual host name is pod name.

For pods derived from StatefulSet, virtual host name is <pod name>.<svc name>.<namespace>.svc.cluster.local. Compared to Deployment, it’s more regular. And it supports access from other pods.

pod Consecutive Crashbackoff

Crashbackoff has many causes.

Sandbox creation (FailedCreateSandBox) failure is mostly a CNI network plugin problem.

Image pulling has issues with Chinese characteristics, may be too large, pulling is slow.

There’s also a possibility that container concurrency is too high, causing traffic avalanche.

For example, there are now 3 containers abc. a suddenly encounters a traffic spike causing internal crash, then Crashbackoff, so a will be removed by service. The remaining bc can’t handle that much traffic, crash consecutively, and finally the website becomes inaccessible. This situation is common in high-concurrency websites + low-efficiency web containers.

Without changing code, the optimal solution is to increase replica count and add HPA to achieve dynamic scaling.

DNS Inefficiency

Enable nscd (domain name caching service) inside containers to significantly improve resolution performance.

Strictly prohibit using alpine as base image in production (will cause DNS resolution request abnormalities)

deploy

MinimumReplicationUnavailable

If deploy configured SecurityContext, but api-server rejected it, this situation will occur. In the api-server container, remove the SecurityContextDeny startup parameter.

See Using Admission Controllers

service

Created a Service, But No Corresponding po, What Happens?

Requests will have no response until request timeout

Reference

  1. Configure Out Of Resource Handling

service connection refuse

Possible reasons:

  1. pod didn’t set readinessProbe, requests go to unready pods
  2. kube-proxy is down (kube-proxy is responsible for forwarding requests)
  3. Network overload

service No Load Balancing

Check if headless service is used. headless service does not automatically load balance…

1
2
3
4
5
kind: Service
spec:
# clusterIP: None is `headless service`
  type: ClusterIP
  clusterIP: None

Specific behavior: service has no virtual IP of its own, nslookup will show all pod IPs. But when pinging, only the first pod’s IP appears.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.31.10.94 172-31-10-94.consul.default.svc.cluster.local
Address 2: 172.31.10.95 172-31-10-95.consul.default.svc.cluster.local
Address 3: 172.31.11.176 172-31-11-176.consul.default.svc.cluster.local

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.973 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.170 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.170/0.571/0.973 ms

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.206 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.178 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.178/0.192/0.206 ms

For normal type: ClusterIP service, nslookup will show the service’s own IP

/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.30.15.52 consul.default.svc.cluster.local

ReplicationController Not Updating

ReplicationController is not updated with apply, but with kubectl rolling-update. However, this command is also deprecated, replaced by kubectl rollout. So should use kubectl rollout as the update method, or be lazy, apply file then delete po.

Try to use deploy instead.

StatefulSet

pod Update Failed

StatefulSet updates one by one. Observe if there are containers in Crashbackoff. It’s possible this container caused the update to get stuck. Delete it.

unknown pod

If a StatefulSet bound pod’s status becomes unknown, this is very problematic. StatefulSet won’t help you recreate the pod.

This will cause external requests to keep failing.

Comprehensive recommendation: don’t use StatefulSet, replace it with operator pattern.

kube-apiserver

kube-apiserver is a set of special containers running on master. Taking Alibaba Cloud kubernetes as an example (same for kubernetes created with kubeadm)

Three files are defined under /etc/kubernetes/manifests/

  1. kube-apiserver.yaml
  2. kube-controller-manager.yaml
  3. kube-scheduler.yaml

The master node will automatically monitor changes to files in this directory and automatically restart as needed.

So to modify api server settings, just modify kube-apiserver.yaml, save and exit, and the corresponding container will restart. Similarly, if you modify the configuration incorrectly, api server will fail to start. Before modifying, be sure to carefully read the documentation

Alibaba Cloud Kubernetes Issues

Modify Default Ingress

Create a new load balancer type svc pointing to ingress, then modify the startup parameters of nginx-ingress-controller under kube-system.

1
2
3
4
5
6
7
8
        - args:
            - /nginx-ingress-controller
            - '--configmap=$(POD_NAMESPACE)/nginx-configuration'
            - '--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services'
            - '--udp-services-configmap=$(POD_NAMESPACE)/udp-services'
            - '--annotations-prefix=nginx.ingress.kubernetes.io'
            - '--publish-service=$(POD_NAMESPACE)/<custom svc>'
            - '--v=2'

LoadBalancer Service Has No IP

Specific behavior is EXTERNAL-IP always shows pending.

1
2
3
~ kg svc consul-web
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
consul-web   LoadBalancer   172.30.13.122   <pending>     443:32082/TCP   5m  

This problem is related to the Alibaba Cloud Provider component. cloud-controller-manager has 3 components. They need internal leader election. Something may have gone wrong. At that time, I deleted one of the problematic pods, and it was fixed.

Clean Statefulset Dynamic PVC

Currently, Alibaba Cloud Statefulset dynamic PVC uses nas.

  1. For this type of storage, first scale container replicas to 0, or delete the entire Statefulset.
  2. Delete PVC
  3. Mount nas to any server, then delete the pvc corresponding nas directory.

After Upgrading to v1.12.6-aliyun.1, Node Allocatable Memory Decreased

This version reserves 1Gi per node, equivalent to the entire cluster having N GB less (N is the number of nodes) for Pod allocation.

If a node is 4G and a Pod requests 3G, it’s extremely easy to be evicted.

Recommendation: Increase node specifications.

1
Server Version: version.Info{Major:"1", Minor:"12+", GitVersion:"v1.12.6-aliyun.1", GitCommit:"8cb561c", GitTreeState:"", BuildDate:"2019-04-22T11:34:20Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}

New Node Shows NetworkUnavailable

RouteController failed to create a route

Check kubernetes events to see if this appears:

1
timed out waiting for the condition -> WaitCreate: ceate route for table vtb-wz9cpnsbt11hlelpoq2zh error, Aliyun API Error: RequestId: 7006BF4E-000B-4E12-89F2-F0149D6688E4 Status Code: 400 Code: QuotaExceeded Message: Route entry quota exceeded in this route table  

This problem occurs because the VPC custom route entry limit was reached. Default is 48. Need to increase the quota for vpc_quota_route_entrys_num.

Accessing LoadBalancer svc Randomly Shows Traffic Forwarding Abnormalities

See [bug] Alibaba Cloud kubernetes version doesn’t check loadbalancer service port, causing traffic to be abnormally forwarded Simply put, the same SLB cannot have the same svc port, otherwise it will forward blindly.

Official statement:

Multiple Services reusing the same SLB cannot have the same frontend listening port, otherwise it will cause port conflicts.

Console Shows Node Memory Usage Always Too High

Docker Container Memory Monitoring

The reason is their console uses usage_in_bytes(cache+buffer), so it will be larger than the numbers seen in cloud monitoring.

Ingress Controller Mystical Optimization

Modify the configmap named nginx-configuration under kube-system

1
2
3
4
5
6
7
8
9
10
11
proxy-connect-timeout: "75" 
proxy-read-timeout: "75" 
proxy-send-timeout: "75" 
upstream-keepalive-connections: "300" 
upstream-keepalive-timeout: "300" 
upstream-keepalive-requests: "1000" 
keep-alive-requests: "1000" 
keep-alive: "300"
disable-access-log: "true" 
client-header-timeout: "75" 
worker-processes: "16"

Note: one item corresponds to one configuration, not one file. Format is roughly like this:

1
2
3
4
5
6
7
8
9
➜  ~ kg cm nginx-configuration -o yaml
apiVersion: v1
data:
  disable-access-log: "true"
  keep-alive: "300"
  keep-alive-requests: "1000"
  proxy-body-size: 20m
  worker-processes: "16"
  ......

pid Problem

1
Message: **Liveness probe failed: rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:262: starting container process caused "process_linux.go:86: adding pid 30968 to cgroups caused \"failed to write 30968 to cgroup.procs: write /sys/fs/cgroup/cpu,cpuacct/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podfe4cc065_cc58_11e9_bf64_00163e08cd06.slice/docker-0447a362d2cf4719ae2a4f5ad0f96f702aacf8ee38d1c73b445ce41bdaa8d24a.scope/cgroup.procs: invalid argument\""

Alibaba Cloud initialization nodes use an old centos version, kernel is 3.1. Centos7.4’s kernel 3.10 doesn’t support cgroup limits for pid/fd yet, so this type of problem occurs.

Recommendations:

  1. Manually maintain nodes, upgrade to 5.x kernel (currently some nodes have been upgraded to 5.x, but docker version is still 17.6.2, continuing to observe~)
  2. Install NPD + eventer, use event mechanism to alert administrators for manual maintenance

OSS PVC FailedMount

OSS can be used through PV specifying access key, access secret + PVC. One day, a deploy encountered a FailedMount problem. Contacted Alibaba Cloud development engineers, who said flexvolume will have problems running on nodes running for the first time, need to let it “re-register”

Affected version: registry-vpc.cn-shenzhen.aliyuncs.com/acs/flexvolume:v1.12.6.16-1f4c6cb-aliyun

Solution:

1
touch /usr/libexec/kubernetes/kubelet-plugins/volume/exec/alicloud~oss/debug

References (application scheduling related):

  1. Kubernetes Health Checks and Service Dependency Handling
  2. How does kubernetes solve service dependencies?
  3. Kubernetes Road 1 - Java Application Resource Limit Misconceptions
  4. Control CPU Management Policies on the Node
  5. Reserve Compute Resources for System Daemons
  6. Configure Out Of Resource Handling

Опыт (уроки) управления кластером Kubernetes

2020-02-26 Обновление: Эта статья снова обновлена, пожалуйста, перейдите к Опыт управления кластером Kubernetes

Проблемы узлов

Правильные шаги для удаления узла

1
2
3
4
5
# SchedulingDisabled, убедитесь, что новые контейнеры не будут запланированы на этот узел
kubectl cordon $node
# Вытеснить все поды, кроме daemonsets
kubectl drain $node   --ignore-daemonsets
kubectl delete $node

Правильные шаги для обслуживания узла

1
2
3
4
5
6
# SchedulingDisabled, убедитесь, что новые контейнеры не будут запланированы на этот узел
kubectl cordon $node
# Вытеснить все поды, кроме daemonsets
kubectl drain $node --ignore-daemonsets --delete-local-data
# После завершения обслуживания восстановите его нормальное состояние
kubectl uncordon $node

–delete-local-data означает игнорирование временного хранилища, такого как emptyDir

ImageGCFailed

kubelet может очистить неиспользуемые контейнеры и образы. kubelet перерабатывает контейнеры и образы каждую минуту и каждые пять минут соответственно.

Настройка сборки мусора kubelet

Но у сборки мусора kubelet есть проблема: она может перерабатывать только неиспользуемые образы, что-то вроде docker system prune. Однако наблюдения показывают, что мертвые контейнеры — не самая большая проблема; запущенные контейнеры — большая проблема. Если ImageGCFailed продолжает происходить, а использование контейнерами ephemeral-storage/hostpath (хост-каталоги) продолжает увеличиваться, это в конечном итоге приведет к более серьезным проблемам DiskPressure, затрагивающим все контейнеры на узле.

Рекомендации:

  1. Для машин с высокими характеристиками (4 ядра 32G и выше) настройте 100G+ SSD пространства для каталога docker
  2. Настройте ResourceQuota для ограничения общих квот ресурсов
  3. Отключите ephemeral-storage (запись локальных файлов) на стороне контейнера или используйте spec.containers[].resources.limits.ephemeral-storage для ограничения и контроля записи в хост-каталоги

Давление диска узла (DiskPressure)

1
--eviction-hard=imagefs.available<15%,memory.available<300Mi,nodefs.available<10%,nodefs.inodesFree<5%

kubelet указывает давление диска при запуске. В качестве примера возьмем Alibaba Cloud: imagefs.available<15% означает, что когда слой чтения-записи контейнера меньше 15%, узел будет вытеснен. Последствием вытеснения узла является возникновение DiskPressure, и узел больше не может запускать какие-либо образы, пока проблема с диском не будет решена. Если контейнеры на узле используют хост-каталоги, эта проблема будет фатальной. Потому что вы не можете удалить каталоги, но именно накопление этих хост-каталогов привело к вытеснению узла.

Поэтому выработайте хорошие привычки: не пишите вещи случайно в контейнерах (запись файлов в контейнерах будет занимать ephemeral-storage, слишком много ephemeral-storage приведет к вытеснению подов), используйте больше stateless-контейнеров, тщательно выбирайте способы хранения, старайтесь не использовать хранилище hostpath.

Когда это происходит, действительно чувствуешь, что хочешь плакать, но нет слез.

1
2
3
4
5
6
7
8
9
10
11
12
13
Events:
  Type     Reason                 Age                   From                                            Message
  ----     ------                 ----                  ----                                            -------
  Warning  FreeDiskSpaceFailed    23m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 5182058496 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  ImageGCFailed          18m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 6089891840 bytes, but freed 0 bytes
  Warning  FreeDiskSpaceFailed    13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Warning  ImageGCFailed          13m                   kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4953321472 bytes, but freed 0 bytes
  Normal   NodeHasNoDiskPressure  10m (x5 over 47d)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasNoDiskPressure
  Normal   Starting               10m                   kube-proxy, node.xxxx1  Starting kube-proxy.
  Normal   NodeHasDiskPressure    10m (x4 over 42m)     kubelet, node.xxxx1     Node node.xxxx1 status is now: NodeHasDiskPressure
  Warning  EvictionThresholdMet   8m29s (x19 over 42m)  kubelet, node.xxxx1     Attempting to reclaim ephemeral-storage
  Warning  ImageGCFailed          3m4s                  kubelet, node.xxxx1     failed to garbage collect required amount of images. Wanted to free 4920913920 bytes, but freed 0 bytes

ImageGCFailed — очень проблемное состояние. Когда появляется это состояние, это означает, что kubelet попытался освободить диск, но не смог. На этом этапе рассмотрите возможность ручного исправления на машине.

Рекомендации:

  1. Когда количество образов превышает 200, приобретите 100G SSD для хранения образов
  2. Используйте меньше временного хранилища (empty-dir, hostpath и т.д.)

Ссылки:

  1. Сигналы вытеснения
  2. 10 диаграмм для глубокого понимания контейнеров и образов Docker

Высокое использование CPU узла

Возможно, узел выполняет GC (GC контейнера/GC образа). Проверьте с помощью describe node. Я столкнулся с этой ситуацией один раз, и в итоге контейнеров на узле стало намного меньше, что было немного расстраивающим.

1
2
3
4
Events:
  Type     Reason                 Age                 From                                         Message
  ----     ------                 ----                ----
  Warning  ImageGCFailed          45m                 kubelet, cn-shenzhen.xxxx  failed to get image stats: rpc error: code = DeadlineExceeded desc = context deadline exceeded

Ссылка:

Анализ исходного кода kubelet: Сборка мусора

Отключение узла (unknown)

1
2
3
4
5
6
  Ready                False   Fri, 28 Jun 2019 10:19:21 +0800   Thu, 27 Jun 2019 07:07:38 +0800   KubeletNotReady              PLEG is not healthy: pleg was last seen active 27h14m51.413818128s ago; threshold is 3m0s

Events:
  Type     Reason             Age                 From                                         Message
  ----     ------             ----                ----                                         -------
  Warning  ContainerGCFailed  5s (x543 over 27h)  kubelet, cn-shenzhen.xxxx                    rpc error: code = DeadlineExceeded desc = context deadline exceeded

После SSH-входа на хост я обнаружил, что хотя служба docker все еще работает, docker ps зависла. Поэтому я обновил ядро до 5.1 и перезапустил.

Позже выяснилось, что кто-то развернул проблемный образ, который крашил любой узел, на котором он запускался, независимо от узла. Это было расстраивающим.

unknown — очень серьезная проблема, и к ней нужно относиться серьезно. Когда узел становится unknown, сам kubernetes master не знает, живы ли контейнеры на узле или мертвы. Если на unknown-узле работает очень важный контейнер, и он случайно упал, kubernetes не запустит для вас другой контейнер автоматически. Это нужно отметить.

Ссылки:

Узел мечется между Ready/NotReady с проблемами PLEG Глубокий анализ Pod Disruption Budgets (PDB) Kubernetes

SystemOOM

SystemOOM не обязательно означает, что память машины исчерпана. Одна ситуация — это docker, контролирующий память контейнера.

По умолчанию место хранения Docker: /var/lib/docker/containers/$id

В этом каталоге есть важный файл: hostconfig.json, частичный отрывок выглядит так:

1
2
3
4
5
6
7
8
9
	"MemorySwappiness": -1,
	"OomKillDisable": false,
	"PidsLimit": 0,
	"Ulimits": null,
	"CpuCount": 0,
	"CpuPercent": 0,
	"IOMaximumIOps": 0,
	"IOMaximumBandwidth": 0
}

"OomKillDisable": false, предотвращает гармонизацию службой docker контейнеров, превышающих лимиты ресурсов, путем убийства процессов/перезапуска, а вместо этого санкционирует их другими способами (подробности можно увидеть здесь)

docker daemon зависла

Я столкнулся с этой ситуацией один раз. Причина была в проблемном контейнере, который повлиял на весь узел.

Эту проблему нужно решить быстро, потому что все поды на узле станут unknown.

1
2
3
systemctl daemon-reexec
systemctl restart docker (опционально, в зависимости от ситуации)
systemctl restart kubelet

В тяжелых случаях работает только перезапуск узла и остановка задействованного контейнера.

Рекомендация: Для liveness/readiness контейнера используйте методы tcp/httpget, избегайте частого использования exec

pod

Частые перезапуски pod

Есть много причин, нельзя обобщать

Одна ситуация: deploy настроил проверки работоспособности, узел работает нормально, но из-за слишком высокой нагрузки узла проверки работоспособности не проходят (load15 постоянно выше 2), частые Backoff. После того, как я повысил порог нездоровья и снизил нагрузку узла, проблема была решена.

1
2
3
4
5
6
7
8
9
10
          livenessProbe:
            # Порог нездоровья
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 8080
            timeoutSeconds: 1

Ресурсы достигли установленного лимита

Повысьте лимит или проверьте приложение

Readiness/Liveness connection refused

Неудачные проверки Readiness также перезапустят, но неудача проверки Readiness не обязательно является проблемой приложения. Если сам узел перегружен, также может возникнуть connection refused или timeout.

Эту проблему нужно исследовать на узле.

pod вытеснен (Evicted)

  1. Узел добавил taint, вызвав вытеснение pod
  2. ephemeral-storage превысил лимит и был вытеснен
    1. Если использование EmptyDir превышает его SizeLimit, то этот pod будет вытеснен
    2. Если использование Container (лог, и если нет раздела overlay, включает imagefs) превышает его лимит, то этот pod будет вытеснен
    3. Если общее использование локального временного хранилища Pod (все emptydir и container) превышает сумму всех лимитов контейнеров в pod, то pod вытесняется

ephemeral-storage — это временное хранилище, используемое pod.

1
2
3
4
5
resources:
       requests: 
           ephemeral-storage: "2Gi"
       limits:
           ephemeral-storage: "3Gi"

После вытеснения узла вы все еще можете видеть его через get po. Используйте команду describe, чтобы увидеть историческую причину вытеснения.

Message: The node was low on resource: ephemeral-storage. Container codis-proxy was using 10619440Ki, which exceeds its request of 0.

Ссылки:

  1. Настройка ephemeral-storage pod Kubernetes
  2. Управление вычислительными ресурсами для контейнеров

kubectl exec вход в контейнер не удался

Я столкнулся с этой проблемой при настройке codis-server. В то время готовность и проверки работоспособности не были настроены. Но при получении описания pod оно показывало running. На самом деле, в этот момент контейнер уже был ненормальным.

1
2
3
~ kex codis-server-3 sh
rpc error: code = 2 desc = containerd: container not found
command terminated with exit code 126

Решение: Удалите этот pod, настройте livenessProbe

виртуальное имя хоста pod

Для подов, производных от Deployment, virtual host name — это pod name.

Для подов, производных от StatefulSet, virtual host name — это <pod name>.<svc name>.<namespace>.svc.cluster.local. По сравнению с Deployment, это более регулярно. И поддерживает доступ от других подов.

последовательные Crashbackoff pod

Crashbackoff имеет много причин.

Неудача создания песочницы (FailedCreateSandBox) в основном является проблемой плагина сети CNI.

Вытягивание образа имеет проблемы с китайской спецификой, может быть слишком большим, вытягивание медленное.

Также есть возможность, что параллелизм контейнера слишком высок, вызывая лавину трафика.

Например, теперь есть 3 контейнера abc. a внезапно столкнулся со всплеском трафика, вызвав внутренний сбой, затем Crashbackoff, поэтому a будет удален service. Оставшиеся bc не могут обработать столько трафика, последовательно падают, и в конечном итоге веб-сайт становится недоступным. Эта ситуация часто встречается в высококонкурентных веб-сайтах + неэффективных веб-контейнерах.

Без изменения кода оптимальное решение — увеличить количество реплик и добавить HPA для достижения динамического масштабирования.

Неэффективность DNS

Включите nscd (службу кэширования доменных имен) внутри контейнеров, чтобы значительно повысить производительность разрешения.

Строго запрещено использовать alpine в качестве базового образа в production (вызовет аномалии запросов разрешения DNS)

deploy

MinimumReplicationUnavailable

Если deploy настроил SecurityContext, но api-server отклонил его, возникнет эта ситуация. В контейнере api-server удалите параметр запуска SecurityContextDeny.

См. Использование контроллеров допуска

service

Создана служба, но нет соответствующего po, что произойдет?

Запросы не будут иметь ответа до истечения времени ожидания запроса

Ссылка

  1. Настройка обработки нехватки ресурсов

service connection refuse

Возможные причины:

  1. pod не установил readinessProbe, запросы идут на неготовые поды
  2. kube-proxy не работает (kube-proxy отвечает за пересылку запросов)
  3. Перегрузка сети

service нет балансировки нагрузки

Проверьте, используется ли headless service. headless service не балансирует нагрузку автоматически…

1
2
3
4
5
kind: Service
spec:
# clusterIP: None — это `headless service`
  type: ClusterIP
  clusterIP: None

Конкретное поведение: у службы нет собственного виртуального IP, nslookup покажет все IP подов. Но при ping будет появляться только IP первого пода.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.31.10.94 172-31-10-94.consul.default.svc.cluster.local
Address 2: 172.31.10.95 172-31-10-95.consul.default.svc.cluster.local
Address 3: 172.31.11.176 172-31-11-176.consul.default.svc.cluster.local

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.973 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.170 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.170/0.571/0.973 ms

/ # ping consul
PING consul (172.31.10.94): 56 data bytes
64 bytes from 172.31.10.94: seq=0 ttl=62 time=0.206 ms
64 bytes from 172.31.10.94: seq=1 ttl=62 time=0.178 ms
^C
--- consul ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.178/0.192/0.206 ms

Для обычного типа: ClusterIP service, nslookup покажет собственный IP службы

/ # nslookup consul
nslookup: can't resolve '(null)': Name does not resolve

Name:      consul
Address 1: 172.30.15.52 consul.default.svc.cluster.local

ReplicationController не обновляется

ReplicationController не обновляется с помощью apply, а с помощью kubectl rolling-update. Однако эта команда также устарела, заменена на kubectl rollout. Поэтому следует использовать kubectl rollout в качестве метода обновления, или быть ленивым, применить файл, затем удалить po.

Старайтесь использовать deploy вместо этого.

StatefulSet

обновление pod не удалось

StatefulSet обновляется по одному. Наблюдайте, есть ли контейнеры в Crashbackoff. Возможно, этот контейнер вызвал зависание обновления. Удалите его.

unknown pod

Если статус привязанного к StatefulSet pod становится unknown, это очень проблематично. StatefulSet не поможет вам пересоздать pod.

Это приведет к постоянным сбоям внешних запросов.

Комплексная рекомендация: не используйте StatefulSet, замените его паттерном operator.

kube-apiserver

kube-apiserver — это набор специальных контейнеров, работающих на master. В качестве примера возьмем kubernetes Alibaba Cloud (то же самое для kubernetes, созданного с помощью kubeadm)

Три файла определены под /etc/kubernetes/manifests/

  1. kube-apiserver.yaml
  2. kube-controller-manager.yaml
  3. kube-scheduler.yaml

Узел master будет автоматически отслеживать изменения файлов в этом каталоге и автоматически перезапускаться по мере необходимости.

Поэтому для изменения настроек api server просто измените kube-apiserver.yaml, сохраните и выйдите, и соответствующий контейнер перезапустится. Аналогично, если вы неправильно измените конфигурацию, api server не запустится. Перед изменением обязательно внимательно прочитайте документацию

Проблемы Kubernetes Alibaba Cloud

Изменить Ingress по умолчанию

Создайте новый svc типа балансировщика нагрузки, указывающий на ingress, затем измените параметры запуска nginx-ingress-controller под kube-system.

1
2
3
4
5
6
7
8
        - args:
            - /nginx-ingress-controller
            - '--configmap=$(POD_NAMESPACE)/nginx-configuration'
            - '--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services'
            - '--udp-services-configmap=$(POD_NAMESPACE)/udp-services'
            - '--annotations-prefix=nginx.ingress.kubernetes.io'
            - '--publish-service=$(POD_NAMESPACE)/<пользовательский svc>'
            - '--v=2'

У службы LoadBalancer нет IP

Конкретное поведение: EXTERNAL-IP всегда показывает pending.

1
2
3
~ kg svc consul-web
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
consul-web   LoadBalancer   172.30.13.122   <pending>     443:32082/TCP   5m  

Эта проблема связана с компонентом Alibaba Cloud Provider. cloud-controller-manager имеет 3 компонента. Им нужно внутреннее избрание лидера. Возможно, что-то пошло не так. В то время я удалил один из проблемных pods, и это было исправлено.

Очистка динамического PVC Statefulset

В настоящее время динамический PVC Statefulset Alibaba Cloud использует nas.

  1. Для этого типа хранилища сначала масштабируйте реплики контейнера до 0 или удалите весь Statefulset.
  2. Удалите PVC
  3. Подключите nas к любому серверу, затем удалите соответствующий каталог nas pvc.

После обновления до v1.12.6-aliyun.1 выделяемая память узла уменьшилась

Эта версия резервирует 1Gi на узел, что эквивалентно тому, что весь кластер имеет на N GB меньше (N — количество узлов) для выделения Pod.

Если узел 4G, а Pod запрашивает 3G, его очень легко вытеснить.

Рекомендация: Увеличьте спецификации узла.

1
Server Version: version.Info{Major:"1", Minor:"12+", GitVersion:"v1.12.6-aliyun.1", GitCommit:"8cb561c", GitTreeState:"", BuildDate:"2019-04-22T11:34:20Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}

Новый узел показывает NetworkUnavailable

RouteController failed to create a route

Проверьте события kubernetes, чтобы увидеть, появляется ли это:

1
timed out waiting for the condition -> WaitCreate: ceate route for table vtb-wz9cpnsbt11hlelpoq2zh error, Aliyun API Error: RequestId: 7006BF4E-000B-4E12-89F2-F0149D6688E4 Status Code: 400 Code: QuotaExceeded Message: Route entry quota exceeded in this route table  

Эта проблема возникает из-за достижения лимита пользовательских записей маршрута VPC. По умолчанию 48. Нужно увеличить квоту для vpc_quota_route_entrys_num.

Доступ к LoadBalancer svc случайно показывает аномалии пересылки трафика

См. [bug] Версия kubernetes Alibaba Cloud не проверяет порт службы loadbalancer, вызывая аномальную пересылку трафика Проще говоря, один и тот же SLB не может иметь тот же порт svc, иначе он будет пересылать вслепую.

Официальное заявление:

Несколько служб, повторно использующих один и тот же SLB, не могут иметь один и тот же порт прослушивания на передней панели, иначе это вызовет конфликт портов.

Консоль показывает использование памяти узла всегда слишком высоким

Мониторинг памяти контейнера Docker

Причина в том, что их консоль использует usage_in_bytes (cache+buffer), поэтому она будет больше, чем числа, видимые в облачном мониторинге.

Мистическая оптимизация Ingress Controller

Измените configmap с именем nginx-configuration под kube-system

1
2
3
4
5
6
7
8
9
10
11
proxy-connect-timeout: "75" 
proxy-read-timeout: "75" 
proxy-send-timeout: "75" 
upstream-keepalive-connections: "300" 
upstream-keepalive-timeout: "300" 
upstream-keepalive-requests: "1000" 
keep-alive-requests: "1000" 
keep-alive: "300"
disable-access-log: "true" 
client-header-timeout: "75" 
worker-processes: "16"

Примечание: один элемент соответствует одной конфигурации, а не одному файлу. Формат примерно такой:

1
2
3
4
5
6
7
8
9
➜  ~ kg cm nginx-configuration -o yaml
apiVersion: v1
data:
  disable-access-log: "true"
  keep-alive: "300"
  keep-alive-requests: "1000"
  proxy-body-size: 20m
  worker-processes: "16"
  ......

проблема pid

1
Message: **Liveness probe failed: rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:262: starting container process caused "process_linux.go:86: adding pid 30968 to cgroups caused \"failed to write 30968 to cgroup.procs: write /sys/fs/cgroup/cpu,cpuacct/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podfe4cc065_cc58_11e9_bf64_00163e08cd06.slice/docker-0447a362d2cf4719ae2a4f5ad0f96f702aacf8ee38d1c73b445ce41bdaa8d24a.scope/cgroup.procs: invalid argument\""

Узлы инициализации Alibaba Cloud используют старую версию centos, ядро 3.1. Ядро 3.10 Centos7.4 еще не поддерживает ограничения cgroup для pid/fd, поэтому возникает этот тип проблемы.

Рекомендации:

  1. Вручную обслуживайте узлы, обновите до ядра 5.x (в настоящее время некоторые узлы были обновлены до 5.x, но версия docker все еще 17.6.2, продолжаю наблюдать~)
  2. Установите NPD + eventer, используйте механизм событий для предупреждения администраторов о ручном обслуживании

OSS PVC FailedMount

OSS можно использовать через PV, указывающий access key, access secret + PVC. Один день deploy столкнулся с проблемой FailedMount. Связался с инженерами разработки Alibaba Cloud, которые сказали, что flexvolume будет иметь проблемы при запуске на узлах, запускающихся впервые, нужно дать ему “перерегистрироваться”

Затронутая версия: registry-vpc.cn-shenzhen.aliyuncs.com/acs/flexvolume:v1.12.6.16-1f4c6cb-aliyun

Решение:

1
touch /usr/libexec/kubernetes/kubelet-plugins/volume/exec/alicloud~oss/debug

Ссылки (связанные с планированием приложений):

  1. Проверки работоспособности Kubernetes и обработка зависимостей служб
  2. Как kubernetes решает зависимости служб?
  3. Путь Kubernetes 1 - Заблуждения об ограничениях ресурсов приложения Java
  4. Управление политиками управления CPU на узле
  5. Резервирование вычислительных ресурсов для системных демонов
  6. Настройка обработки нехватки ресурсов