说实话,Kubernetes 的命令行工具 kubectl 用熟了,效率能翻好几倍。我在日常维护集群、排查问题、发布应用时,最依赖的就是那几十条高频命令。这份速查不是把官方文档搬过来,而是把我实际项目里反复用到、踩过坑、验证过的命令和参数整理出来,每条都标清楚为什么这么用、什么时候需要用、以及哪些参数组合容易让人翻车。不管你是刚入门 K8s,还是已经写过不少 yaml,这篇都值得收藏下来当手边手册。
这份内容的适用对象很直接:用 kubectl 管理集群的人,不管是开发者、运维还是 SRE。你能从中得到一套可以直接照抄的命令组合,遇到 Pod 起不来、服务不通、资源卡住时,按着里面的排查顺序走,基本上不会跑偏。另外,我也把参数部分做了重点拆解,像 -o、-l、--field-selector、--dry-run 这些看起来简单,实际组合起来的威力很大,很多问题定位到根因,靠的就是这些参数而不是 echo 打印日志。
1. 为什么你需要一份K8s命令速查
1.1 这命令到底有多常用
kubectl 是 Kubernetes 的官方命令行客户端,几乎所有的集群操作都通过它发起。我见过不少同学一开始只会在 get pods 和 logs 之间来回切换,等遇到真正的问题,比如 Deployment 更新没有生效、节点 NotReady、Pod 卡在 Pending,就不知道该用哪条命令去定位。这是很正常的,因为 K8s 的资源类型非常多,光内置的工作负载类型就有 Deployment、StatefulSet、DaemonSet、Job、CronJob 这几种,每个资源又有关联的子资源、事件、状态描述,光靠死记硬背肯定不行。
但如果有一份按场景组织的命令速查,情况就完全不同了。查询类命令负责描述现状,排查类命令负责缩小范围,操作类命令负责修改状态,资源清理类命令负责收尾。这套思路和任何系统运维都一样,只是 K8s 的抽象层级更多,需要掌握的查询入口也更多。我平时接到一个集群异常反馈,脑子里第一反应就是先跑kubectl get events --sort-by=.lastTimestamp看最近发生了什么,再根据资源类型跑对应的describe,这一步能解决大概一半的虚拟化层问题。
把常用命令固化成肌肉记忆最大的好处是减少上下文切换。你要在终端和浏览器之间来回翻文档时,事故现场早就变了。我自己写过一阵子速查卡,贴在工位上,后来发现最实用的反而是那些带参数解释的版本——光记命令不够,参数之间的配合才是关键,比如-o wide不是多显示一列那么简单,--all-namespaces在排障时几乎可以救命。
1.2 这份速查和官方文档的区别
官方文档当然是权威的,但它的定位是字典,不是场景手册。字典把所有命令按字母排序,参数说明写得很严谨,但你看完还是不知道“Node 磁盘压力导致 Pod 被驱逐”时应该先查什么。这份速查是按照我实际使用频率和故障类型来组织的,每个命令都配了真实场景说明,参数部分也不是罗列所有选项,而是挑那些最常用、性价比最高的讲,并告诉你在什么条件下参数会失效。
举个例子,kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}'这种命令官方文档里有,但你要是没点 JSONPath 的基础,根本不知道怎么写。我会把这类的用法拆开讲,告诉你 JSONPath 的结构和常见的过滤条件怎么写,而不是让你去啃一整章。另一个例子是--field-selector,这个参数能按资源的字段精确过滤,很多人根本没听说过,但在排查“某个节点上的所有 Pod”或“所有 Failed 的 Pod”时非常好用。
这份速查还含了不少我自己的习惯。比如我从来不用kubectl edit直接改线上资源,而是先get -o yaml备份再改,改完用apply回写。这种习惯没法从官方文档里学到,但能避免很多事故。我尽量把这些经验也写进去,让你少走弯路。
2. 基础命令:从零到能跑通一次发布
2.1 查看集群与节点状态
拿到一个新集群,第一步永远是确认自己和集群的连接状态。kubectl cluster-info会打印出控制平面和核心组件(如 CoreDNS、kube-proxy)的访问地址,如果集群没就绪,这条命令会直接报错。更精细的视角是kubectl get nodes,它列出所有节点及其状态、角色(通常是 master/worker 或 control-plane/node)、K8s 版本、容器运行时版本和操作系统类型。加上-o wide能看到节点的内部 IP、外部 IP 以及所在的可用区,这在我们做网络诊断时非常有用。
看节点状态时,STATUS 列常见值有 Ready、NotReady、SchedulingDisabled 和 Unknown。NotReady 意味着节点上的 kubelet 长时间没上报健康状态,通常和负载过高、磁盘满、网络分区有关。SchedulingDisabled 则说明节点被主动调控过,比如执行过kubectl cordon设置了不可调度。这时候可以用kubectl describe node <node-name>查看节点状态的具体 Condition,里面有 MemoryPressure、DiskPressure、PIDPressure、Ready 等详细字段,能直接看到是哪一个维度的压力触发了异常。
另外,kubectl get nodes -o jsonpath这种高级查询也可以在日常巡检中使用。我习惯写一条命令同时输出节点名称、可分配 CPU 和内存、以及当前已用比例,虽然用 Prometheus 也能看,但命令行内直接出结果是最轻量的方式。还有一点,节点维护前一定要用kubectl drain把业务 Pod 优雅撤离,而不是直接cordon加一步手动删除 Pod,否则工作负载可能面临中断。drain 有自动驱逐的功能,配合--ignore-daemonsets可以跳过 DaemonSet 管理的 Pod,避免卡住。
2.2 命名空间与上下文切换
命名空间是 K8s 隔离资源的基本单位。刚开始用集群的人最喜欢在所有命令后加-n指定命名空间,但系统里通常有多个命名空间,每次手打-n很麻烦。更聪明的办法是用kubectl config set-context来切换默认上下文。比如你经常操作 staging 环境,可以执行kubectl config set-context <context-name> --namespace=staging,然后kubectl config use-context <context-name>,之后所有的 kubectl 命令都会默认在 staging 命名空间下工作,不用再带 -n。
查看当前上下文用kubectl config current-context,查看所有上下文用kubectl config get-contexts。当多个集群切换时,我习惯把每个集群的 context 命名成<cluster>-<env>,比如 prod-k8s、dev-k8s,这样一眼能看出自己在哪个环境,避免误操作生产。还有一个容易被忽略的细节:有些 cluster 连接需要自定义证书或 token,如果多台机器共用 kubeconfig,建议用KUBECONFIG环境变量合并多个配置文件,而不是直接覆盖默认的 ~/.kube/config。
命名空间本身的操作不多,创建用kubectl create namespace <ns>,查看列表用kubectl get ns。但你需要知道,不同命名空间里的资源是逻辑隔离的,网络策略可能进一步限制通信。排查跨服务调用问题时,先确认是不是命名空间级网络策略拦截了请求,这个排查方向经常比看代码更有效。
2.3 部署与Pod生命周期管理
部署一个应用最标准的命令是kubectl apply -f deployment.yaml,推荐用 apply 而不是 create,因为 apply 支持声明式更新,后一次提交会对比当前状态做增量变更,而 create 只能新建,二次执行会报“已存在”错误。我们团队内部几乎所有工作负载都以 yaml 方式维护,提交到 git 仓库后,用 apply 同步到集群。这样的好处是随时能知道线上资源实际配置和仓库里是否一致。
查看部署状态用kubectl get deployment,检查滚动更新情况可以用kubectl rollout status deployment/<name>。这条命令会阻塞住,直到部署成功或者超时,非常适合写在发布脚本里判断发布是否完成。发布失败时,用kubectl rollout undo deployment/<name>回滚到上一个版本,也可以用--to-revision=<n>回滚到指定历史版本。查看历史版次用kubectl rollout history deployment/<name>,里面会记录每次变更的版本号和变更原因,前提是 deployment 没有设置revisionHistoryLimit: 0,否则历史会被清空。
Pod 是真正运行应用实例的最小单元,查看列表用kubectl get pods。很多人不知道-o wide对查看 Pod 所在节点和 IP 非常方便,有时 Pod 重启了、IP 变了,-o wide能直接看到新旧差异。如果你想一次看到 Pod 的资源请求、限制以及 QoS 等级,可以kubectl get pods -o custom-columns=NAME:.metadata.name,CPU:.spec.containers[*].resources.requests.cpu,MEM:.spec.containers[*].resources.requests.memory。这种自定义列输出是替代写脚本的最好方式,效率和可读性都很高。
Pod 的增删改查要注意一个点:直接kubectl delete pod <name>会让 Deployment 管理下的 Pod 自动重新创建,因为 ReplicaSet 会持续维持期望副本数。但如果你删除的是裸 Pod(没有控制器管理的),那它不会自动恢复。所以在做临时测试时,我通常会明确知道自己删的是什么资源类型,避免“删了之后怎么又起来了”或者“删了之后没起来”两种尴尬。
3. 参数详解:别只会加 -n 和 -o
3.1 常用输出格式 -o 与自定义列
kubectl 的-o参数真的是一个被严重低估的宝藏。基础用法有-o wide显示更多列,-o json和-o yaml输出结构化对象,-o name只输出资源名称,-o jsonpath可以对字段做精确提取。很多人只用到前两个,觉得够用就行了,但实际上-o jsonpath和-o custom-columns才是命令行排障的效率神器。
举个例子,我想知道某个 Deploy 管理的所有 Pod 的名称,用kubectl get pods -l app=nginx -o name就能拿到每行一个 pod/xxx 格式的结果,不用 grep 再去抠字段。如果想把 Pod 名称、所在节点、当前状态汇总成表格,可以用:
kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase这种方式非常直观,特别是节点有成百上千个 Pod 时,比-o wide默认输出更容易找到关键信息。JSONPath 更灵活,但语法也更容易出错。我总结一个经验:当你要在 bash 脚本里把命令输出赋值给变量时,优先用-o jsonpath配合--output后处理,因为返回的是纯文本,不会带多余的空格和表头。比如获取某个 Service 的 ClusterIP:
kubectl get svc nginx -o jsonpath='{.spec.clusterIP}'写 JSONPath 时,建议先跑kubectl get <resource> -o json看一眼整体结构,然后套路径,别凭感觉写。我们会经常踩两个坑:一是字段名大小写不对,K8s 的 JSON 字段基本都是驼峰;二是选择器把数组和对象弄混,比如.items[*].metadata.name是取多个资源名称,而.spec.containers[0].image是取第一个容器的镜像,中括号里的*和数字含义完全不同。
3.2 标签选择器与字段选择器
标签选择器-l是 kubectl 里最常见的过滤方式。K8s 的所有资源都可以打标签,所以-l app=nginx,env=prod这种组合可以精确定位一组资源。标签选择器支持=、!=、in、notin四种操作符,比如-l 'env in (prod,staging)'能选出两个环境的所有资源,这个写法在排查多环境问题时特别好用。不过要注意,标签不是随机加的,工作负载的 selector 一旦创建就不能改,否则 Deployment 会认为没有匹配的 Pod。所以设计标签体系时要提前规划,尽量包含业务、环境、版本、组件等维度。
字段选择器是--field-selector,它按资源对象的字段过滤,不是按标签。这俩经常被搞混,实际应用场景也不同。比如我想列出某个命名空间下所有 Failed 的 Pod:
kubectl get pods --field-selector=status.phase=Failed再比如列出所有在 control-plane 节点上的 Pod,可以结合节点名过滤:
kubectl get pods -A --field-selector=spec.nodeName=node-01-l和--field-selector可以同时使用,但要注意,field selector 不是所有字段都支持,最常见的支持字段包括metadata.name、metadata.namespace、spec.nodeName、status.phase、spec.schedulerName等,其他字段不可用时会直接报错。做批量清理时,我看过有人用--field-selector=status.phase=Succeeded一次性删掉所有已经跑完的 Job Pod,比手动一个个删高效得多。
3.3 常用命令的隐藏参数
有好几个参数平时不怎么被提到,但实际价值极大。第一个是--dry-run。kubectl apply -f deployment.yaml --dry-run=client只做本地校验,不会真的改集群;--dry-run=server会在服务端做校验,能提前发现资源冲突或 schema 问题。我以前写过不少 yaml,经常在 apply 之后被报 schema 错误,后来每次写完先跑一遍--dry-run=server,把绝大部分语法问题在发布前就拦下来了。
第二个是--validate=false。在用kubectl apply或者create某些资源时,如果希望跳过 schema 校验,可以带上它。比如从旧集群导出的 crd 资源可能字段略微过时,不兼容当前集群版本,先--validate=false导入再修复,比卡死在入口强。当然,不是所有的字段都能跳过去,服务端会拒绝真正非法的资源,这个参数更多是解决那种版本差异带来的“假报错”。
第三个是删除类参数组合。kubectl delete pod <name> --grace-period=0 --force可以强制立即删除。正常情况下,K8s 会给 Pod 先发 SIGTERM,等--grace-period默认 30 秒过后再发 SIGKILL,这在测试环境想快速回收卡住的 Pod 时很有用。但强制删除有风险,它绕过了一部分优雅终止逻辑,如果应用没实现好信号处理,可能会产生脏数据。我建议线上不要轻易用强制删除,先看日志和事件,确认是死锁或资源泄漏再决定。
还有一个被忽视的参数是kubectl get events --sort-by='.lastTimestamp'里的 sort-by。它按事件时间排序,把最近发生的问题排在最前面。默认输出按事件创建顺序排列,最新的事件反而不在最显眼的地方,加了这个排序,排查问题时的体验会好很多。
4. 排错与Debug:kubectl 不只是看日志
4.1 事件排查与describe使用技巧
当 Pod 卡在某个状态,比如一直 Pending、CrashLoopBackOff、ImagePullBackOff,第一件事就是看事件。kubectl describe pod <pod-name>会在 Events 区域列出所有和该 Pod 相关的事件,包括调度失败、拉取镜像失败、健康检查不通过、被驱逐等。describe 输出比较冗长,你只要盯着两个部分:Conditions 和 Events。Conditions 里看 Ready 是否是 True,如果 False 会有详细原因;Events 里看最下面的几条,时间越近越可能是直接原因。
describe不只适用于 Pod,对节点、Service、Deployment 都适用。kubectl describe node <node>可以看到节点资源压力、镜像缓存、被驱逐的 Pod 列表,以及集群证书过期时间。kubectl describe svc <service>可以查看 Endpoint 列表和负载均衡配置,如果 Service 后端 Pod 数量为 0,访问自然会失败。
事件虽然好用,但它有保留时间限制,默认一小时左右会被清理。所以出了问题别磨蹭,先立即抓事件。我平时会在脚本里把关键资源的事件追加到日志文件,实现简单的问题留痕。还有一个小技巧:kubectl get events --all-namespaces --sort-by=.lastTimestamp | tail -50可以在多命名空间环境里快速找到全局问题,比如某个节点的网络组件异常,事件会在所有命名空间里批量出现。
4.2 端口转发与exec交互
调试用的两大神器是kubectl exec和kubectl port-forward。kubectl exec -it <pod> -- /bin/sh进入容器,和 SSH 到服务器本质类似。进入容器后,你可以看进程、看网络、看环境变量,还可以直接 curl 内部端口。不过前提是容器镜像里得有 shell,如果用的是 distroless 镜像,没有 shell,那就需要kubectl cp或者临时用调试容器,比如kubectl debug。kubectl debug是后来加的能力,可以在目标 Pod 旁边启动一个附加容器,挂到同一个网络和进程命名空间,专门用来排障,非常灵活。
端口转发适合本地调试。kubectl port-forward svc/my-service 8080:80把本地 8080 端口映射到 Service 的 80 端口。这条命令在你不想暴露服务、又需要访问集群内部服务时特别有用。比如想连集群内的数据库调试,直接用 port-forward 到数据库 Service,然后本地用数据库客户端连 localhost,不用改配置、不用建跳板机。注意 port-forward 是长驻前台进程,命令行会被一直占用,可以加nohup或者放到后台。另外,端口转发只适合低流量调试,高并发场景应该走 Ingress 或 LoadBalancer,转发路径的性能瓶颈明显。
用 exec 调试时,我有个习惯:进入容器后先把时区、语言环境、代理变量都看一下,经常发现问题出在环境变量没传全。比如容器内应用连不上某个内部服务,先 exec 进去getent hosts my-service,如果解析不到,问题大概率不在应用代码,而在 DNS 或 Service 定义。
4.3 资源使用与节点诊断
查看工作负载资源消耗,kubectl top是最直接的命令。kubectl top node输出每个节点的 CPU 和内存使用率;kubectl top pod输出每个 Pod 的实时用量。但它的前提是你已经部署了 metrics-server 或类似的指标采集组件,否则会得到“Metrics API not available”的报错。没有指标组件时,我一般用kubectl describe node里的 Allocated resources 来看调度请求量,再用节点上的free、df等命令辅助判断。
节点诊断方面,kubectl get componentstatuses在旧版本里可以用来查看 etcd、kube-scheduler、kube-controller-manager 等核心组件的健康状态,但新版本里这个命令已经被弃用,推荐用kubectl get --raw='/healthz'或者直接访问各组件接口。你还可以用kubectl get nodes -o wide确认 kubelet 和容器运行时版本是否一致,版本不一致时,有时会出现容器运行时接口调用失败,导致节点 NotReady。
解除节点异常状态有一套固定流程。先确认节点是不是被cordon了,如果是,kubectl uncordon <node>恢复调度;如果节点因为资源压力 NotReady,需要先处理节点的磁盘或内存,再重启 kubelet;如果是 kubelet 崩溃,通常要登录到节点上systemctl status kubelet看日志,这已经超出 kubectl 范围,但仍然是日常诊断的一部分。
5. 实操总结:这套命令组合拳怎么用
5.1 场景一:服务无法访问
服务访问不通,我会按以下顺序排查:
# 1. 确认 Service 是否存在,以及它选择的 Pod kubectl get svc my-service -o yaml # 2. 查看 Service 的 Endpoint 是否有地址 kubectl get endpoints my-service # 3. 确认后端 Pod 状态 kubectl get pods -l app=my-app -o wide # 4. 查看最近事件 kubectl get events --sort-by=.lastTimestamp | grep my-service如果 Endpoint 为空,说明 Service 的 selector 没有匹配到任何 Pod,最常见的错误是 yaml 里标签写错,比如app: myapp写成app: my-app。如果 Endpoint 有地址但访问还是不通,可能问题出在 kube-proxy 或 CNI 网络插件。这时用kubectl exec进入某个 Pod,curl <ClusterIP>:<port>,看能否通。通不了就进一步检查 Service 的 targetPort 是否和 Pod 内容器监听端口一致。
5.2 场景二:Pod起不来
Pod 状态一直 Pending,我用kubectl describe pod <pod>查看事件,通常能看到调度失败的提示,比如节点资源不足、节点亲和性不满足、或者有污点没有容忍。处理方式也对应:扩容节点、修改资源请求、加 toleration。如果 Pod 状态是 CrashLoopBackOff,说明容器启动后立刻崩溃,看kubectl logs <pod> --previous拿到上一次容器的日志,很多应用在重启前会打印 panic 或错误堆栈。注意--previous只适用于容器已经重启过的情况。
如果 Pod 一直 ImagePullBackOff,用kubectl describe pod <pod>看事件,错误信息一般是拉取镜像超时或认证失败。检查镜像仓库地址是否写错、镜像标签是否存在、私有仓库的 imagePullSecret 是否正确配置。这里有个经验:镜像拉取失败的事件会被保留一段时间,但如果之前误填了不存在的镜像名,后续改了 yaml 再 apply,旧事件依然存在,别被旧事件干扰,看当前 Pod 的最近一次事件为准。
5.3 场景三:批量清理资源
日常开发中经常要清理测试环境。比如清理所有 completed 的 Job,使用 field selector 可以一步到位:
kubectl delete jobs --field-selector=status.successful=1清理所有处于 Evicted 状态的 Pod:
kubectl delete pods --field-selector=status.phase=Failed如果要按命名空间整体清理但保留命名空间本身,可以用kubectl delete all --all -n <ns>。这个命令会删除该命名空间下所有常用资源类型,包括 Pod、Service、Deployment、ConfigMap 等。注意它不会删除 PersistentVolumeClaim 和 Secret,所以在清理测试环境时,还要手动确认有没有要保留的数据卷。批量清理前,我强烈建议先加--dry-run=client看一眼影响范围,避免误删。
6. 常见坑与经验
6.1 两个容易忽略的权限坑
一个是 kubectl 的权限来自 kubeconfig 中的用户凭证,你当前 context 指向的凭证决定了你能操作哪些资源。如果你在生产环境切换到只读的 ServiceAccount,却还在跑kubectl delete,会收到 forbidden 报错。这个报错本身会让人误以为集群出问题了,其实只是 RBAC 权限不足。排查这种事最快的方式是kubectl auth can-i delete pods,它会直接告诉你当前用户有没有对应权限。
另一个坑是 kubectl 的版本和集群版本不是严格匹配也没关系,只要版本差不太远都能工作。但反过来,插件或 CRD 需要版本兼容时,就会出幺蛾子。如果你本地 kubectl 版本太旧,打出来的资源结构可能缺失新字段,--validate=false可以一部分缓解,但最好还是保持 kubectl 版本在 API 支持范围内。
6.2 别把连接信息写死在命令里
有人喜欢把集群地址和 token 直接写在 kubectl 命令里,比如kubectl --server=https://... --token=... get pods。这在临时联调时可以,但长期用会带来安全和维护双重问题。正确做法是把连接信息放进 kubeconfig 的 context 中,再通过别名来回切换。我用 alias 把各个环境封装成简单命令,比如alias k-prod='kubectl config use-context prod-k8s',这样不仅操作方便,还能避免因环境切换失败导致连错集群。
6.3 让输出变成脚本可用的格式
写自动化脚本时,避免解析kubectl get的默认文本输出。默认输出是给人看的,列对齐、空格多、表头干扰,脚本解析容易崩。要使用-o jsonpath、-o custom-columns或者-o name让输出干净简单。比如我要取所有失败 Pod 的名字做批量删除,可以写成:
kubectl get pods --all-namespaces --field-selector=status.phase=Failed -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}'这里range和end是 jsonpath 的循环语法,输出两列:命名空间和 Pod 名称,再用 awk 处理。这个模式我在很多自动化脚本里反复用,基本不会出错。
6.4 善用 shell 别名和函数
kubectl 命令很长,别名能减少很多输入。我自己的 bashrc 里长期躺着这几个:
alias k='kubectl' alias kg='kubectl get' alias kd='kubectl describe' alias kl='kubectl logs' alias kx='kubectl exec -it' alias kgp='kubectl get pods' alias kgpa='kubectl get pods --all-namespaces'再加一个函数,快速进入某个 Pod:
ksh() { kubectl exec -it "$1" -- /bin/sh; }用起来就是ksh pod-name,清爽很多。但别把命令藏得太深,至少你自己一个月后回来还能看懂这些缩写是什么,不然脚本维护成本反而上升。
最后再分享一个小经验。我刚开始用 K8s 时特别喜欢堆命令,一条命令恨不得把全部信息都打出来,后来发现格式化输出+精确过滤才是王道。大部分排查场景根本不需要那么多输出,你真正要找的是那个“不同点”。先把集群基线摸清楚,比如节点资源、常见镜像版本、主要命名空间列表,出了问题再对照基线去看差异,比每次都从头看一遍整个集群状态高效得多。这份速查表里的命令,都是我从那几趟折腾里沉淀下来的,希望对你也有用。