【JVM故障问题排查心得】「内存诊断系列」Docker容器经常被kill掉,k8s中该节点的pod也被驱赶,怎么分析?

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【JVM故障问题排查心得】「内存诊断系列」Docker容器经常被kill掉,k8s中该节点的pod也被驱赶,怎么分析?

背景介绍


最近的docker容器经常被kill掉,k8s中该节点的pod也被驱赶。


我有一个在主机中运行的Docker容器(也有在同一主机中运行的其他容器)。该Docker容器中的应用程序将会计算数据和流式处理,这可能会消耗大量内存。


该容器会不时退出。我怀疑这是由于内存不足,但不是很确定。我需要找到根本原因的方法。那么有什么方法可以知道这个集装箱的死亡发生了什么?




容器层级判断检测


提到docker logs containerid查看该应用程序的输出。这永远是我要检查的第一件事。接下来,您可以运行dockerinspectcontainer_id查看该应用程序的输出。这永远是我要检查的第一件事。接下来,您可以运行docker inspect containeriddockerinspectcontainer_id以查看状态的详细信息,例如:


"State": {
        "Status": "exited",
        "Running": false,
        "Paused": false,
        "Restarting": false,
        "OOMKilled": false,
        "Dead": false,
        "Pid": 0,
        "ExitCode": 2,
        "Error": "",
        "StartedAt": "2016-06-28T21:26:53.477229071Z",
        "FinishedAt": "2016-06-28T21:26:53.478066987Z"
    }
复制代码

重要的一行是“ OOMKilled”,如果您超出了容器的内存限制,并且Docker杀死了您的应用程序,则该行将为true。您可能还需要查找退出代码,以查看其是否标识出您的应用退出的原因。


  • Docker内部,这仅表示docker本身是否会杀死您的进程,并要求您在容器上设置内存限制。


  • Docker外部,如果主机本身内存不足,Linux内核可以销毁进程。发生这种情况时,Linux通常会在/ var / log中写入日志。使用Windows和Mac上的Docker Desktop,您可以在docker设置中调整分配给嵌入式Linux VM的内存。


  • 可以通过阅读日志来了解容器内的进程是否被OOM杀死。OOMkill是由内核启动的,因此每次发生时,都会在中包含很多行/var/log/kern.log,例如:


python invoked oom-killer: gfp_mask=0x14000c0(GFP_KERNEL), nodemask=(null), order=0, oom_score_adj=995
oom_kill_process+0x22e/0x450
Memory cgroup out of memory: Kill process 31204 (python) score 1994 or sacrifice child
Killed process 31204 (python) total-vm:7350860kB, anon-rss:4182920kB, file-rss:2356kB, shmem-rss:0kB
复制代码




Linux操作系统的进程服务发生被killed的原因是什么


在Linux中,经常会遇到一些重要的进程无缘无故就被killed,而大多数的经验之谈就是系统资源不足或内存不足所导致的。


当Linux系统资源不足时,Linux内核可以决定终止一个或多个进程,内存不足时会在系统的物理内存耗尽时触发OOM killed,可以利用“dmesg | tail -N”命令来查看killed的近N行日志。

image.png




常规的宕机监控之类


在服务宕机或者重启之前我们的常规操作就是采用ps指令判定服务的增长趋势以及展示真实使用的资源的大小的前几位排名。


  • Linux下显示系统进程的命令ps,最常用的有ps -ef 和ps aux。这两个到底有什么区别呢?


ps -ef指令代表着'SystemV风格',而ps aux代表着’BSD风格‘。

image.png

由上图所示,可以分析出对应的数据结构模型。


USER      //用户名
%CPU      //进程占用的CPU百分比
%MEM      //占用内存的百分比
VSZ       //该进程使用的虚拟內存量(KB)
RSS       //该进程占用的固定內存量(KB)resident set size
STAT      //进程的状态
START     //该进程被触发启动时间
TIME      //该进程实际使用CPU运行的时间
复制代码

其中CPU算是第3个位置、内存MEM算是第4个位置,虚拟内存VSZ是第5个位置,记住这个后面我们会使用这个方式进行排序。




