应用程序并不总是在稳定状态下运行。会根据日期、时间或特定事件而波动。CPU 需求各不相同,运行时内存和网络需求也各不相同。而应用程序不断变化的需求,由Kubernetes来调度程序分配计算或内存资源,这些可能会导致Kubernetes上的node或者pod处于不可用状态的原因之一,而这些pod最终是关联到应用程序上,只有将这些资源被分配给其他应用程序或暂停,直到一切结束。
这种重新分配可能有意或意外地发生。突然的性能波动可能导致集群内的节点故障——或其他由pod 驱逐、内核恐慌,内存溢出,或 VM 意外停机引起的中断。
OOMKilled
OOMKilled是为了保证vm的健康状态,在后台,OOM Killer 为每个正在运行的进程分配一个分数。分数越高,进程被杀死的可能性就越大, Kubernetes 会利用该分数来帮助决定要杀死哪些 pod。
VM 上运行的 kubelet 监控内存消耗。如果 VM 上的资源变得稀缺,kubelet 将开始杀死 pod。从本质上讲,这个想法是为了保持 VM 的健康状况,以便在其上运行的所有 pod 都不会失败。多数的需求超过了少数的需求,少数被干掉。两种方式
- OOMKilled:限制过度使用
- OOMKilled:已达到容器限制
限制过度使用
当pod 限制的总和大于节点上的可用内存时,可能会发生OOMKilled: Limit Overcommit错误。例如,如果有一个具有 8 GB 可用内存的节点,可能会得到 8 个 pod,每个 pod 都需要 1 gig 内存。但是,即使其中一个 Pod 配置了 1.5 gigs 的限制,也会面临内存不足的风险。只需要一个 pod 出现流量峰值或未知的内存泄漏,Kubernetes 将被迫开始杀死 pod。
达到容器限制
虽然Limit Overcommit错误与节点上的内存总量有关,但Container Limit Reached通常归结为单个 pod。当 Kubernetes 检测到一个 pod 使用的内存超过了设置的限制时,它会杀死该 pod,并显示错误OOMKilled—Container Limit Reached。
发生这种情况时,检查应用程序日志以尝试了解 pod 使用的内存超过设置限制的原因。可能有多种原因,例如流量激增或长时间运行的Kubernetes 作业导致它使用比平时更多的内存。
如果在期间发现应用程序按预期运行并且它只需要更多内存来运行,可能会考虑增加 request 和 limit 的值。
有效应对这些事件至关重要。但是,了解特定应用程序如何以及为何表现出此类行为同样重要。K8s 事件对象可以帮助提供一些上下文,但是默认的手段能到的东西有限
事件
事件在Kubernetes框架中是一个对象,它会自动生成以响应其他资源(如节点、Pod 或容器)的变化
状态变化是最关键的部分。例如,pod 生命周期中的各个阶段——比如从pending到running的转换,或者成功或失败,或重启等状态可能会触发 K8s 事件。正如之前提到的,重新分配和调度也是如此。
事件实际上是 K8s 领域的。它们可以深入了解基础架构的运行方式,同时为任何令人不安的行为提供信息。但是Kubernetes 中的事件日志记录并不完美。
由于事件对象不被视为常规日志,因此默认情况下它们不包含在Kubernetes 日志中。此外,事件可能不会按预期显示以响应某些行为,例如由错误镜像引起的容器启动失败(例如[ImagePullBackoff)。我们可能希望某个事件在某些资源(ReplicaSet、StatefulSet等)上可见,但它们在 pod 本身上却是模糊可见的。因此,管理员需要执行调试时手动提取
事件分类
Kubernetes 部署中可能有多种类型的事件。当 Kubernetes 执行核心操作时,可能会出现许多状态转换
Failed Events
容器创建失败非常常见,因此创建失败或者更新的失败会因为很多原因导致,如镜像名称错误,权限等都会导致失败
此外,节点本身可能会失败。当这些故障发生时,应用程序应该回退到正常的剩余节点
Evicted Events
驱逐事件相当普遍,因为 Kubernetes 可以在工作节点终止其各种 pod。某些 pod 可能会占用计算和内存资源,或者相对于它们各自的运行时消耗不成比例的数量。Kubernetes 通过驱逐 pod 并在别处分配磁盘、内存或 CPU 空间来解决这个问题。
这并不总是一个问题,如果未能对他们的 pod 设置适当的限制,因此未能在容器级别限制资源消耗。如果没有定义的请求或限制参数,资源很可能会失控。
被驱逐的事件可以揭示这些次优配置,当数百个容器同时运行时,这些配置很容易在一次新的洗牌中丢失。驱逐事件还可以告诉我们pod 何时被分配到新节点。
Kubernetes Scheduling Events
称为FailedScheduling事件,当 Kubernetes 调度程序无法找到合适的节点时发生。这个事件的介绍非常具有描述性。记录的消息准确地解释了为什么新节点没有获得必要的资源。内存或 CPU 不足也会触发此事件。
Node-Specific Events
节点上的事件可能指向系统内某处的不稳定或不健康行为。首先,NodeNotReady事件表示没有准备好进行 pod 调度的节点。相反,健康节点将被描述为“就绪”,而“unknown”节点无法轮询状态和响应。
同时,Rebooted事件的含义很简单。由于特定操作或不可预见的崩溃,可能必须重新启动节点。
最后,当集群无法访问时会触发HostPortConflict事件。这可能意味着选择的 nodePort 不正确。此外,DaemonSets可能与 hostPorts 冲突并导致此问题。
过滤和监控事件
Kubernetes 事件并非所有事件都是关键任务。就像确认消息一样,其中许多可以简单地应用于按设计或预期运行的系统。K8s 将这些表示为Normal。
因此,所有事件都被分配了一个类型——Normal, Information, Warning。对于典型的集群,正常事件是无聊且不那么有用的;在故障排除过程中,它们不会透露任何内在价值。还为事件分配了一个简短的原因(触发此事件的原因)、一个Age、一个From(或起源)和一个提供更多上下文的Message 。这些本质上是与所有事件相关的“属性”或字段。它们还提供了一种从更大的集合中过滤某些事件的方法。
过滤非常简单。在kubectl中,可以输入以下内容以过滤掉正常事件,--field-selector type!=Normal
# kubectl -n preh5 get events --field-selector type!=Normal
LAST SEEN TYPE REASON OBJECT MESSAGE
14m Warning Failed pod/gv-service-857fc678f8-wwtpv Error: ImagePullBackOff
也可以根据最新的时间选项来匹配--sort-by='.lastTimestamp'
# kubectl -n preh5 get events --field-selector type!=Normal --sort-by='.lastTimestamp'
LAST SEEN TYPE REASON OBJECT MESSAGE
8m33s Warning Failed pod/gv-service-857fc678f8-wwtpv Error: ImagePullBackOff
使用-o json
查看json格式的信息
# kubectl -n pre-veh5 get events --field-selector type!=Normal --sort-by='.lastTimestamp' -o json
{
"apiVersion": "v1",
"items": [
{
"apiVersion": "v1",
"count": 1150,
"eventTime": null,
"firstTimestamp": "2022-03-16T03:18:45Z",
"involvedObject": {
"apiVersion": "v1",
"fieldPath": "spec.containers{gis-vehicle-service}",
...
"resourceVersion": "",
"selfLink": ""
}
}
同时可以使用kubectl get events --watch
开持续观察日志
由于使用的是kubectl,因此可以从 Kubernetes 组件日志或集成的第三方日志工具中提取这些事件。后者很常见,因为 K8s 事件通常不存储在默认的 Kubernetes 日志中
可观测Sloop
Sloop 监控 Kubernetes,记录事件和资源状态变化的历史,并提供可视化来帮助调试过去的事件。
主要特征:
我们安装sloop,通过docker run起来
docker run --rm -it -p 28080:8080 -v ~/.kube/:/kube/ -v /etc/localtime:/etc/localtime -e KUBECONFIG=/kube/config sloopimage/sloop:latest
docker-compose
version: '2.2'
services:
sloopimage:
image: sloopimage/sloop:latest
container_name: sloopimage
restart: always
hostname: "sloopimage"
#network_mode: "host"
environment:
- KUBECONFIG=/kube/config
volumes:
- /root/.kube/:/kube/
- /etc/localtime:/etc/localtime
- /data:/some_path_on_host
mem_limit: 2048m
ports:
- 28080:8080
kube-eventer
kube-eventer是阿里云的开源项目,他可以捕捉一些事件,配合钉钉发送报警, 但是他的频率非常高
类似这样
TestPlan
Level:Warning
Kind:Pod
Namespace:test-test
Name:vecial-96b6765cf-6zst5.16d65799bf506486
Reason:BackOff
Timestamp:2022-03-16 15:42:14
Message:Back-off restarting failed container
参考
https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/在 Linux OOM Killer 中幸存