背景
今天发现好多pod的状态都是Evicted,然后我没有监控的权限,本来想看看grafana上监控图是否出现了特殊情况,无奈没权限看。
因为我发现pod出现大量的Evicted状态的时候,查看pod所在的node节点,距离当时发生Evicted的时间已经是7小时之久了。因此可能会存在一种原因:发生了Evicted的时候的确磁盘已经超过默认的kubelet的资源预留参数了。但是问题发生后,触发了阈值,已经回收了磁盘空间,导致我看的时候磁盘空间已经恢复。
在每个 Kubernetes Node节点 上,kubelet 默认根目录是 /var/lib/kubelet 和 日志目录 /var/log 保存在节点的系统分区上,这个分区同时也会被Pod的 EmptyDir 类型的 volume、容器日志、镜像层、容器的可写层所占用。ephemeral-storage 便是对系统分区进行管理。
大量的Evicted状态的pod
- $ kubectl get po -A -o wide | grep -v "Running"
- NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
- nsop account-service-pre-master-6db67f5cc-5nrgf 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
- nsop account-service-pre-master-6db67f5cc-7zbrf 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
- nsop account-service-pre-master-6db67f5cc-h78hv 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
- nsop account-service-pre-master-6db67f5cc-jj4xx 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
- nsop account-service-pre-master-6db67f5cc-jz4cs 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
- nsop account-service-pre-master-6db67f5cc-km2cz 0/1 Evicted 0 103m <none> node2.pre.ayunw.cn <none> <none>
当我们的集群中有太多被驱逐的 pod 时,这会导致网络负载。因为每个 pod 即使被驱逐是连接到网络的,并且在云 Kubernetes 集群的情况下,也会阻塞一个 IP 地址,这可能导致如果您的集群有固定的 IP 地址池,也会耗尽 IP 地址。此外,当我们有太多处于 Evicted 状态的 Pod 时,通过运行kubectl get pod命令来监控 Pod 会变得很困难,因为会存在非常多的 Evicted Pod。当然你可以通过grep等手段过滤掉Evicted状态的pod。
查看Evicted的pod的任意一个node
describe任意一个pod查看,发现Warning提示DiskPressure,表示磁盘存在压力了。
- $ kubectl describe po account-service-pre-master-6db67f5cc-5nrgf -n nsop
- ...
- QoS Class: Burstable
- Node-Selectors: <none>
- Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
- node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
- topology.kubernetes.io/env=pre:NoSchedule
- topology.kubernetes.io/region=bce-gz:NoSchedule
- topology.kubernetes.io/type=appserver:NoSchedule
- topology.kubernetes.io/zone:NoSchedule op=Exists
- Events:
- Type Reason Age From Message
- ---- ------ ---- ---- -------
- Normal Scheduled 100m default-scheduler Successfully assigned nsop/account-service-pre-master-6db67f5cc-5nrgf to node2.pre.ayunw.cn
- Warning Evicted 100m kubelet, node2.pre.ayunw.cn The node had condition: [DiskPressure].
登录node2.pre.ayunw.cn查看
- [root@node2-pre-ayunw.cn ~]# df -Th | egrep -v "overlay2|kubernetes|docker"
- Filesystem Type Size Used Avail Use% Mounted on
- devtmpfs devtmpfs 32G 0 32G 0% /dev
- tmpfs tmpfs 32G 0 32G 0% /dev/shm
- tmpfs tmpfs 32G 5.9M 32G 1% /run
- tmpfs tmpfs 32G 0 32G 0% /sys/fs/cgroup
- /dev/vda1 ext4 50G 7.9G 39G 17% /
- /dev/vdb1 xfs 200G 138G 63G 69% /data
- tmpfs tmpfs 6.3G 0 6.3G 0% /run/user/0
发现还有69%的磁盘空间,似乎也没有什么问题啊,应该磁盘空间也还很充足的。
iostat命令查看磁盘IO
- [root@node2-pre-ayunw.cn ~]# iostat -xk 1 3
- Linux 5.10.8-1.el8.elrepo.x86_64 (node2-pre-ayunw.cn) 08/31/2021 _x86_64_ (32 CPU)
- avg-cpu: %user %nice %system %iowait %steal %idle
- 1.86 0.00 1.77 0.03 0.00 96.34
- Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
- vda 0.02 2.77 0.40 22.43 0.00 2.14 4.57 43.58 1.51 0.75 0.00 24.11 8.09 0.38 0.11
- vdb 0.08 126.81 3.31 519.35 0.00 0.54 0.31 0.43 3.20 0.56 0.07 40.29 4.10 0.47 6.01
- avg-cpu: %user %nice %system %iowait %steal %idle
- 3.09 0.00 3.34 0.03 0.00 93.54
- Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
- vda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
- vdb 0.00 51.00 0.00 168.50 0.00 0.00 0.00 0.00 0.00 0.45 0.02 0.00 3.30 0.55 2.80
- avg-cpu: %user %nice %system %iowait %steal %idle
- 2.74 0.00 2.81 0.00 0.00 94.45
- Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
- vda 0.00 3.00 0.00 40.00 0.00 7.00 0.00 70.00 0.00 0.67 0.00 0.00 13.33 1.00 0.30
- vdb 0.00 62.00 0.00 619.50 0.00 7.00 0.00 10.14 0.00 0.58 0.04 0.00 9.99 0.50 3.10
目前似乎也看不到有什么IO压力 。但是由于我手上没有监控权限,估计也是直接就没有对pod做监控。然后describe的时候看到问题发生也是7个小时之前的事情了,所以的话这边猜测可能是当时已经触发了kubelet的eviction-hard,然后磁盘已经有部分空间被回收了,而且压力可能也已经下去了。
查看node上的日志
查看节点上kubelet日志和message日志,并没有任何Evicted的日志被发现。
- $ tail -500 kubelet.log | grep "Evicted"
- $ tail -500 /var/log/messages | grep "Evicted"
那当前情况下就只能临时先处理掉这个Evicted状态的pod了
- $ kubectl get po -n nsop --field-selector 'status.phase!=Running' -o json| kubectl delete -f -
因为是磁盘空间的问题,所以想到去检查一下是否有持续增长的目录。最后排查发现,所有出现Evicted状态的pod所处的节点似乎都有一个共性:那就是都启用了skywalking,并且以emptyDir的形式写日志到本地临时存储中。
目前公司将默认的docker目录和kubelet目录都改到了/data目录下,上pod所在的node,到/data/目录下通过du -sh ./* | grep G命令去查看了一下有好多/data/kubernetes/kubelet/pods/xxx/volumes/kubernetes.io~empty-dir/vol-apm-empty/logs的目录下存在skywalking-api.log的日志,而且都是轮转的日志,默认没有设置日志保留时间。
skywalking-agent的配置文件中默认开启了以下几个参数:
- $ egrep -v "^$|^#" agent.config
- agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
- collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
- logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
- logging.level=${SW_LOGGING_LEVEL:INFO}
- plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
skywalking-agent在emptyDir下的日志
- [root@node2-pre-ayunw.cn vol-apm-empty]# cd logs/
- [root@node2-pre-ayunw.cn logs]# ll
- total 4327672
- -rw-r--r-- 1 root root 260328481 Aug 31 09:43 skywalking-api.log
- -rw-r--r-- 1 root root 314573222 Aug 12 02:56 skywalking-api.log.2021_08_12_02_56_35
- -rw-r--r-- 1 root root 314573394 Aug 13 15:01 skywalking-api.log.2021_08_13_15_01_56
- -rw-r--r-- 1 root root 314574277 Aug 15 03:12 skywalking-api.log.2021_08_15_03_12_26
- -rw-r--r-- 1 root root 314574161 Aug 16 15:21 skywalking-api.log.2021_08_16_15_21_13
- -rw-r--r-- 1 root root 314574334 Aug 18 03:31 skywalking-api.log.2021_08_18_03_31_18
- -rw-r--r-- 1 root root 314572887 Aug 19 15:40 skywalking-api.log.2021_08_19_15_40_22
- -rw-r--r-- 1 root root 314574238 Aug 21 03:44 skywalking-api.log.2021_08_21_03_44_28
- -rw-r--r-- 1 root root 314574144 Aug 22 15:49 skywalking-api.log.2021_08_22_15_49_08
- -rw-r--r-- 1 root root 314573963 Aug 24 03:51 skywalking-api.log.2021_08_24_03_51_28
- -rw-r--r-- 1 root root 314572991 Aug 25 15:54 skywalking-api.log.2021_08_25_15_54_21
- -rw-r--r-- 1 root root 314573321 Aug 27 03:57 skywalking-api.log.2021_08_27_03_57_11
- -rw-r--r-- 1 root root 314572890 Aug 28 16:01 skywalking-api.log.2021_08_28_16_01_26
- -rw-r--r-- 1 root root 314573311 Aug 30 04:05 skywalking-api.log.2021_08_30_04_05_34
我的docker根目录被更改过,不是默认的/var/lib/docker,而是/data/docker。我的k8s的kubelet目录也是被更改过的,在/data/kubernetes/kubelet。
临时解决日志爆满的两种方法
- 在K8s-master节点查看Evicted的pod调度在哪个节点,然后到/data/kubernetes/kubelet/pods目录下去通过du -sh 命令找到目录占用量大的pod,然后将截图指出的轮转后(就是带上时间2021_08_17这一类)的日志文件删除
- 直接重新删除pod,其实只要是pod重启后,EmptyDir目录就会被删除掉。
操作步骤
- $ cd /data/kubernetes/kubelet/pods
- $ du -sh ./* | grep G
- 1.3G ./02c9511d-0787-49f1-8c59-0db239baee79
- 1.3G ./079f3ca0-810d-468d-9136-75f3d3235b2d
- 4.8G ./07fc67f7-d46d-4d0c-8f6c-401e14705ae1
- 3.0G ./091594a0-b5ac-45c2-8ad9-7dcfc91c9e55
- 1.8G ./130a1b35-b447-43e1-8802-eb74aefa566c
- 1.2G ./1b257c27-cbaf-49f8-bca3-ceadc467aad6
- 2.8G ./2ec50216-f81e-4e83-922d-14316762dee2
- 7.0G ./321baae6-1efe-4535-8a20-0fdfa6cc3117
- 8.0G ./46680114-11f7-47af-9ee2-347f56592924
- ...
我这里找到了占用7.0G大小的pod,根据目录名称找到pod名字,然后触发了这个pod的cicd,也就相当于更新了这个pod的deployment.yaml,然后apply -f重新生成了一遍这个pod
- $ docker ps -a | grep "321baae6-1efe-4535-8a20-0fdfa6cc3117"
- a69b2635ba98 registry.ayunw.cn/tsp/msmessagecenter "/startApp.sh" 5 weeks ago Up 5 weeks k8s_msmessagecenter-perf-dev-v1-0-0_msmessagecenter-perf-dev-v1-0-0-7f746b84bf-wb4g5_tsp_321baae6-1efe-4535-8a20-0fdfa6cc3117_0
- c8f2cc0a2737 874552b27b34 "sh -c 'set -ex;mkdi…" 5 weeks ago Exited (0) 5 weeks ago k8s_init-skywalking-agent_msmessagecenter-perf-dev-v1-0-0-7f746b84bf-wb4g5_tsp_321baae6-1efe-4535-8a20-0fdfa6cc3117_0
- c415f52e7489 registry.ayunw.cn/library/k8s.gcr.io/pause:3.2 "/pause" 5 weeks ago Up 5 weeks k8s_POD_msmessagecenter-perf-dev-v1-0-0-7f746b84bf-wb4g5_tsp_321baae6-1efe-4535-8a20-0fdfa6cc3117_0
等pod被完全删除后查看这个目录已经消失
- $ du -sh ./* | grep G
- 1.3G ./02c9511d-0787-49f1-8c59-0db239baee79
- 1.3G ./079f3ca0-810d-468d-9136-75f3d3235b2d
- 4.8G ./07fc67f7-d46d-4d0c-8f6c-401e14705ae1
- 3.0G ./091594a0-b5ac-45c2-8ad9-7dcfc91c9e55
- 1.8G ./130a1b35-b447-43e1-8802-eb74aefa566c
- 1.2G ./1b257c27-cbaf-49f8-bca3-ceadc467aad6
- 2.8G ./2ec50216-f81e-4e83-922d-14316762dee2
- 8.0G ./46680114-11f7-47af-9ee2-347f56592924
- ...
永久解决日志保留个数方法
- 直接在Dockerfile打镜像的时候更改参数或者提前写好配置文件然后构建镜像的时候COPY进去
我这里直接改好agent.config参数然后Dockerfile中COPY进去了
- $ cat Dockerfile
- FROM registry.ayunw.cn/library/alpine:3.12.0
- ENV LANG=C.UTF-8 \
- SKYWLKING_AGENT_VERSION=8.6.0
- RUN set -eux && mkdir -p /opt/skywalking/agent \
- && apk add wget \
- && wget https://downloads.apache.org/skywalking/${SKYWLKING_AGENT_VERSION}/apache-skywalking-apm-es7-${SKYWLKING_AGENT_VERSION}.tar.gz -P /tmp/ \
- && cd /tmp && tar zxf apache-skywalking-apm-es7-${SKYWLKING_AGENT_VERSION}.tar.gz \
- && mv /tmp/apache-skywalking-apm-bin-es7/agent/* /opt/skywalking/agent \
- && rm -f /opt/skywalking/agent/optional-plugins/apm-spring-annotation-plugin-8.6.0.jar /opt/skywalking/agent/plugins/thrift-plugin-8.6.0.jar \
- && mv /opt/skywalking/agent/plugins/thrift-plugin-8.6.0.jar /tmp/thrift-plugin-8.6.0.jar \
- && cp -r /opt/skywalking/agent/optional-plugins/* /opt/skywalking/agent/plugins/ \
- && unset export \
- && rm -rf /tmp/* /opt/skywalking/agent/config/agent.config
- COPY agent.config /opt/skywalking/agent/config/
- WORKDIR /
- $ egrep -v "^$|^#" agent.config
- agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
- collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
- logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log}
- logging.level=${SW_LOGGING_LEVEL:INFO}
- plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
- # 以下参数是我更改后的,表示日志保留个数为3个
- logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:3}
其实agent.config文件中是有logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:-1}这一行的,但是默认被注释掉了。我这里将它打开,然后将-1改成了3。这行配置是JAVA中的写法,意思是默认是-1表示"最大历史日志文件保留个数",而-1则表示不设置最大历史日志文件保留,也就是一直轮转,不会做日志清理。参数意思可以参考skywalking官网。
然后重新构建这个skywalking-agent镜像,在deployment中引用即可。
- $ cat deployment.yaml
- apiVersion: apps/v1
- kind: Deployment
- ...
- dnsPolicy: ClusterFirst
- terminationGracePeriodSeconds: 10
- serviceAccountName: default
- imagePullSecrets:
- - name: registry-auth-ayunw-cn
- initContainers:
- - name: init-skywalking-agent
- image: "registry.ayunw.cn/library/skywalking-agent:33-ac402d20"
- command:
- - 'sh'
- - '-c'
- - 'set -ex;mkdir -p /skywalking/agent;cp -r /opt/skywalking/agent/* /skywalking/agent;'
- volumeMounts:
- - name: vol-apm-empty
- mountPath: /skywalking/agent
- containers:
- - name: demo-hello-pre-master
- image: "registry.ayunw.cn/paas/demo-hello:537-c87b6177"
- ...
- volumeMounts:
- - name: vol-apm-empty
- mountPath: /skywalking/agent
- volumes:
- - name: vol-apm-empty
- emptyDir: {}
其实这里的磁盘DiskPressure目前只能大概排查到skywalking导致,但没有监控的情况下并不能百分百确认就是skywalking引起,因此如果需要更精准的定位这个问题,还需要通过监控等手段去排查。如果各位有更好的解决Evicted状态的pod这种问题的方法,也欢迎后台回复,一起交流。
本文转载自微信公众号「运维开发故事」
【编辑推荐】