前端也要懂点k8s-下篇

2,303 阅读12分钟

前言

通过上篇的学习,我们清楚了k8s中新手容易混淆的几个概念:

  • 比如说k8s和docker的关系,通俗的讲就是docker负责造车,k8s负责让车队有序行驶;
  • 又比如说Node和Pod的关系,Node相当于宿舍楼, Pod是宿舍楼中的某一间房子;
  • 又比如说Ingress和Service的区别,Ingress的作用对象是Service,Service的作用对象是Pod, Service的用途是暴露服务,Ingress的用途是路由和反向代理;
  • 再比如说Pod, Deployment,Service, Ingress之间的关系,Deployment创建并管理多个副本的 Pod,Service通过标签选择器连接这些 Pod,提供统一访问入口,Ingress定义基于域名和路径的访问规则,将外部请求路由到 Service,外部用户通过浏览器访问 http://example.com/app → 被 Ingress Controller 接收 → 匹配到路径 /app → 转发到对应的 Service → Service 将流量负载均衡转发给 Deployment 管理的 Pod。

现在我们继续学习K8s常见的日志查看与排查故障操作。

五 日志查看与排查故障

在 Kubernetes 中进行日志查看和故障排查是日常运维中最重要的技能之一。排查故障的常规思路是: 问题表现 ==> 查找 Pod ==> 查看状态/事件 ==> 查看日志 ==> 查看服务连接 ==> 查看资源使用 ==> 进一步排查。下面将系统性地介绍如何查看日志和定位故障的常用方法。

场景命令
查看 Pod 状态kubectl get pods
查看详细信息kubectl describe pod <pod>
查看当前日志kubectl logs <pod>
查看历史日志kubectl logs --previous
查看服务连接情况kubectl describe svc / ingress
查看资源使用kubectl top pod / node

5.1 Pod 状态和事件排查

查看 Pod 状态

kubectl get pods -n namespace

输出示例:

NAME         READY   STATUS             RESTARTS   AGE
namespace    0/1     CrashLoopBackOff   5          10m

说明 Pod 启动失败,反复崩溃。

查看详细信息(事件)

kubectl describe pod my-app-123 -n namespace

重点关注Events 部分,通常可以看到:

  • 拉镜像失败
  • 探针检查失败
  • 资源不足
  • 无法连接 Service、Volum

5.1.1 拉镜像失败(ImagePullBackOff / ErrImagePull)

错误关键词:

Warning  Failed          Failed to pull image "xxx"
Warning  BackOff         Back-off pulling image "xxx"

示例输出:

Warning  Failed     12s (x4 over 1m)  kubelet  Failed to pull image "my-registry/myapp:latest": image not found
Warning  BackOff    2s (x5 over 30s)  kubelet  Back-off pulling image "my-registry/myapp:latest"

常见原因:

  • 镜像不存在或拼写错误
  • 镜像仓库私有,需要认证
  • 网络不通

5.1.2 探针检查失败(Liveness/Readiness probe failed)

探针(Probe) 是 Kubernetes 检查容器健康状态的机制。主要分为:

类型用途
livenessProbe容器是否“活着”,失败会重启容器
readinessProbe容器是否“准备好提供服务”,失败会从 Service 中移除

错误关键词:

Warning  Unhealthy  Liveness probe failed
Warning  Unhealthy  Readiness probe failed

示例输出:

Warning Unhealthy Liveness probe failed: Get "http://10.244.0.12:8080/healthz": dial tcp 10.244.0.12:8080: connect: connection refused

常见原因:

  • 应用没启动完成
  • 探针配置错误(如端口/路径/超时时间)
  • 容器本身服务崩溃

5.1.3 资源不足(Insufficient CPU / Memory)

错误关键词:

FailedScheduling  0/3 nodes are available: 3 Insufficient memory.

示例输出:

Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 3 Insufficient cpu.

常见原因:

  • 请求的 resources.requests 超出 Node 可用资源
  • 集群资源本身不足

5.1.4 无法连接 Service / Volume

错误关键词(Service):

Connect: connection refused

错误关键词(Volume):

Unable to attach or mount volumes

示例输出(Service):

Error: Get "http://my-service.default.svc.cluster.local:8080/health": dial tcp: lookup my-service.default.svc.cluster.local: no such host

