Kubernetes实战指南:从Pod概念、集群部署到监控告警
2026/9/9 12:57:41 网站建设 项目流程

这个系列写到第5篇,后台留言明显分成了两拨:一拨是刚上手k8s的新手,还在纠结Pod和容器到底啥关系,YAML文件里一堆字段看着就头疼;另一拨是已经搭好集群、开始往生产环境推的老手,天天在监控告警和故障排查里扑腾,磁盘一告警就抓瞎。索性这一篇就把两条线都收进来,从核心概念讲到部署落地,再到日常运维和监控告警体系搭建,一篇能当五篇用。不管你是准备面试、正在搭测试环境,还是已经在维护线上集群,这篇都值得存一下。

我先把最容易被问懵的几个基础概念拆开讲清楚,再带着你把单节点、集群、权限、监控挨个走一遍。全文涉及的所有命令和配置,我都在实际环境里跑过,不是那种抄官方文档的复读机内容,放心往下看。

1. 先把K8s的另一半讲明白:Pod、Entrypoint、Cmd 到底怎么回事

1.1 为什么非要搞个Pod出来,直接跑容器不行吗

很多新手对Pod的第一反应是:Docker里我直接docker run nginx就完事了,到了K8s里非要包一层Pod,不是多此一举吗。我第一次也有这个疑问,但真去用了才发现,这一层抽象是K8s整个调度模型的地基。

Pod是K8s里最小的调度和部署单元,一个Pod里可以有一个或多个容器,这些容器共享同一个网络命名空间、IPC命名空间,还能通过共享卷交换数据。最典型的例子就是日志边车容器,主容器写日志到共享卷,sidecar容器去读取并转发,两个容器通过localhost就能互相访问。这在纯Docker环境里要搞一堆网络配置才能实现,在Pod里是天然支持的。

还有个容易被忽略的点:Pod是“瞬时的”。K8s里Pod是有生命周期的对象,它的IP每次重建都可能变,所以上层有Deployment、StatefulSet这些控制器来管理Pod的期望状态。你把Pod理解成“一组容器的调度单位”,把Deployment理解成“管理Pod死活的管理员”,这个认知框架就立住了。

1.2 Entrypoint和Cmd:这两个字段很多人用错,坑了半夜

说实话,K8s里commandargs这两个字段我见过太多人搞混了,而且一错就是“容器启动即退出”这种经典故障。

先记一个对应关系:K8s的command对应Docker的ENTRYPOINT,K8s的args对应Docker的CMD。在Dockerfile里正常会写两种风格,一种是用ENTRYPOINT指定主程序、CMD传默认参数,另一种是在CMD里写完整命令。到了K8s的YAML里,如果你只写了command,那Dockerfile里的ENTRYPOINT会被覆盖;如果你只写args,那只会覆盖Dockerfile里的CMD。

关键区别在于:ENTRYPOINT是容器启动后执行的程序本身,CMD是传给这个程序的参数。所以很多人在K8s里写:

containers: - name: myapp image: myapp:latest command: ["-c", "echo hello"]

然后容器直接报错退出,因为这里的command会被当成可执行文件去查找,系统里根本没有名叫-c的程序。正确的做法是:

containers: - name: myapp image: myapp:latest command: ["/bin/sh"] args: ["-c", "echo hello"]

或者更符合直觉的写法:如果镜像本身ENTRYPOINT已经写好了,你只需要传参,那就只用args,不要去碰command

还有一个隐蔽细节:如果镜像里有ENTRYPOINT,你在K8s里只写了command,那会连ENTRYPOINT一起覆盖;如果希望追加参数而不是覆盖程序,就必须只写args。我在排查类似故障时,第一件事永远是kubectl get pod xxx -o yaml看最终的command字段到底变成了什么,而不是猜。

1.3 探针和资源限制,新手最容易忽略的Pod配置

再说两个和Pod紧密相关的配置:探针和资源限制。