查看当前系统内CPU占用最多的前10个进程(栏位属于第3个)

ps auxw | sort -rn -k3 | head -10
复制代码

image.png

ps auxw指令(BSD风格)


  • u:以用户为主的格式来显示程序状况
  • x:显示所有程序,不以终端机来区分
  • w:采用宽阔的格式来显示程序状况



sort排序指令

sort -rn -k5
复制代码

-n是按照数字大小排序(-n 这代表着排除n行的操作处理),-r是以相反顺序,-k是指定需要排序的栏位


ps auxw | head -1
复制代码



内存消耗最多的前10个进程(栏位属于第4个)

ps auxw | head -1;ps auxw|sort -rn -k4|head -10
复制代码



虚拟内存使用最多的前10个进程(栏位属于第5个)

ps auxw|head -1;ps auxw|sort -rn -k5|head -10
复制代码



去掉x参数的结果

ps auw | head -1; ps auw|sort -rn -k4 | head -10
复制代码



stat取值含义

image.png

D      //无法中断的休眠状态(通常 IO 的进程);
R      //正在运行可中在队列中可过行的;
S      //处于休眠状态;
T      //停止或被追踪;
W      //进入内存交换 (从内核2.6开始无效);
X      //死掉的进程 (基本很少见);
Z      //僵尸进程;
<      //优先级高的进程
N      //优先级较低的进程
L      //有些页被锁进内存;
s      //进程的领导者(在它之下有子进程);
l      //多线程,克隆线程(使用 CLONE_THREAD, 类似 NPTL pthreads);
+      //位于后台的进程组;
复制代码




dmesg的命令分析


有几个工具/脚本/命令 可以更轻松地从该虚拟设备读取数据,其中最常见的是 dmesg 和 journalctl。

输入dmesg指令进行egrep正则表达式匹配killed的进程信息,将输出对应的进程信息。

dmesg | egrep -i -B100 'killed process'
复制代码


dmesg | grep -i -B100 'killed process'
复制代码

以上的指令就可以输出最近killed的信息,其中-B100,表示 'killed process’之前的100行内容,与head的指令非常的相似。

image.png

如果我们看到了oom-kill的字样之后,就可以判断它是被内存不足所导致的kill,oom-kill之后,就是描述那个被killed的程序的pid和uid。


Out of memory: Killed process 1138439 (python3) total-vm:8117956kB, anon-rss:5649844kB,内存不够
复制代码
total_vm和rss的指标值

image.png


  • total_vm:总共使用的虚拟内存 Virtual memory use (in 4 kB pages),8117956/1024(得到MB)/1024(得到GB)=7.741GB


  • rss:常驻内存使用Resident memory use (in 4 kB pages) 5649844/1024/1024=5.388GB



案例1:查看到pod被驱赶的原因
[3899860.525793] Out of memory: Kill process 64058 (nvidia-device-p) score 999 or sacrifice child
[3899860.526961] Killed process 64058 (nvidia-device-p) total-vm:126548kB, anon-rss:2080kB, file-rss:0kB, shmem-rss:0kB
复制代码


案例2:查看到docker容器被kill 的原因
[3899859.737598] Out of memory: Kill process 27562 (jupyter-noteboo) score 1000 or sacrifice child
[3899859.738640] Killed process 27562 (jupyter-noteboo) total-vm:215864kB, anon-rss:45928kB, file-rss:0kB, shmem-rss:0kB
复制代码




journalctl命令 – 查看指定的日志信息


当内存不足时,内核会将相关信息记录到内核日志缓冲区中,该缓冲区可通过 /dev/kmsg 获得。除了上面的dmesg之外,还有一个journalctl。


语法格式: journalctl [参数]


常用参数:

image.png

查看Killed日志


使用sudo dmesg | tail -7命令(任意目录下,不需要进入log目录,这应该是最简单的一种)而journalctl命令来自于英文词组“journal control”的缩写,其功能是用于查看指定的日志信息。



journalctl指令介绍