示例输出(Volume):

Warning FailedMount Unable to attach or mount volumes: unmounted volumes=[data], unattached volumes=[data default-token-xyz]

常见原因:

  • Service 名错误或未创建
  • Pod 所在 namespace 不一致
  • PVC 没绑定或 StorageClass 有误

5.2 查看容器日志

先说说多容器 + 多副本的概念,一个 Pod 可以有多个容器,一个 Deployment 可以有多个副本 Pod。

5.2.1 Pod 中的多个容器

一个 Pod 通常有一个主容器(主业务逻辑),但也可以包含多个容器,例如:

  • 一个主容器运行应用
  • 一个 sidecar 容器负责日志收集、代理、配置同步等

这种设计允许它们共享网络和存储卷,但你在查看日志时必须指定 -c <container-name>

例如:

kubectl logs my-app-123 -c app-container   # 主容器日志
kubectl logs my-app-123 -c sidecar         # 辅助容器日志

5.2.2 Deployment 中的多个副本

如果你有如下 Deployment:

spec:
  replicas: 3

Kubernetes 会启动 3 个副本的 Pod,Pod 名字会自动加随机后缀,例如:

  • my-app-1234
  • my-app-5678
  • my-app-90ab

你可以使用以下命令查看这些副本的名字:

kubectl get pods -l app=my-app

然后用日志命令逐个查看:

kubectl logs my-app-1234 -c <container-name>
kubectl logs my-app-5678 -c <container-name>

5.1.3 查看历史容器日志(如 CrashLoop)

查看历史容器命令:

kubectl logs my-app-123 -c <container-name> --previous

如果你的应用名为 my-app,且其 Pod 名称为 my-app-123,容器名称为 main-container,那么具体命令可能是这样的:

kubectl logs my-app-123 -c main-container --previous

输出示例:

2025-05-03T09:05:23.456Z INFO application - Application started successfully. 
2025-05-03T09:07:12.345Z ERROR application - Uncaught exception: NullPointerException ...

5.3 排查 CrashLoopBackOff 问题

CrashLoopBackOff 是 Kubernetes 中 Pod 无法正常启动并持续崩溃的一种状态,表示容器启动后立即崩溃,并且 Kubernetes 尝试重启它,但总是失败。当日志显示:

Back-off restarting failed container

说明发生了CrashLoopBackOff错误。常见的原因和解决方法是:

原因解决建议
应用本身错误检查日志,确认是否由于代码异常退出,或者缺少必要参数
配置错误检查 ConfigMap、Secret、环境变量是否配置完整
依赖未准备好应用依赖服务未启动或连接失败(如数据库、Redis)
探针失败Liveness 或 Readiness Probe 配置过于严格导致频繁重启
资源限制过低memorycpu 限制太小,导致容器 OOM(Exit Code 137)
挂载卷失败PVC 未绑定、权限不足、路径错误等
镜像问题镜像缺少入口点、依赖库、权限等问题

可按照如下步骤排查这个问题:

5.3.1 查看 Pod 状态与事件

使用以下命令查看 Pod 当前的状态和事件信息:

kubectl describe pod <pod-name> -n <namespace>

重点查看以下内容:

  • Last State 是否有 Exit Code(比如 1、137、139 等)

  • Events 区域是否提示:

    • Back-off restarting failed container
    • Liveness probe failed
    • FailedMount(可能是 volume 问题)
    • ImagePullBackOff(可能是镜像拉取失败)

5.3.2 查看容器日志

查看容器崩溃前的日志:

kubectl logs <pod-name> -n <namespace> --previous

说明:

  • --previous 表示查看上一次运行(已崩溃)的容器日志
  • 通常能看到崩溃前的错误输出,比如缺配置、环境变量错误、依赖未连接等

5.3.3 分析 Exit Code(退出码)

describe pod 中或 kubectl get pod 后添加 -o wide,查看容器退出码:

退出码含义
1通用错误,程序异常退出
137被 SIGKILL 杀死,常因内存不足
139段错误(Segmentation fault)
255通常表示严重错误或非法退出

5.3.4 检查YAML 配置

查看完整 YAML 配置,排查环境变量、探针设置、镜像配置、挂载路径等是否有误。