探针分为存活探针(livenessProbe)、就绪探针(readinessProbe)和启动探针(startupProbe)。就绪探针决定流量是否打到这个Pod上,存活探针决定Pod死了要不要重启。很多人图省事不写探针,结果就是明明服务已经挂了,Service还在往这个Pod转发流量,用户一脸懵。

资源限制就是requestslimitsrequests是调度器为Pod预留的资源,limits是Pod能用到的上限。如果只写limits不写requests,K8s会默认把requests设成和limits一样,导致调度器认为每个Pod都会占用那么大资源,集群里能塞的Pod数量大幅缩水。实践上我建议requests按真实使用量填,limits留出一定余量,两个都别空着。

2. K8s和Docker的关系:不是替代,是各管一段

2.1 从运行时讲清楚:K8s并不直接管理Docker容器

很多人都没意识到,K8s在很早之前就支持多种容器运行时了,通过CNI、CRI这些标准接口对接。Docker只是其中一种,而且现在很多新集群默认用的是containerd,连Docker都不装了。所以K8s和Docker的关系,准确来说是“调度平台”和“容器运行时”的关系。

K8s负责的是:你的应用该在哪个节点上跑、跑几个副本、挂了怎么恢复、怎么滚动更新、怎么把流量均衡到各个Pod上。Docker负责的是:镜像怎么构建、容器怎么启动、文件系统怎么隔离。理解了这个,再看到kubectl get nodes里显示containerd://而不是docker://就完全不慌了。

至于很多教程里用docker ps查看集群内容器,这在新版集群里基本是看不到的,因为Pod里的容器是由containerd起的管理,你该用的是crictl ps或者kubectl系列命令。我见过不少老哥上生产环境后第一件事就是找Docker socket,结果发现压根没装Docker。

2.2 共享内核:容器隔离的边界在哪

还有一个必须说清的点:Docker容器和虚拟机不一样,它不是完整的操作系统,而是共享宿主机内核,通过名称空间和控制组做隔离。所以你在容器里跑uname -r,看到的是宿主机的内核版本,不是CentOS或Ubuntu的内核。

这带来了两个实际影响。第一个是兼容性:容器镜像里的二进制必须能在宿主机内核上运行,所以你在镜像里用的glibc版本、依赖的内核模块都要心里有数。第二个是安全性:既然共享内核,内核漏洞就可能影响所有容器,这也是K8s里要有PodSecurityPolicy(现在叫Pod Security Admission)这类安全机制的原因。

我之前在项目里遇到一个服务在测试环境跑得好好的,上生产就段错误,排查了半天发现是生产内核版本太老,镜像里用了比较新的系统调用。这种问题在虚拟机时代很少见,但在容器环境下会频繁出现,这也是“容器不等同于虚拟机”的活教材。

2.3 生产环境两者是怎么配合的

现在很多公司的实际架构是:开发环境用Docker Compose快速起服务,生产环境用K8s来编排。Docker负责开发时的一键启动和镜像构建,K8s负责生产环境的多副本调度、自动伸缩、滚动更新。

在CI/CD流水线里,Docker构建出镜像推到私有仓库,然后K8s的Deployment通过更新镜像版本来完成发布。这个链路里每个环节都有明确分工。我给团队的建议是:不要想着用K8s完全替代Docker,也不要以为有了Docker就不需要K8s,它们本来就是不同层级的工具。

3. 实操第一步:单节点部署K8s,新手最稳妥的上手路径

3.1 环境准备:先别急着敲命令,把前置条件理顺

新建一台干净的服务器或者虚拟机,推荐Ubuntu 22.04 LTS,2核4G起步,磁盘至少20G。系统装好后,先把三件事做了:关闭swap、加载内核模块、配置系统参数。

