当容器终止时,容器引擎使用退出码来报告容器终止的原因。如果是 Kubernetes 用户,容器故障是 pod 异常最常见的原因之一,了解常见的容器退出码可以帮助在排查时更快捷找到 pod异常的根本原因。可以参考https://komodor.com/learn/exit-codes-in-containers-and-kubernetes-the-complete-guide/
下面是容器常见的退出码:
退出码 | 名称 | 大致含义 |
---|---|---|
0 | 正常退出 | 正常退出 |
1 | 应用错误 | 容器因代码程序错误或镜像规范中的错误引用停止 |
125 | 容器未能运行 | docker run 命令没有执行成功 |
126 | 命令调用错误 | 无法调用镜像中指定的命令 |
127 | 找不到文件或目录 | 指定命令引用了不存在的文件或目录 |
128 | 退出时使用的参数无效 | 退出是用无效的退出码触发的(有效代码是 0-255 之间的整数) |
134 | 异常终止 (SIGABRT) | 容器使用 abort() 函数自行中止 |
137 | 立即终止 (SIGKILL) | 容器被操作系统通过 SIGKILL 信号终止 |
139 | 分段错误 (SIGSEGV) | 容器试图访问未分配给它的内存并被终止 |
143 | 优雅终止 (SIGTERM) | 容器收到即将终止的警告,然后终止 |
255 | 退出状态 | 超出范围容器退出,返回可接受范围之外的退出代码,表示错误原因未知 |
说明:在使用kubernetes时,我们其实不需要记住具体的代码含义,很多时候,我们通过describe中event中的提示信息就能知道容器异常的原因。
下面我们将解释如何在宿主机和 Kubernetes 中对失败的容器进行故障排除,并提供有关上面列出的所有退出代码的更多详细信息。容器生命周期
为了更好地理解容器故障的原因,让我们先要了解容器的生命周期。以 Docker 为例 ,Docker 容器可能会处于以下几种状态之一:
当一个容器达到 Exited 状态时,Docker 会在日志中报告一个退出码,告诉你容器发生了什么导致它退出。
下面我们将详细说明每个退出码。
退出码 0:正常退出
退出代码 0 由开发人员在任务完成后故意停止容器时触发。从技术上讲,退出代码 0 意味着前台进程未附加到特定容器。如果容器以退出码 0 终止怎么办?
退出码 1:应用错误
退出代码 1 表示容器由于以下原因之一停止:
如果容器以退出码 1 终止怎么办?
退出码 125:容器未能运行
退出码 125 表示该命令用于运行容器。例如 docker run 在 shell 中被调用但没有成功执行。以下是可能发生这种情况的常见原因:
退出码 126:命令调用错误
退出码 126 表示无法调用容器镜像中使用的命令。这通常是用于运行容器的持续集成脚本中缺少依赖项或错误的原因。如果容器以退出码 126 终止怎么办?
退出码 127:找不到文件或目录
退出码 127 表示容器中指定的命令引用了不存在的文件或目录。如果容器以退出码 127 终止怎么办?
与退出码 126 相同,识别失败的命令,并确保容器镜像中引用的文件名或文件路径真实有效。退出码
128:退出时使用的参数无效
退出码 128 表示容器 内的代码触发了退出命令,但没有提供有效的退出码。 Linux exit 命令只允许 0-255 之间的整数,因此如果进程以退出码 3.5 (小数)退出,则日志将报告退出代码 128。如果容器以退出码 128 终止怎么办?
退出码 134:异常终止 (SIGABRT)
退出码 134 表示容器自身异常终止,关闭进程并刷新打开的流。此操作是不可逆的,类似 SIGKILL(请参阅下面的退出码 137)。进程可以通过执行以下操作之一来触发 SIGABRT:
1.调用libc 库中的abort() 函数;
2.调用assert() 宏,用于调试。如果断言为假,则该过程中止。
如果容器以退出码 134 终止怎么办?
1.检查容器日志,查看哪个库触发了SIGABRT 信号;
2. 检查中止进程是否是预期内的(例如,因为库处于调试模式),如果不是,则对库进行故障排除,并修改以避免中止容器。
退出码 137:立即终止 (SIGKILL)
退出码 137 表示容器已收到来自主机操作系统的 SIGKILL 信号。该信号指示进程立即终止,没有宽限期。可能的原因是:
1.当通过容器引擎杀死容器时触发,例如使用docker kill 命令时;
2.由 Linux 用户向进程发送kill -9 命令触发;
3.在尝试终止容器并等待 30 秒的宽限期后由 Kubernetes 触发(默认情况下);
4.由主机自动触发,通常是由于内存不足。在这种情况下,docker inspect 命令将指示OOMKilled 错误。
如果容器以退出码 137 终止怎么办?
退出码 139:分段错误 (SIGSEGV)
退出码 139 表示容器收到了来自操作系统的 SIGSEGV 信号。这表示分段错误 —— 内存违规,由容器试图访问它无权访问的内存位置引起。SIGSEGV 错误有三个常见原因:
1.编码错误:容器进程没有正确初始化,或者它试图通过指向先前释放的内存的指针来访问内存
2.二进制文件和库之间不兼容:容器进程运行的二进制文件与共享库不兼容,因此可能会尝试访问不适当的内存地址
3.硬件不兼容或配置错误:如果您在多个库中看到多个分段错误,则主机上的内存子系统可能存在问题或系统配置问题
如果容器以退出码 139 终止怎么办?
退出码 143:优雅终止 (SIGTERM)
退出码 143 表示容器收到来自操作系统的 SIGTERM 信号,该信号要求容器正常终止,并且容器成功正常终止(否则您将看到退出码 137)。该退出码可能的原因是:
1.容器引擎停止容器时触发,例如使用docker stop 或docker-compose down 命令时;
2.由 Kubernetes 将 Pod 设置为 Terminating 状态触发,并给容器 30 秒的时间以正常关闭。
如果容器以退出码 143 终止怎么办?
1.检查主机日志,查看操作系统发送 SIGTERM 信号的上下文。如果您使用的是 Kubernetes,请检查 kubelet 日志,查看 pod 是否以及何时关闭。一般来说,退出码 143 不需要故障排除。这意味着容器在主机指示后正确关闭。
退出码 255:退出状态超出范围
当您看到退出码 255 时,意味着容器的 entrypoint 以该状态停止。这意味着容器停止了,但不知道是什么原因。如果容器以退出码 255 终止怎么办?
哪些 Kubernetes 错误与容器退出代码有关?
每当 pod 中容器发生故障,或者 Kubernetes 指示 pod 出于任何原因终止时,容器将关闭并记录退出代码。识别退出代码可以帮助您了解 pod 异常的根本原因。
可以使用以下命令查看 pod 错误:kubectl describe pod
如下所示:
[root@k8s-m1 k8s-volumes]# kubectl describe pod -n metallb-system speaker-76lcc
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Mon, 24 Jul 2023 15:44:08 +0800
Finished: Mon, 24 Jul 2023 15:44:08 +0800
Ready: False
Restart Count: 7876
Environment:
METALLB_NODE_NAME: (v1:spec.nodeName)
METALLB_HOST: (v1:status.hostIP)
METALLB_ML_BIND_ADDR: (v1:status.podIP)
METALLB_ML_LABELS: app=metallb,component=speaker
METALLB_ML_SECRET_KEY: <set to the key 'secretkey' in secret 'memberlist'> Optional: false
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from speaker-token-z5mww (ro)
使用kubectl提供的退出代码解决问题:
如果退出代码为 0:容器正常退出,无需排查
如果退出代码在 1-128 之间:容器因内部错误而终止,例如镜像规范中缺少或无效的命令
如果退出代码在 129-255 之间:容器因操作信号而停止,例如 SIGKILL 或 SIGINT
如果退出代码是exit(-1)或 0-255 范围之外的另一个值,kubectl将其转换为 0-255 范围内的值。
如上,Exit Code为1 ,大致推断为程序内部错误。可以结合kubectl logs
进行排查
[root@k8s-m1 k8s-volumes]# kubectl logs -n metallb-system speaker-76lcc
{"branch":"HEAD","caller":"level.go:63","commit":"v0.11.0","goversion":"gc / go1.16.9 / amd64","level":"info","msg":"MetalLB speaker starting version 0.11.0 (commit v0.11.0, branch HEAD)","ts":"2023-07-24T07:49:13.848664833Z","version":"0.11.0"}
{"caller":"level.go:63","error":"Could not set up network transport: failed to obtain an address: Failed to start UDP listener on \"192.168.2.142\" port 7946: listen udp 192.168.2.142:7946: bind: address already in use","level":"error","msg":"failed to create memberlist","op":"startup","ts":"2023-07-24T07:49:13.84936419Z"}
发现是由于端口冲突造成。解决了端口冲突即可解决问题。
更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出