kubectl get pod <pod-name> -n <namespace> -o yaml

检查对应 Deployment 或 StatefulSet 的配置

kubectl describe deploy <deploy-name> -n <namespace>
kubectl get deploy <deploy-name> -n <namespace> -o yaml

5.3.5 检查 Node 和资源情况

判断是否是资源瓶颈导致 OOM。查看所有 Node 的资源使用情况 kubectl top 命令依赖于 Metrics Server 插件。检查是否安装:

kubectl get deployment metrics-server -n kube-system

如果没有安装,可以使用官方提供的方式快速部署:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/compon
kubectl top node

输出示例

NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
node-1         350m         18%    1.2Gi           30%
node-2         100m         5%     800Mi           20%

查看某个命名空间下 Pod 的资源使用情况 或者 查看所有命名空间下的 Pod 使用情况

kubectl top pod -n <namespace>
kubectl top pod --all-namespaces

示例输出:

NAMESPACE     NAME                       CPU(cores)   MEMORY(bytes)
default       my-app-7b74d6d969-abcde    25m          100Mi

5.4 排查 Service/Ingress 无法访问问题

Kubernetes 中遇到 ServiceIngress 无法访问的问题时,可以按照从下到上的层级逐步排查,涵盖网络、Service 类型、端口、路由、DNS 解析、Ingress Controller 状态等关键点。

5.4.1 检查 Service 配置

kubectl get svc -n <namespace>
kubectl describe svc <service-name> -n <namespace>
  • 类型是否为 ClusterIP, NodePort, LoadBalancer
  • PortTargetPort 是否匹配
  • Selector 是否能正确匹配 Pod 标签

常见错误:Pod 标签与 Service selector 不匹配,导致没有后端 Pod 被转发。验证后端 Pod 是否被选中:

kubectl get pod -l <service-selector> -n <namespace>

5.4.2 检查 Pod 和应用是否监听对应端口

进入 Pod 内测试端口是否监听:

kubectl exec -it <pod-name> -- netstat -tulnp

或直接在 Pod 中使用 curl 测试自身服务:

kubectl exec -it <pod-name> -- curl localhost:<port>

5.4.3 检查 Service 到 Pod 的连通性(Cluster 内部)

可以用 BusyBox 测试:

kubectl run tmp-shell --rm -i --tty --image=busybox -- /bin/sh

在里面测试:

nslookup <service-name>.<namespace>.svc.cluster.local
wget <service-name>:<port> -O -

5.4.4 检查 Ingress 配置

kubectl get ingress -n <namespace>
kubectl describe ingress <ingress-name> -n <namespace>

确认是否包含:

  • 正确的 host 配置
  • 正确的 path 与后端 serviceName / servicePort
  • 是否设置了 TLS(如果启用 HTTPS)

5.4.5 检查 Ingress Controller 是否部署、正常运行

kubectl get pod -n ingress-nginx
kubectl logs -n ingress-nginx <ingress-controller-pod>

常见控制器:

  • ingress-nginx
  • traefik
  • istio-ingressgateway

确保:

  • 它监听了外部端口(默认 80 / 443)
  • 有对应的 LoadBalancer IP 或 NodePort 暴露

5.4.6 外部网络访问测试

  • 确认域名是否正确解析到 Ingress Controller 的地址
  • 使用 curl -v http://your-domain/path 查看响应
  • 如果使用了 HTTPS,确认 TLS 证书是否配置成功

5.5 如何查看容器所在 Node 和调度状态?

要查看容器所在的 Node 以及它的调度状态,可以使用以下几个命令:

5.5.1 查看 Pod 所在 Node

kubectl get pod <pod-name> -n <namespace> -o wide

输出中会包含类似这样的字段:

NAME       READY   STATUS    RESTARTS   AGE     IP           NODE            ...
my-app     1/1     Running   0          2m      10.244.1.10  node-worker-1   ...

NODE 列显示了 Pod 被调度到哪个 Node 上。

5.5.2 查看调度状态(Pending / 被 taint 拒绝等)

kubectl describe pod <pod-name> -n <namespace>

关注以下部分:

  1. 调度结果