关闭swap的原因是Kubelet在默认配置下要求必须关闭swap才能正常工作,否则节点会一直处于NotReady状态。执行swapoff -a只是临时关闭,要持久化还需要注释掉/etc/fstab里的swap行。我见过太多人只执行了swapoff -a,重启后又开始swap,然后一脸迷茫地来问为什么K8s又挂了。

内核模块方面,需要加载overlaybr_netfilter

modprobe overlay modprobe br_netfilter

然后创建/etc/sysctl.d/k8s.conf,写入:

net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1

执行sysctl --system让配置生效。这一步是为了让iptables能正确处理K8s网络转发流量,不然后面部署网络插件会出一堆玄学问题。

3.2 用kubeadm部署单节点集群的具体步骤

环境准备好后,开始装三个核心组件:kubelet、kubeadm、kubectl。这里推荐直接配置阿里云镜像源或中科大镜像源,在国内环境下速度快很多,没必要在默认源上干等。

apt-get update && apt-get install -y apt-transport-https curl curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet kubeadm kubectl

注意装完后要把三个包的版本锁住,防止升级导致集群不一致:

apt-mark hold kubelet kubeadm kubectl

然后初始化控制面:

kubeadm init \ --apiserver-advertise-address=192.168.1.10 \ --image-repository registry.aliyuncs.com/google_containers \ --pod-network-cidr=10.244.0.0/16

--pod-network-cidr的值要和后面用的网络插件匹配。我用的是Flannel,它的默认网段是10.244.0.0/16,保持一致能少踩很多坑。

初始化完成后,按提示执行:

mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config

这里有个很多人忽略的点:这个admin.conf就是你的集群管理员凭证,放到家目录的.kube/config是为了让kubectl默认就能找到它。如果你换了台机器想管理这个集群,把这个文件复制过去,设置KUBECONFIG环境变量指向它就行。

3.3 安装CNI网络插件并验证

单节点集群,控制面的污点还在,得先安装网络插件再考虑调度Pod。装Flannel:

kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

然后查看Pod状态:

kubectl get pods -n kube-flannel

等所有Pod变成Running之后,如果想让这个单节点也能跑应用,要解除控制面的污点:

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

这样你的单节点集群就能正常调度业务Pod了。验证一下:

kubectl run nginx-test --image=nginx kubectl get pod

如果状态是Running,恭喜,你的第一个K8s集群已经能干活了。

4. 从单节点到多节点:集群搭建和网络方案选型

4.1 多节点集群里,控制面和工作节点各干什么

生产环境不可能只有一台机器,肯定要拆成控制面节点和工作节点。控制面跑的是apiserver、scheduler、controller-manager、etcd这些组件,工作节点只跑kubelet和kube-proxy,外加一堆业务Pod。

在物理拓扑上,etcd最好单独部署或者至少放在独立节点上,因为etcd是整个集群的“大脑”,存储了所有集群状态。etcd一挂,整个集群就只读了,啥都改不了。我在一个同事那边见过etcd和业务Pod混布的结果,业务Pod一通流量高峰直接把etcd的磁盘IO打满,整个集群开始抖动,恢复起来极其痛苦。

4.2 多节点部署时的具体操作步骤

控制面节点初始化完成后,工作节点加入集群只需要两步。

第一步,拿到控制面的加入命令。在控制面节点上执行:

kubeadm token create --print-join-command

这个命令会输出类似:

kubeadm join 192.168.1.10:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx

第二步,在工作节点上,先把环境准备里的swap、内核模块、系统参数全部做一遍,然后安装kubelet、kubeadm、kubectl,最后执行刚才拿到的join命令。

等节点加入后,在控制面节点查看:

kubectl get nodes

如果新节点状态是NotReady,九成是网络插件问题或kubelet没起来。看kubelet日志的方式是:

journalctl -u kubelet -f

这里再次强调:工作节点不需要装kubectl,也不需要有kubeconfig文件,它只需要kubelet和kubeadm就够了,kubelet会向apiserver注册自己并接收指令。

