干了这么多年 Kubernetes 运维,我最依赖的命令行工具始终是 kubectl。这不是情怀,而是现实:图形界面和自研平台再好用,到了生产环境要定位问题,最后还是要掏终端,敲一条 get、一条 describe、一把 logs,把最原始的返回结果拿在手里。今天这篇就把 kubectl 常用命令按实战需求从头捋一遍,覆盖日常查询、发布变更、故障排查和提效技巧。不管你刚接触 K8s 不久,还是已经被各种 YAML 折腾过几轮,这篇文章都适合。我会按我自己的使用频率来排优先级,尽量告诉你每个命令什么时候用、用什么参数、输出怎么看,也会穿插一些我踩过的坑。你会发现 kubectl 本质上不复杂,复杂的是不知道它给了你多少把钥匙。
1. 先搞懂 kubectl 在跟谁说话
1.1 一条命令背后的架构映射
kubectl 不是 Kubernetes 本身,它只是一个客户端,所有命令最终都会转换成 HTTP 请求发给 API Server。理解这一点很重要,因为很多“命令不生效”的问题,根子都在认证、权限、网络连通性上。API Server 是集群的“大管家”,kubectl 相当于你手里的一张门禁卡,卡片上写着你属于哪个用户、能进哪些房间。命令能执行,不代表你有权限看到所有数据;看不到数据,也不代表资源不存在。
所以在学命令之前,先记住一个检查顺序:kubectl 能否连接集群,要看 kubeconfig;能否操作资源,要看 RBAC;能否拿到预期结果,要看资源自身的状态。这样后续排查时就不会在一条命令里瞎试。实际运维中我最常犯的错误,是换了一个环境忘了切 context,结果对着测试集群查了半天生产问题。为了避免这种低级失误,我习惯在 shell 提示符里把当前 context 和 namespace 显示出来,时刻提醒自己在哪。
kubectl cluster-info # 查看控制面地址 kubectl version # 查看客户端和服务端版本 kubectl config current-context # 查看当前上下文1.2 kubeconfig、context 与 namespace 三件套
kubectl 默认从 $HOME/.kube/config 读取配置。配置里通常有多个 cluster、多个 user,把某个 cluster 和某个 user 组合在一起,就形成一个 context。同一个 kubeconfig 文件里可以放开发、测试、生产多个集群的信息,切换起来非常方便。我自己的习惯是给每个环境单独一个文件,然后通过 KUBECONFIG 环境变量把它们串起来,避免把所有账号混在一个文件里。
export KUBECONFIG=~/.kube/dev-config:~/.kube/prod-config kubectl config get-contexts # 列出所有上下文 kubectl config use-context prod # 切到生产上下文 kubectl config set-context --current --namespace=your-ns最后一条命令很常用,它直接把当前上下文的默认命名空间改掉,避免后续每次操作都要在后面加-n xxx。这里有一个隐蔽的坑:切换 context 后,权限是跟着 user 走的,user 没有权限时命令虽然能连通 API Server,但返回的是 Forbidden。你以为是网络问题或资源不存在,其实只是 RBAC 没放行。所以在排错顺序里,权限检查要放在非常靠前的位置。
1.3 先记住这组查询命令,其他都好说
如果只允许记一组 kubectl 命令,我建议先记 get、describe、logs。这三个命令覆盖了绝大多数日常查询场景。get 负责列表概览,describe 负责对象详情,logs 负责容器日志。把它们用熟了,再学别的命令会顺手很多。
| 命令 | 用途 | 典型场景 |
|---|---|---|
| kubectl get | 列表概览 | 看 Pod 是否 Running、看节点状态 |
| kubectl describe | 详情描述 | Pod 起不来时看事件和状态详情 |
| kubectl logs | 容器日志 | 应用报错时看输出的异常栈 |
kubectl get pods -o wide能显示节点 IP 和 Pod IP,比默认输出多了不少信息;kubectl get pods -w可以实时监听资源变化,发布的时候开一个窗口盯着十分方便。很多人一上来喜欢研究高级参数,反而忽略了这三个基础命令的威力。我自己排查问题时,80% 的时间只是在反复用 get、describe、logs 这三种姿势。
2. 日常操作命令:从查询到进入 Pod
2.1 查询命令的各自分工
get 是高频中的高频,常用变体很多。比如kubectl get pods -n kube-system查看系统组件,kubectl get nodes -o wide查看节点内网 IP、内核版本、容器运行时版本。更灵活的是它支持一次查多种资源:kubectl get deploy,svc,ing -n app。参数拼错了或者资源不存在,命令会返回非 0 退出码,但要注意“查不到”和“没权限”是两回事,前者通常返回正常退出码,后者会直接打印 Forbidden。
describe 适合看单对象。kubectl describe pod my-pod-xxxx会输出标签、注解、调度结果、容器状态、探针配置,最下面还有一个 Events 段,这是定位问题的第一现场。比如 Pod 卡在 Pending,describe 里的事件会写清楚“0/1 nodes are available”以及具体是资源不足、端口冲突还是污点不匹配。logs 就简单直接,拉容器标准输出。如果 Pod 内有多个容器,必须加-c指定容器名,否则会报错。
kubectl logs -f pod_name -c container_name kubectl logs --previous pod_name -c container_name--previous可以查看上一次容器的输出,对 CrashLoopBackOff 这类反复重启的问题特别有价值。因为容器每次崩溃都会重启,当前日志可能只有启动几秒的内容,上一次日志里往往藏着真正的异常栈。配合--tail=100限制行数,日志量大的时候不会把终端刷爆。
2.2 进入 Pod 与数据拷贝:exec、cp、port-forward
进入容器调试是绕不开的需求。kubectl exec -it pod_name -- bash是最常用的方式。有些精简镜像没有 bash,只有 sh,可以换成-- sh。如果连 sh 都没有,说明镜像用 scratch 构建,只能通过kubectl debug注入调试容器,这在后面会单独讲。exec 进入后,先用ps、netstat、cat /proc/1/cmdline确认进程状态,别一上来就看日志,很多时候是进程启动参数不对。
kubectl cp用于把文件拷进拷出,但底层依赖 exec 和 tar,Pod 里没有 tar 命令时它就会失败。遇到“tar: not found”不必硬扛,可以用kubectl exec配合管道实现文件读取。比如把远程日志捞到本地:
kubectl exec pod_name -- cat /var/log/app.log > app.logport-forward 是本地调试利器。kubectl port-forward svc/xxx 8080:80会把本地 8080 端口映射到服务的 80 端口,适合临时访问数据库管理页面、调试接口。需要注意的是它是一个前台进程,会一直占着终端,调试完用 Ctrl+C 结束即可。如果是远端服务器,通常会搭配 SSH 隧道一起用,但这块和 kubectl 本身无关,我就不展开讲了。
2.3 按 label 和字段筛选:过滤才是高效的关键
生产环境 Pod 数量一多,一条裸的kubectl get pods会刷出几百行结果,真正的关键信息全被淹没在滚动输出里。这时就要善用 label selector。kubectl get pods -l app=web,env=prod可以精确匹配多组标签,把范围快速缩小到某次发布所涉及的 Pod。标签是自己设计的分组维度,设计得好不好直接决定筛选是否顺手。我见过不少团队在 YAML 里乱写标签,后面只能靠 pod 名猜归属,排查效率非常低。
除了标签,还可以用--field-selector按字段过滤。比如只看调度到某个节点上的 Pod:
kubectl get pods --field-selector spec.nodeName=node-01再比如只看某个状态阶段的 Pod:
kubectl get pods --field-selector status.phase=Running这类过滤在写运维脚本时特别有用,可以避免把无关资源拉回来再做二次处理。我经常在脚本里组合-l和--field-selector,把目标资源定位到很小范围,后续的循环和处理都会快很多。过滤条件写得越精确,排错时的心智负担越小。
3. 应用发布与变更:用命令走完一次完整流程
3.1 创建与声明式更新:create、apply、delete 的区别
kubectl create 和 kubectl apply 是两种不同思路。create 是命令式创建,文件里有就创建,重复执行会报 AlreadyExists,适合初始化临时资源时用。apply 是声明式更新,文件里没有则创建,有则根据本地文件和集群现状做差异计算,只更新变更的部分。生产环境我基本只用 apply,因为它符合“把 YAML 作为唯一事实来源”的理念,后续回滚和审计也方便。
kubectl apply -f deployment.yaml kubectl delete -f deployment.yamldelete 要特别小心。尤其是加了--grace-period=0 --force的强制删除,会让 API Server 跳过很多优雅终止流程,可能造成资源残留。一般只在 namespace 卡在 Terminating、finalizer 一直删不掉的时候才考虑用。普通场景想删掉一个 Deployment,直接kubectl delete deployment app就好,控制器会处理剩余的事情。如果你只想缩容,千万别用 delete 去删 Pod,正确的做法是kubectl scale deployment app --replicas=0。
3.2 一次滚动发布中必用的命令与参数
Deployment 是最常见的发布载体。发布时可以整体应用新 YAML,也可以只改镜像。整体应用适合配置有较多改动的场景,只改镜像适合快速升级版本。两条路线都会触发滚动更新,控制器会逐个替换 Pod,新 Pod 通过了 readiness 探针才会继续下一个。
kubectl apply -f deploy-app-v2.yaml kubectl rollout status deployment/app或者只改镜像:
kubectl set image deployment/app app=registry.example.com/app:v2 kubectl rollout status deployment/approllout status会一直阻塞到发布完成或超时。这里的超时很值得注意,新 Pod 一直没 Ready 时命令会卡住,并不代表发布一定失败,而是 controller 在等待你的探针反馈。此时应该另开终端去 describe Pod,看事件里探针是否失败、镜像是否能拉取、调度是否成功。我用这个命令时还有个习惯:发布前先开一个kubectl get pods -w窗口,实时看 Pod 状态变化。
3.3 发布后的验证、回滚与资源清理
发布完成的验证不能只看 Pod 状态。kubectl get pods显示 Running 只说明容器起来了,不代表服务可用。要确认 endpoints 是否正常,服务是否真的把流量分发到了新副本:
kubectl get endpoints -n app kubectl get pod -l app=web -o wide如果发现新版本有问题,回滚操作要越快越好。回滚到上一个版本:
kubectl rollout undo deployment/app回滚到指定版本:
kubectl rollout history deployment/app kubectl rollout undo deployment/app --to-revision=2清理资源时最容易翻车的操作是误删 namespace。namespace 一旦删除,会连带删除其下所有资源,而且如果里面还有自定义资源挂着 finalizer,namespace 会一直卡在 Terminating。这时候可以先导出 namespace 的 JSON,手动把 finalizer 字段清掉再更新。这个方法能解决多数“删不干净”的问题,但操作风险很高,建议先在测试环境演练熟再上生产。
4. 故障排查:把现场证据完整捞出来
4.1 第一步永远看 events
Pod 启动不了,很多人第一反应是看日志,但实例都没起来时,logs 往往是空的。镜像还在拉取,容器还没创建,什么日志都看不到。正确的第一件事是kubectl describe pod xxx,它输出的 Events 段会写清楚调度失败原因、镜像拉取失败原因、探针失败原因。如果 describe 的信息不够,还可以直接查事件:
kubectl get events --sort-by=.lastTimestamp kubectl get events -A --sort-by=.lastTimestamp-A会看所有命名空间,适合节点组件异常或自定义控制器报错的场景。Event 里常出现的错误有:0/1 nodes are available表示调度失败,具体原因可能是节点资源不足或污点不匹配;ImagePullBackOff表示镜像拉取失败,需要检查镜像地址、标签和拉取凭证;CrashLoopBackOff表示容器启动后反复崩溃,要把重点放到应用启动日志上。这些关键词基本把问题范围圈定了。
4.2 从 Pod 状态反查故障根因
要快速定位问题,就得把常见的 Pod 状态和对应根因对上。下面是一张我自己整理的速查表。
| Pod 状态 | 常见原因 | 第一排查动作 |
|---|---|---|
| Pending | 资源不足、污点、PVC 未绑定 | describe 看调度事件 |
| ContainerCreating | 镜像拉取慢、存储卷挂载失败 | describe 看容器事件 |
| Running 但不 Ready | readiness 探针失败、进程未就绪 | 看日志、进入容器检查 |
| CrashLoopBackOff | 启动命令错误、依赖缺失、配置异常 | 用--previous看上次日志 |
| Terminating 卡住 | 容器忽略退出信号、存储卷占用 | 确认业务可断后强制删除 |
Pending 状态优先检查调度器。describe 里那句FailedScheduling会直接告诉你哪些节点不满足条件,比如 CPU 不足、端口已被占用、或者节点上有无法容忍的污点。ContainerCreating 卡住,常见的是大镜像拉取慢或 PVC 挂载不上。Running 但不 Ready,多半是 readiness 探针配置太严格,可以通过kubectl describe看探针的失败次数。每次排查时,我都会按“调度-容器-探针-日志”这个顺序走,而不是随便翻一个状态就开始猜。
4.3 集群层面诊断:top、api-resources、auth can-i
单看 Pod 有时候不够,还需要从集群视角判断。kubectl top node和kubectl top pod用于查看资源使用情况,但需要集群里部署了 metrics-server,没有的话命令会直接报错。资源使用数据对判断节点是否需要扩容、Pod 是否被限流很有帮助。kubectl api-resources可以列出集群当前支持的所有资源类型,写 YAML 时想不起某个资源的简称,用它查一下最方便。
kubectl top node kubectl top pod -n app kubectl api-resources | grep pod kubectl explain deployment.spec.replicaskubectl auth can-i是验证权限的快捷方式。比如想确认当前用户能不能创建 Deployment:
kubectl auth can-i create deployments如果返回 yes,说明权限没问题;返回 no,说明 RBAC 限制了操作。这种方式比对照角色定义猜快得多,尤其在排查“为什么 apply 没生效”的时候,先用它排除权限因素。
还有一个被低估的命令是kubectl debug。Pod 里没有调试工具时,可以临时注入一个调试容器:
kubectl debug node/node-01 -it --image=busybox这条命令会在目标节点上启动一个临时容器,挂载宿主文件系统,方便检查节点上的日志、进程、磁盘情况。虽然平时不常用,但遇到节点异常时它是救急利器。
5. 高效使用 kubectl 的实战习惯
5.1 自动补全与别名,省下的时间超乎想象
命令敲得越多,越觉得自动补全和别名是刚需。bash 和 zsh 都支持 kubectl 补全,执行一次配置写到 shell 配置里,以后按 Tab 就能补资源名和命令参数,省下大量记忆功夫。
source <(kubectl completion bash) source <(kubectl completion zsh)我自己的别名配置也很简单,核心就是缩短高频命令:
alias k='kubectl' alias kgp='kubectl get pods' alias kgpa='kubectl get pods -A' alias kd='kubectl describe' alias kl='kubectl logs' alias kg='kubectl get'有了别名之后,日常操作从敲一长串命令变成两三个字母,效率提升非常明显。有人会把kgp直接定义为kubectl get pods -o wide,这样 IP、节点信息默认就显示出来,我试过之后就一直这么用了。
5.2 自定义输出格式:-o jsonpath 和自定义列
默认输出适合人看,但脚本和自动化的场景需要精确提取字段。-o json配合 jq 是灵活度最高的组合。比如提取某个 Pod 的当前阶段:
kubectl get pod my-pod -o json | jq '.status.phase'如果不想安装 jq,也可以直接用 jsonpath。下面这个命令把 label 为 app=web 的所有 Pod 名字逐行输出:
kubectl get pods -l app=web -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'还有 custom-columns 方式,适合生成好看的表格:
kubectl get pods -o custom-columns=NAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeNamejsonpath 的写法看起来怪,但掌握几个常用的.metadata.name、.status.phase、.spec.nodeName就够用了。复杂逻辑我更推荐用 jq,嵌套太深的 jsonpath 容易把人绕晕。
5.3 多集群、多上下文管理的一些方法
维护多套环境是常态,我常用的方式就是前面提到的 KUBECONFIG 环境变量。把多个配置文件合并成搜索路径后,用kubectl config get-contexts查看所有上下文,再用kubectl config use-context切换。给每个 context 设置固定 namespace,可以避免切换后忘加-n导致查错资源:
kubectl config set-context prod --namespace=prod kubectl config set-context dev --namespace=dev配置多了以后,我会写一个 shell 函数,让 Tab 能补全 context 名称,同时在提示符里显示当前 context,时刻提醒自己在哪。这个方法不依赖任何第三方工具,纯 kubectl 原生功能就能满足日常多集群管理。减少工具链就是减少额外的学习成本和故障点。
5.4 我踩过的几个 kubectl 相关的坑
最后分享几个印象深刻的坑。第一个是“Pod 删不掉”的假象。直接删 Deployment 管理的 Pod,确实会触发控制器立刻补一个新的,表面上看起来一直是 Running,实际上根本不需要手动删。正确的操作是先缩容:kubectl scale deployment app --replicas=0。
第二个是 logs 把终端刷爆。应用日志量大时,直接kubectl logs -f会瞬间刷掉大量历史输出,连滚动都来不及看。先用--tail=100限制末尾行数,再加-f跟进,信息密度会舒服很多。
第三个是“No resources found”误导排错。在某个 namespace 里查不到 Pod,不一定是没部署,有可能是 context 默认 namespace 不对,或者 RBAC 没有列出的权限。先把 namespace 参数显式写出来,再确认kubectl get ns是否有权限,能少走很多弯路。
第四个是 apply 了但资源没变化。不要只看输出里的configured,先跑一遍kubectl diff -f file.yaml,看看本地 YAML 和集群现状到底差在哪里。这个命令在发布前非常值得养成习惯,能提前暴露“我以为改了”但实际没改的问题。
从最开始只会敲 get、logs,到现在能在一堆输出里快速定位问题,我最大的体会是:kubectl 不需要记全部命令,但一定要理解每一条命令背后对应的资源对象和 API 行为。真正的高效不是背命令,而是知道用什么命令去验证你的假设。遇到奇怪现象时,按“通信-权限-事件-日志”的顺序拆一遍,大多数时候都能找到答案。希望这篇梳理对你有用,少踩几个我当年踩过的坑。