在RHEL7/CentOS7及以后版本的Linux系统中,Systemd服务统一管理了所有服务的启动日志,带来的好处就是可以只用journalctl一个命令,查看到全部的日志信息了。


查看所有日志(默认情况下 ,只保存本次启动的日志)
journalctl
复制代码


查看内核日志(不显示应用日志)
journalctl -k
复制代码


查看系统本次启动的日志
journalctl -b
journalctl -b -0
复制代码


查看上一次启动的日志(需更改设置)
journalctl -b -1
复制代码


查看指定时间的日志
journalctl --since=“2021-09-16 14:22:02”
journalctl --since “30 min ago”
journalctl --since yesterday
journalctl --since “2021-01-01” --until “2021-09-16 13:40”
journalctl --since 07:30 --until “2 hour ago”
复制代码


显示尾部的最新10行日志
journalctl -n
复制代码


显示尾部指定行数的日志
journalctl -n 15
复制代码


实时滚动显示最新日志
journalctl -f
复制代码


查看指定服务的日志
journalctl /usr/lib/systemd/systemd
复制代码


比如查看docker服务的日志
systemctl status docker
复制代码


查看某个 Unit 的日志
journalctl -u nginx.service
journalctl -u nginx.service --since today
复制代码


实时滚动显示某个 Unit 的最新日志
journalctl -u nginx.service -f
复制代码


合并显示多个 Unit 的日志
$ journalctl -u nginx.service -u php-fpm.service --since today




相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
3月前
|
Kubernetes API 网络安全
当node节点kubectl 命令无法连接到 Kubernetes API 服务器
当Node节点上的 `kubectl`无法连接到Kubernetes API服务器时,可以通过以上步骤逐步排查和解决问题。首先确保网络连接正常,验证 `kubeconfig`文件配置正确,检查API服务器和Node节点的状态,最后排除防火墙或网络策略的干扰,并通过重启服务恢复正常连接。通过这些措施,可以有效解决与Kubernetes API服务器通信的常见问题,从而保障集群的正常运行。
249 17
|
8月前
|
Kubernetes API 调度
k8s中节点无法启动Pod
【10月更文挑战第3天】
287 6
|
3月前
|
Kubernetes Shell Windows
【Azure K8S | AKS】在AKS的节点中抓取目标POD的网络包方法分享
在AKS中遇到复杂网络问题时,可通过以下步骤进入特定POD抓取网络包进行分析:1. 使用`kubectl get pods`确认Pod所在Node;2. 通过`kubectl node-shell`登录Node;3. 使用`crictl ps`找到Pod的Container ID;4. 获取PID并使用`nsenter`进入Pod的网络空间;5. 在`/var/tmp`目录下使用`tcpdump`抓包。完成后按Ctrl+C停止抓包。
125 12
|
4月前
|
Arthas 监控 Java
记一次内存利用率问题排查
记一次内存利用率问题排查
|
10月前
|
存储 Kubernetes Docker
Kubernetes节点资源耗尽状态的处理
Kubernetes节点资源耗尽状态的处理
|
9月前
|
监控 Java Linux
redisson内存泄漏问题排查
【9月更文挑战第22天】在排查 Redisson 内存泄漏问题时,首先需确认内存泄漏的存在,使用专业工具(如 JProfiler)分析内存使用情况,检查对象实例数量及引用关系。其次,检查 Redisson 使用方式,确保正确释放资源、避免长时间持有引用、检查订阅和监听器。此外,还需检查应用程序其他部分是否存在内存泄漏源或循环引用等问题,并考虑更新 Redisson 到最新版本以修复潜在问题。
286 5
|
8月前
|
Kubernetes 应用服务中间件 Linux
多Master节点的k8s集群部署
多Master节点的k8s集群部署
|
10月前
|
Kubernetes Unix Linux
k8s将节点容器运行时从Docker迁移到Containerd
k8s将节点容器运行时从Docker迁移到Containerd
|
1月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
214 55
|
2月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
125 6

相关产品

  • 容器服务Kubernetes版