4.3 网络插件的区别,别随便选一个就上

K8s本身不实现Pod间的网络互通,需要第三方CNI插件来做。最主流的三选一:

插件优势劣势适合场景
Flannel简单易用,VXLAN模式稳定性能一般,功能少学习环境、小规模集群
Calico支持网络策略,BGP模式性能好配置复杂,对内核有要求生产环境、需要对Pod做网络隔离
Cilium基于eBPF,性能极强,功能全学习曲线陡,依赖较新内核大规模集群、对性能敏感

我自己的经验是:测试环境用Flannel,图省心;生产环境用Calico或Cilium,尤其是对安全隔离有要求的场景,Flannel默认是允许所有Pod互通的,等于没有网络安全组。如果要用Calico,初始化时--pod-network-cidr要改成192.168.0.0/16,因为Calico默认用这个网段。

4.4 搭建完集群后必做的检查清单

很多人集群起来了就觉得完事了,实际上隐藏问题一大堆。我每次搭完都要跑一遍这些检查:

  • kubectl get nodes:所有节点Ready,版本一致。
  • kubectl get pods -A:核心组件和网络插件都Running。
  • kubectl describe node:看节点上的资源压力和污点。
  • 部署一个测试Deployment,然后手动删掉一个Pod,看它会不会自动重建。
  • 滚动更新一个镜像版本,看是否平滑过渡。

这套检查跑下来,集群才算真正可用。特别是最后两步,能帮你提前暴露调度和控制器的问题,而不是等业务上线了才发现。

5. 日常运维必备:常用命令全集和只读权限配置

5.1 高频命令手册:这些不用想,顺手就敲出来

很多人学K8s卡在记不住命令上,其实核心就几十条。我按用途分类,平时最常用的是这些:

查看类:

kubectl get nodes # 查看节点 kubectl get pods -A # 查看所有命名空间的Pod kubectl get deploy,svc,cm,secret -n xxx # 查看工作负载和配置 kubectl describe pod <pod-name> # 看Pod详细状态和事件 kubectl logs -f <pod-name> --tail=100 # 看日志

操作类:

kubectl apply -f xxx.yaml # 创建或更新资源 kubectl delete -f xxx.yaml # 删除资源 kubectl scale deploy xxx --replicas=5 # 扩缩容 kubectl rollout restart deploy xxx # 重启Deployment kubectl exec -it <pod-name> -- /bin/sh # 进入容器 kubectl edit deploy xxx # 在线编辑配置

排查类:

kubectl top node # 查看节点资源使用 kubectl top pod -A # 查看Pod资源使用 kubectl get events -n xxx --sort-by=.lastTimestamp # 查看事件 kubectl api-resources # 查看所有资源类型

个人习惯是把常用命令写进一个shell别名文件,比如kgp代表kubectl get podskd代表kubectl describe,用久了速度能快不少。

5.2 只读权限用户配置:别再给所有人都发管理员证书

搜索热词里那句“k8s只开只读权限的用户”,我猜肯定是有人拿着管理员权限被坑过了。K8s的权限控制走RBAC,核心是Role、ClusterRole和RoleBinding、ClusterRoleBinding这四类对象。

给一个用户配只读权限,有三个步骤。第一步,创建RBAC配置:

apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: readonly-role rules: - apiGroups: [""] resources: ["pods", "pods/log", "services", "endpoints", "configmaps", "secrets", "nodes", "namespaces", "events"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["deployments", "statefulsets", "daemonsets", "replicasets"] verbs: ["get", "list", "watch"] - apiGroups: ["metrics.k8s.io"] resources: ["pods"] verbs: ["get", "list", "watch"]

保存为readonly-clusterrole.yaml,执行kubectl apply -f

第二步,给这个用户或服务账户绑定:

apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: readonly-binding subjects: - kind: User name: zhangsan apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: readonly-role apiGroup: rbac.authorization.k8s.io

第三步,为用户生成凭证。最常见的做法是生成一个签名的证书,或者直接用kubeconfig文件的token方式。简单起见,可以先把管理员kubeconfig复制一份,然后把user字段换成新用户,并移除client-certificate-dataclient-key-data中的管理员信息,替换成新证书。但这一步操作稍繁琐,更推荐的做法是用服务账户(ServiceAccount)加token:

kubectl create serviceaccount readonly-sa kubectl create token readonly-sa

拿到token后放到kubeconfig里,注意默认情况下ServiceAccount是无权限的,所以要给它绑定刚才的只读ClusterRole:

kubectl apply -f readonly-binding-sa.yaml

这个思路要记牢:先建角色和权限规则,再建绑定把角色和用户/服务账户关联起来,最后分发凭证。顺序反了或者漏了绑定,就会遇到“明明建了用户却什么都看不了”的问题。

5.3 RBAC配置的几个坑

第一个坑是apiGroups写错。比如deployments属于apps这个apiGroup,如果你写成apiGroups: [""],那permissions会失效。我排查过一个同事的授权问题,最后发现就是apiGroup空字符串和apps写混了。

第二个坑是secrets资源的可见性。很多只读角色忘了加secrets,结果用户连查看Secret里的配置都做不到。这在排查问题时会非常折腾,因为某些控制器会把Secret内容编进Pod的环境变量里。

第三个坑是RBAC的变更不是实时对所有会话生效的,有时需要重新加载kubeconfig或新开一个会话才生效,遇到权限“没变化”可以先考虑这个因素。

6. 监控告警体系搭建:node-exporter + Prometheus + Grafana 磁盘告警实战

6.1 监控体系的分工:采集、存储、展示、告警各司其职

Google到“k8s监控告警体系中node-exporter,prometheus,grafana,磁盘告警规则是如何配置”的朋友,大概率是想搞懂一条完整的监控链路。我直接把这条链路拆开讲。

Prometheus负责抓取指标并存储,它通过HTTP周期性访问各种exporter暴露的/metrics接口,把数据存进自己的时序数据库。node-exporter是跑在每个节点上的DaemonSet,专门负责采集节点的CPU、内存、磁盘、网络指标。Grafana负责从Prometheus读取数据,把数据变成可视化面板,同时也能配置告警规则。这四者配合起来,才是一个完整的监控体系。

6.2 用Helm一条命令部署监控全家桶

手动一个个写YAML部署Prometheus全家桶太痛苦了,我建议直接用Helm。先确保Helm已经装好:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update

然后创建命名空间并一键部署:

kubectl create namespace monitoring helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring

这个chart会把Prometheus、Grafana、node-exporter、kube-state-metrics、alertmanager全装进去,版本之间都是匹配好的,比自己手动拼省心太多。

等Pod全部Running后,看服务对应的端口:

kubectl get svc -n monitoring

默认情况下是ClusterIP,外部访问不到。测试环境可以直接把Grafana的Service改成NodePort:

kubectl edit svc prometheus-grafana -n monitoring

type: ClusterIP改成type: NodePort,然后访问http://节点IP:NodePort,默认账号密码是admin/prom-operator。生产环境建议用Ingress暴露,并开启认证,别裸奔。

6.3 磁盘告警规则到底怎么写

磁盘告警是运维里最刚需的告警之一,磁盘一满,各种服务就接二连三地挂。Prometheus里配置告警规则的思路是:定义一条PromQL表达式,当表达式查出来的值满足条件时,就触发告警。

kube-prometheus-stack自带的磁盘告警规则已经比较完整,但如果要自定义,在values里覆盖alertmanager和prometheus的rules即可。我先讲一下核心的PromQL:

groups: - name: disk-alerts rules: - alert: NodeDiskUsageHigh expr: (1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs", mountpoint!~"/var/lib/docker/containers"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay|squashfs", mountpoint!~"/var/lib/docker/containers"})) * 100 > 80 for: 5m labels: severity: warning annotations: summary: "节点 {{ $labels.instance }} 磁盘使用率超过 80%" description: "当前使用率: {{ $value | humanizePercentage }}, 挂载点: {{ $labels.mountpoint }}"