Node:           node-worker-1/<IP>
  1. 调度失败原因(如果 Pod 状态是 Pending

会在 Events 中显示:

Warning  FailedScheduling  ...  0/3 nodes are available: 1 Insufficient cpu, 2 node(s) had taint ...

常见调度失败原因包括:

  • CPU / 内存资源不足
  • 节点被 taint 拒绝调度
  • 节点不满足 nodeSelectoraffinity 等限制条件

5.5.3 排查调度失败的 Pod

找出所有 Pending 状态的 Pod:

kubectl get pod -A --field-selector=status.phase=Pending

逐个 describe 进行分析,查看是否是资源不足、节点限制、调度策略问题等。

5.5.4 查看 Node 资源与状态

kubectl get node -o wide
kubectl describe node <node-name>
kubectl top node

可用于分析:

  • 当前节点是否可用
  • 是否有 taint 导致 Pod 被拒调度
  • 是否资源不足(通过 top

在5.3.5章节讲过,不再赘述。

5.6 收集所有日志信息(进阶)

对于大型集群,建议使用日志收集系统:

  • EFK(Elasticsearch + Fluentd + Kibana)
  • Loki + Promtail + Grafana
  • Datadog / Splunk / NewRelic 等商用方案

这些工具能收集全集群日志,统一存储、搜索和分析。

六 资源限制与健康检查

在 Kubernetes 中,为了保证服务稳定运行并避免资源争抢,资源限制(Resource Limits)健康检查(Liveness / Readiness Probes) 是非常关键的配置。

6.1资源限制(Resource Requests & Limits)

6.1.1 定义方法(Pod/Container 中配置)

resources:
  requests:
    cpu: "100m"
    memory: "200Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"
  • requests:调度时预留的资源。如果不设置,可能无法合理调度。
  • limits:运行时最大允许使用的资源。如果超出会被限速(CPU)或杀死(内存)。

6.1.2 示例(在容器中配置)

spec:
  containers:
    - name: my-app
      image: my-image:latest
      resources:
        requests:
          cpu: "200m"
          memory: "256Mi"
        limits:
          cpu: "500m"
          memory: "512Mi"

6.1.3 配置建议

场景建议
Web 服务requests 和 limits 设为相等,避免过度调度
批处理任务requests 小一点,limits 大一些,充分利用资源
高可用系统配置合理的 limits,防止单 Pod 占满整个 Node

6.2 健康检查(Liveness & Readiness)

Liveness Probe(活跃性检查)

  • 判断容器是否 存活
  • 失败则会被 重启

Readiness Probe(就绪检查)

  • 判断容器是否 对流量就绪
  • 失败则 从 Service 负载中移除,但不会重启。

6.2.1 配置方式

有3种配置方式:

方式说明
httpGet访问某个 HTTP 路径,返回 2xx/3xx 表示健康
tcpSocket尝试连接端口
exec容器内执行命令返回 0 表示健康

6.2.2 示例配置(HTTP 方式)

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

6.2.3 实践建议

建议说明
使用 /healthz/ready 路径应用应提供健康检查接口
设置合理的 initialDelaySeconds避免容器启动过慢被误判
在容器异常退出或无响应时重启用 Liveness Probe 保证稳定性
应用初始化未完成时不接收流量用 Readiness Probe 延迟加入服务流量

6.3 综合示例

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: myapp-container
      image: myapp:latest
      ports:
        - containerPort: 8080
      resources:
        requests:
          cpu: "200m"
          memory: "256Mi"
        limits:
          cpu: "500m"
          memory: "512Mi"
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 10
        periodSeconds: 5
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 5

七 最佳实践与总结

最佳实践:

  • 所有配置都应使用 Git 管理版本
  • 使用 Helm 管理应用部署
  • 启用资源限制和探针,提升稳定性
  • 使用 Namespace、RBAC 进行隔离
  • 定期监控集群指标与日志

到此,我们已经掌握了k8s核心概念和常用操作命令,也学会了如何排查故障,可以把本文当作实操手册,遇到问题,按照checklist逐一进行检查,会让你使用k8s的时候少走很多弯路。如果试了本文的方法还找不到解决方案,通过对本文的学习,现在你已经对k8s的核心基础概念有了一定的了解,你向大模型发问相较小白会更精准,会更快速的获得解决方案,这就是本文的价值以及你学习的收益。好了,我们下期见。