这条规则的逻辑是:先算出磁盘使用率(总容量 - 可用容量) / 总容量,再乘以100得到百分数,当超过80时触发告警。fstype的过滤是为了排除tmpfs和overlay这类虚拟文件系统;for: 5m表示使用率持续超过80%达到5分钟才告警,避免瞬时抖动导致误报。

在实际配置时,你可以把PromQL里的80改成自己业务能接受的阈值。我一般会把告警分两级:使用率超过80%发Warning,超过90%发Critical,这样团队能有缓冲时间处理。

配置方法:如果你用Helm,需要在values.yaml里通过additionalPrometheusRulesMap添加自定义规则。示例:

prometheus: prometheusSpec: additionalPrometheusRulesMap: custom-disk-alerts: groups: - name: disk-alerts rules: - alert: NodeDiskUsageHigh expr: ...

然后升级release:

helm upgrade prometheus prometheus-community/kube-prometheus-stack -n monitoring -f values.yaml

6.4 Grafana面板配置:重点看这几个Panel

Grafana装好后,默认会自带一堆面板。我日常最常用的是“Kubernetes / Views / Nodes”这个面板,可以看到集群整体资源使用情况。

如果要自己做一个磁盘使用率面板,只需要加一个Panel,数据源选Prometheus,Query填:

1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})

Legends和Unit都配置成百分比。然后配置Alert条件:当该值大于0.8时触发告警。这样不写PromQL规则也能在Grafana里直接收到告警通知。

顺带说一句:Grafana上面的Alert功能已经比较完善,但生产环境我还是建议把告警规则放在Prometheus里统一管理,Grafana只做展示,因为Prometheus的Alertmanager能对接钉钉、飞书、邮件、Slack等一大堆通知渠道,Grafana的通知渠道相对有限。

6.5 磁盘告警踩过的几个坑

第一个坑:node-exporter采集的磁盘指标里有很多虚拟文件系统的挂载点,比如/etc/hosts/var/lib/kubelet这种,如果不加mountpoint过滤,会出现磁盘使用率虚高导致误报。我见过有人没过滤挂载点,磁盘用了30%就开始疯狂告警。

第二个坑:默认的磁盘告警按“整个节点”维度告警,但很多时候一个节点上有多个数据盘,某个盘满了其他盘还很空。建议把告警规则改成按挂载点分开统计,比如用mountpoint="/data"单独对数据盘设阈值。

第三个坑:告警通知渠道没配置。规则写了、表达式也正确,但Alertmanager没配通知,一切等于白干。我建议在部署的时候就在values里把alertmanager.config里加好webhook或邮箱配置,别等告警来了再补。

7. 故障排查思路:从Pod到节点的常见问题实录

7.1 Pod一直Pending,到底卡在哪

Pod状态是Pending,说明调度器还没把它放到某个节点上。最常见的三个原因:节点资源不足、节点有污点、有resourceQuota限制或亲和规则。

排查思路固定两步:看事件和看资源。

kubectl describe pod <pod-name> kubectl get nodes --show-labels kubectl describe node <node-name>

describe里会直接写“0/3 nodes are available”,并给出原因,比如“Insufficient memory”或“node(s) had taint”。如果是资源不足,就扩容或者删掉些无用Pod;如果是污点问题,要么解除污点,要么给Pod加对应的容忍。

还有一个容易被忽略的点是PVC挂载问题。如果Pod依赖的PVC绑定不上,Pod也会一直Pending。这种错误通过事件和kubectl get pvc -A就能看到。

7.2 CrashLoopBackOff:容器反复重启

这个报错应该是最常见的了。核心原因是容器启动后立刻退出,K8s不断重启它,每次重启间隔越来越长(指数退避,所以叫BackOff)。

排查步骤是:

  1. 看日志:kubectl logs <pod-name> --previous。注意加--previous看上一次退出的日志,因为当前容器可能已经重启没了。
  2. 看事件:kubectl describe pod <pod-name>,里面会有 “Back-off restarting failed container” 的提示。
  3. 判断退出码:Exit Code 1通常是业务代码错误,Exit Code 137是内存杀死(OOM),Exit Code 126/127是命令不存在或无法执行。

我把遇到过的情况列成速查表,方便对照:

退出码大概率原因解决方向
1业务代码异常、StartupProbe失败去日志看异常栈
137OOM或被杀死调大limits,看代码内存使用
126权限不够或文件格式不对检查二进制是否有执行权限、入口是否正确
127命令不存在检查command和镜像里的路径
130被信号终止排查是否被手动kill或oom
143SIGTERM可能是优雅终止流程卡住

7.3 节点状态NotReady:从kubelet开始排查

节点NotReady,问题大概率出在节点上的kubelet或运行时。第一步永远是去看kubelet日志:

journalctl -u kubelet -n 100 --no-pager

常见的NotReady原因包括:swap没关、网络插件没生效、kubelet证书过期、容器运行时异常。另外还有一个高频原因:节点资源耗尽,比如磁盘满了导致kubelet无法上报心跳。

如果kubelet日志看不清,可以查看状态:

systemctl status kubelet

如果是证书过期,日志里会出现类似“certificate has expired”的字眼,解决方式是执行kubeadm certs renew all或者直接重新加入集群。

7.4 服务间访问超时或连接失败

Pod起来了,节点也Ready了,但服务访问就是不通。先判断是集群内部访问还是外部访问问题。

如果是集群内部访问,先看Service的Endpoints:

kubectl get endpoints <service-name>

如果Endpoints为空,说明Service的selector和Pod标签对不上,或者Pod不是Running状态。如果Endpoints正常,再看kube-proxy的规则,或者直接进入一个Pod ping一下ServiceIP和PodIP。

如果是外部访问问题,大概率是Service类型或Ingress配置错了。NodePort模式下要确认节点的安全组放行了对应端口;Ingress模式下要确认Ingress Controller的Service已经暴露出来,且DNS解析指向了正确的入口地址。

这里有个很实用的经验:排查网络问题时,先在同一个命名空间里起一个临时测试Pod,用kubectl run -it test --image=busybox --rm进去测试连通性,速度快而且不影响业务。

8. 总结建议:这套体系要掌握到什么程度

这个系列如果是面试导向的,我建议你重点梳理:Pod的生命周期、Deployment的滚动更新策略、Service的ClusterIP转发原理、RBAC的模型、以及监控告警里PromQL的常见写法。这些都是面试官必问的高频点。

如果是为了实际生产环境,我的建议是先别追求大而全,把基础链路跑通:单节点搭建、多节点扩展、命名空间隔离、资源配额、监控告警闭环。每一块都真正亲手配过,出了问题能独立排查,再去看服务网格、多集群管理这些进阶方向。

踩过几次坑之后,我个人的体会是:K8s上手最大的门槛不是命令记不住,而是脑子里没有一个完整的心智模型。你不理解控制面和工作节点的关系,不理解控制器如何通过etcd实现期望状态,一遇到故障就会卡在“看日志→还是看不懂”的循环里。先把Pod、控制器、Service、RBAC、监控这几条主线打通,后面的路就顺了。

最后再分享一个小技巧:每次部署完一个新功能,都养成kubectl get eventskubectl describe的习惯,很多问题会在事件里提前暴露,而不是等你用户来报了才发现。K8s这套系统本身就是一个巨大的状态机,学会读懂它的状态变化,比背任何命令都值钱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询