上一章是实战练习。本章把专栏前 13 章用到的命令整理成一份可收藏的工具箱,按场景分类,复制即用。
适合场景:上班时突然线上告警,你需要在 30 秒内定位到是哪个 Pod、哪个节点、哪个容器出了问题。
阅读约定
本章所有命令上方都有一行 # 对象:xxx 的注释,明确这条命令操作的是哪类资源。看到 # 对象:Pod 就知道 <pod-name> 要填 Pod 名字,看到 # 对象:Node 就知道要填节点名。
示例资源命名约定:
| 示例名 | 资源类型 |
|---|---|
k8s-m1 / k8s-w1 | Node(节点) |
web-xxx / nginx-xxx | Pod(带 RS 后缀的实例) |
web / api-deploy | Deployment |
web-svc / api-svc | Service |
db-sts / redis-sts | StatefulSet |
data-pvc | PersistentVolumeClaim |
app-cfg / db-pass | ConfigMap / Secret |
web-hpa | HorizontalPodAutoscaler |
web-ing | Ingress |
14.1 命令太长?可选的效率工具(非必须)
本章所有命令都基于标准 kubectl,在 Linux 服务器上直接可用。
但日常敲 kubectl get pods -n kube-system 这种长命令会很累。如果你愿意,可以配置 alias 或安装 kubectx 系列工具提升效率:
# 给 ~/.bashrc 加几个常用 alias(可选)
alias k='kubectl'
alias kgp='kubectl get pods'
alias kl='kubectl logs'
# 自动补全(推荐)
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source ~/.bashrc
# kubectx / kubens:一条命令切换集群和命名空间(可选)
sudo git clone https://github.com/ahmetb/kubectx /opt/kubectx
sudo ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
sudo ln -s /opt/kubectx/kubens /usr/local/bin/kubens
配置好后,下面这些命令等价:
# 完整写法(本章统一用这种)
$ kubectl get pods -n kube-system
# 配了 alias + kubens 之后
$ kubens kube-system
$ k get pods
本章后续所有示例都使用完整的 kubectl 命令,方便直接复制到任何 Linux 服务器上执行。
14.2 集群与节点巡检
早会前 30 秒,快速判断集群是否健康。
# 对象:Node —— 列出集群所有节点,看 STATUS 列是否有 NotReady
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE
k8s-m1 Ready control-plane 90d v1.29.4 10.0.0.11 Ubuntu 22.04
k8s-w1 Ready <none> 90d v1.29.4 10.0.0.12 Ubuntu 22.04
k8s-w2 Ready <none> 90d v1.29.4 10.0.0.13 Ubuntu 22.04
# 对象:Node —— 看每个节点 CPU / 内存实时用量(依赖 Metrics Server)
$ kubectl top nodes
# 对象:Node —— 看节点 k8s-w1 的 Conditions(DiskPressure / MemoryPressure / PIDPressure)
$ kubectl describe node k8s-w1 | grep -A5 Conditions
# 对象:控制面 —— 检查 API Server / etcd / Scheduler / ControllerManager 是否就绪
$ kubectl get --raw='/readyz?verbose'
# 对象:Pod(系统组件)—— 列出 kube-system 命名空间下的所有系统 Pod
$ kubectl -n kube-system get pods
常见坑:
- 节点
NotReady→ 先看kubectl describe node k8s-w1最底部的 Events - 节点磁盘满 →
DiskPressure=True,需要清理镜像:crictl rmi --prune - 证书到期 →
kubectl get csr,或kubeadm certs check-expiration
14.3 Pod:日常操作 90% 都在这里
14.3.1 查
# 对象:Pod —— 列出当前命名空间下所有 Pod,-o wide 多看 IP 和所在节点
$ kubectl get pods -o wide
# 对象:Pod —— 全集群范围(所有命名空间)找名字带 nginx 的 Pod
$ kubectl get pods -A | grep nginx
# 对象:Pod —— 按 label 过滤(找 app=web 的所有 Pod)
$ kubectl get pods -l app=web
# 对象:Pod —— 多 label 组合(app 是 web 或 api,且 tier=frontend)
$ kubectl get pods -l 'app in (web,api),tier=frontend'
# 对象:Pod —— 只看跑在节点 k8s-w1 上的 Pod(按字段过滤)
$ kubectl get pods --field-selector spec.nodeName=k8s-w1
# 对象:Pod —— 全集群找非 Running 状态的 Pod(排查异常的入口)
$ kubectl get pods -A --field-selector=status.phase!=Running
# 对象:Pod —— 全集群找非 Running / 非 Completed 的 Pod(更常用的过滤)
$ kubectl get pods -A | grep -vE 'Running|Completed'
# 对象:Pod —— 按容器重启次数排序(找出不稳定的 Pod)
$ kubectl get pods -A --sort-by='.status.containerStatuses[0].restartCount'
# 对象:Pod —— 持续观察当前命名空间的 Pod 变化(Ctrl+C 退出)
$ kubectl get pods -w
# 对象:Pod —— 每 2 秒刷新一次(watch 是 Linux 命令)
$ watch -n 2 kubectl get pods
14.3.2 看日志
# 对象:Pod —— 看 Pod web-xxx 当前容器的日志
$ kubectl logs web-xxx
# 对象:Pod —— 持续跟踪 Pod web-xxx 的日志(类似 tail -f)
$ kubectl logs -f web-xxx
# 对象:Pod 内的某个 Container —— 多容器 Pod 必须用 -c 指定容器名
$ kubectl logs web-xxx -c sidecar
# 对象:Pod —— 看上一次崩溃前的日志(排查 CrashLoopBackOff 神器)
$ kubectl logs web-xxx --previous
# 对象:Pod —— 最近 1 小时 + 最后 200 行
$ kubectl logs web-xxx --since=1h --tail=200
# 对象:Pod —— 日志带时间戳
$ kubectl logs web-xxx --timestamps
# 对象:一组 Pod —— 按 label 一次拉多个 Pod 的日志
$ kubectl logs -l app=web --all-containers --tail=100
# 对象:一组 Pod —— 用 stern 实时跟踪名字带 web 前缀的所有 Pod
# Linux 安装 stern:
$ wget https://github.com/stern/stern/releases/latest/download/stern_linux_amd64.tar.gz
$ tar -xzf stern_linux_amd64.tar.gz && sudo mv stern /usr/local/bin/
$ stern web -n production
14.3.3 进容器 & 临时调试
# 对象:Pod 内的容器 —— 进入 Pod web-xxx 的默认容器
$ kubectl exec -it web-xxx -- /bin/sh
# 对象:Pod 内的容器 —— 进入 Pod web-xxx 里名为 sidecar 的容器
$ kubectl exec -it web-xxx -c sidecar -- /bin/bash
# 对象:Pod 内的容器 —— 不进容器,直接执行一条命令拿结果
$ kubectl exec web-xxx -- cat /etc/nginx/nginx.conf
# 对象:Pod —— 容器里没有 shell 也没有 curl?注入一个临时 debug 容器
# --target 指定要共享哪个容器的进程命名空间
$ kubectl debug -it web-xxx --image=busybox:1.31 --target=app
# 对象:Pod ↔ 本地 —— 双向复制文件
$ kubectl cp web-xxx:/var/log/nginx/access.log ./access.log
$ kubectl cp ./local.conf web-xxx:/etc/nginx/conf.d/local.conf
14.3.4 看事件(排查调度/拉镜像失败的真相)
# 对象:Event —— 看当前命名空间最近事件,按时间排序
$ kubectl get events --sort-by=.lastTimestamp
# 对象:Event —— 只看 Warning 类型的事件
$ kubectl get events --field-selector type=Warning
# 对象:Pod —— 看 Pod web-xxx 的完整描述,最后 30 行就是事件
$ kubectl describe pod web-xxx | tail -30
90% 的 Pod 起不来,看 events 就够了:镜像拉不下来 / 资源不够 / 探针失败 / 卷挂载超时,全在这里。
14.4 Deployment:发布与回滚
# 对象:Deployment —— 列出当前命名空间所有 Deployment 及副本状态
$ kubectl get deploy
# 对象:Deployment —— 看 Deployment api-deploy 的详细信息
$ kubectl get deploy api-deploy -o wide
# 对象:ReplicaSet —— 看 label 是 app=api 的所有 RS(理解 Deployment → RS → Pod 链路)
$ kubectl get rs -l app=api
# 对象:Deployment —— 把 api-deploy 副本数改成 5
$ kubectl scale deploy api-deploy --replicas=5
# 对象:Deployment —— 把 api-deploy 里 api 容器的镜像更新到 v1.2.3(触发滚动更新)
$ kubectl set image deploy/api-deploy api=myrepo/api:v1.2.3
# 对象:Deployment —— 观察 api-deploy 这次发布的进度(直到完成或失败)
$ kubectl rollout status deploy/api-deploy
# 对象:Deployment —— 看 api-deploy 的历史发布版本
$ kubectl rollout history deploy/api-deploy
# 对象:Deployment —— 看 api-deploy 第 3 个版本改了什么
$ kubectl rollout history deploy/api-deploy --revision=3
# 对象:Deployment —— 回滚到上一个版本
$ kubectl rollout undo deploy/api-deploy
# 对象:Deployment —— 回滚到指定版本
$ kubectl rollout undo deploy/api-deploy --to-revision=2
# 对象:Deployment —— 暂停发布(金丝雀手动分批用)
$ kubectl rollout pause deploy/api-deploy
# 对象:Deployment —— 恢复发布
$ kubectl rollout resume deploy/api-deploy
# 对象:Deployment —— 强制重建所有 Pod(不换镜像,只想重启)
$ kubectl rollout restart deploy/api-deploy
# 对象:Deployment —— 直接编辑 etcd 里的 spec(生产慎用)
$ kubectl edit deploy api-deploy
生产建议:
- 永远用
kubectl set image或改 YAML +apply,不要用kubectl edit改线上 rollout restart是最常用的"重启大法",比删 Pod 优雅
14.5 Service 与网络排障
服务不通时,按下面顺序排查:
# 对象:Service —— 看 Service web-svc 是否存在
$ kubectl get svc web-svc
# 对象:Service —— 看 Service web-svc 的 selector 配置
$ kubectl describe svc web-svc | grep Selector
# 对象:Endpoints —— 看 Service web-svc 后端有哪些 Pod IP(最常见根因:<none>)
$ kubectl get endpoints web-svc
NAME ENDPOINTS AGE
web-svc 10.244.1.15:80,10.244.2.18:80,10.244.3.20:80 5d
# 对象:Pod —— 列出 label app=web 的所有 Pod 及其完整 label 集合
# 用来核对 Service 的 selector 是否真的匹配到 Pod
$ kubectl get pods --show-labels -l app=web
# 对象:临时 Pod —— 起一个临时 busybox 容器,进集群里测网络
$ kubectl run tmp --rm -it --image=busybox:1.31 -- sh
/ # wget -qO- http://web-svc # 测 HTTP 通不通
/ # nslookup web-svc.default.svc.cluster.local # 测 DNS 解析
# 对象:Pod(CoreDNS)—— 看 CoreDNS 系统 Pod 状态
$ kubectl -n kube-system get pods -l k8s-app=kube-dns
# 对象:Pod(CoreDNS)—— 看 CoreDNS 日志(DNS 解析失败时排查)
$ kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
# 对象:NetworkPolicy —— 列出所有命名空间的网络策略
$ kubectl get networkpolicy -A
# 对象:NetworkPolicy —— 看具体某条网络策略的规则
$ kubectl describe networkpolicy <policy-name>
完整 DNS 命名规则(背下来):
# Service 的 DNS
<service-name>.<namespace>.svc.cluster.local
# StatefulSet Pod 的 DNS(按 Pod 名稳定访问)
<pod-name>.<headless-service-name>.<namespace>.svc.cluster.local
14.6 ConfigMap 与 Secret
# 对象:ConfigMap —— 三种创建方式
$ kubectl create configmap app-cfg --from-literal=LOG_LEVEL=debug
$ kubectl create configmap app-cfg --from-file=nginx.conf
$ kubectl create configmap app-cfg --from-env-file=.env
# 对象:Secret —— 创建通用类型 Secret
$ kubectl create secret generic db-pass --from-literal=password=123456
# 对象:Secret —— 创建 TLS 类型 Secret(给 Ingress 用)
$ kubectl create secret tls my-tls --cert=tls.crt --key=tls.key
# 对象:ConfigMap —— 查看 ConfigMap app-cfg 的完整内容
$ kubectl get cm app-cfg -o yaml
# 对象:Secret —— 查看 Secret db-pass 的内容(base64 编码后的)
$ kubectl get secret db-pass -o yaml
# 对象:Secret —— 取出 Secret db-pass 里的 password 字段并 base64 解码
# 注意:base64 是编码不是加密,任何能读 Secret 的人都能解出来
$ kubectl get secret db-pass -o jsonpath='{.data.password}' | base64 -d
# 对象:Deployment —— 改了 ConfigMap 之后 Pod 不会自动重启,需要手动重启 Deployment
$ kubectl rollout restart deploy/api-deploy
14.7 存储:PV / PVC
# 对象:PVC —— 列出当前命名空间所有 PVC,看 STATUS 是否 Bound
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY STORAGECLASS
data-pvc Bound pv-abc 10Gi alicloud-ssd
# 对象:PVC —— PVC 卡在 Pending 时,看 Events 找原因
$ kubectl describe pvc data-pvc
# 对象:PV —— 列出集群里所有 PV
$ kubectl get pv
# 对象:PV —— 看具体某个 PV 的详情(回收策略、绑定关系)
$ kubectl describe pv pv-abc
# 对象:StorageClass —— 列出集群里所有存储类
$ kubectl get sc
14.8 HPA 与资源
# 对象:HPA —— 列出当前命名空间所有 HPA,看目标 / 当前 / 期望副本
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
web-hpa Deployment/api-deploy 35%/50% 2 10 4
# 对象:Pod —— 看所有 Pod 的 CPU / 内存实时用量
$ kubectl top pods
# 对象:Pod 内的 Container —— 看每个容器的资源用量(多容器 Pod 用)
$ kubectl top pods --containers
# 对象:Pod —— 按内存排序,找内存大户
$ kubectl top pods --sort-by=memory
# 对象:HPA —— 编辑 HPA web-hpa(调阈值、副本上下限)
$ kubectl edit hpa web-hpa
14.9 端口转发与本地调试
# 对象:Service —— 把 Service web-svc 的 80 端口转发到本机 8080
$ kubectl port-forward svc/web-svc 8080:80
# 对象:Pod —— 把 Pod web-xxx 的 80 端口转发到本机 8080(绕过 Service 直接连 Pod)
$ kubectl port-forward web-xxx 8080:80
# 对象:Service —— 后台转发,一次起多个(数据库 / 缓存本地调试用)
$ kubectl port-forward svc/web-svc 8080:80 &
$ kubectl port-forward svc/db-svc 5432:5432 &
# 之后访问本机 127.0.0.1:8080 即访问到集群里的 web-svc:80
数据库本地调试神器:把 RDS / Redis 通过 port-forward 暴露到本机,本地代码直连。
14.10 标签与注解
# 对象:Pod —— 给 Pod web-xxx 打上 env=prod 标签
$ kubectl label pod web-xxx env=prod
# 对象:Pod —— 删除 Pod web-xxx 的 env 标签(末尾的 - 表示删除)
$ kubectl label pod web-xxx env-
# 对象:Pod —— 给 Pod web-xxx 加注解(annotation 不参与 selector 匹配)
$ kubectl annotate pod web-xxx description="测试 Pod"
# 对象:Node —— 给节点 k8s-w1 打标签(用于 nodeSelector / 亲和性调度)
$ kubectl label node k8s-w1 disk=ssd
# 对象:Node —— 给节点 k8s-w1 打污点(防止普通 Pod 调度上来)
$ kubectl taint node k8s-w1 dedicated=agent:NoSchedule
# 对象:Node —— 删除节点 k8s-w1 上名为 dedicated 的污点
$ kubectl taint node k8s-w1 dedicated:NoSchedule-
14.11 节点维护:Cordon / Drain
升级内核、换硬盘、清磁盘前的标准动作:
# 对象:Node —— 标记 k8s-w1 不可调度(不再分配新 Pod,但不驱逐已有的)
$ kubectl cordon k8s-w1
# 对象:Node —— 驱逐 k8s-w1 上所有 Pod(自动迁移到其他节点)
$ kubectl drain k8s-w1 \
--ignore-daemonsets \
--delete-emptydir-data \
--grace-period=60 \
--timeout=5m
# 对象:Node —— 维护完成后恢复调度
$ kubectl uncordon k8s-w1
注意:
--ignore-daemonsets是必须的,DaemonSet 不受 drain 影响--delete-emptydir-data会删除 emptyDir 数据,确认无状态再用- 数据层(StatefulSet)慎用 drain,先确认副本数足够
14.12 批量与一次性操作
# 对象:Pod —— 删除所有 Failed 状态的 Pod
$ kubectl delete pods --field-selector=status.phase=Failed
# 对象:Pod —— 删除所有 Succeeded 状态的 Pod(清理 Job 残留)
$ kubectl delete pods --field-selector=status.phase=Succeeded
# 对象:Pod —— 按 label 批量删除
$ kubectl delete pods -l app=web
# 对象:Pod —— 强制删除卡死的 Pod(节点失联场景,谨慎使用)
$ kubectl delete pod web-xxx --force --grace-period=0
# 对象:所有工作负载 —— 删除 my-ns 命名空间下所有 Pod / Deployment / Service
$ kubectl delete all --all -n my-ns
# 对象:Namespace —— 删除整个命名空间(连带所有资源)
$ kubectl delete ns my-ns
危险操作提示:kubectl delete all --all 不会删 PV/PVC/ConfigMap/Secret/Ingress/CRD,别误以为"清空了"。
14.13 输出格式化:让命令变脚本
# 对象:Pod —— 输出 JSON / YAML 完整定义
$ kubectl get pod web-xxx -o json
$ kubectl get pod web-xxx -o yaml
# 对象:Pod —— 只取 Pod 的 IP
$ kubectl get pod web-xxx -o jsonpath='{.status.podIP}'
# 对象:Pod —— 取所有容器的镜像列表
$ kubectl get pod web-xxx -o jsonpath='{.spec.containers[*].image}'
# 对象:Pod —— 循环输出每个 Pod 的名字和 IP(每行一个)
$ kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'
# 对象:Pod —— 自定义输出列
$ kubectl get pods -o custom-columns=NAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeName
# 对象:Pod —— 配合 jq 做复杂过滤(找出非 Running 的 Pod 名)
$ kubectl get pods -o json | jq '.items[] | select(.status.phase!="Running") | .metadata.name'
# 对象:Pod —— wide 模式,多看 IP 和节点
$ kubectl get pods -o wide
14.14 应急排障 SOP(线上告警 → 定位)
按下面顺序执行,90% 的问题在 3 分钟内定位:
# Step 1. 对象:Pod —— 全集群找非 Running 的 Pod(定位是哪个 Pod 异常)
$ kubectl get pods -A | grep -vE 'Running|Completed'
# Step 2. 对象:Pod —— 看异常 Pod 的事件(镜像拉不下来?资源不够?)
$ kubectl describe pod web-xxx -n production | tail -20
# Step 3. 对象:Pod —— 看上一次崩溃前的日志(如果是 CrashLoopBackOff)
$ kubectl logs web-xxx -n production --previous --tail=100
# Step 4. 对象:Pod —— 看现在的实时日志
$ kubectl logs web-xxx -n production --tail=100 -f
# Step 5. 对象:Endpoints —— 看 Service web-svc 后端是不是 <none>
$ kubectl get endpoints web-svc -n production
# Step 5b. 对象:临时 Pod —— 在集群里实测 Service 通不通
$ kubectl run tmp --rm -it --image=busybox:1.31 -n production \
-- wget -qO- http://web-svc:80/health
# Step 6. 对象:Node —— 看节点 Conditions 是否健康(磁盘 / 内存 / PID 压力)
$ kubectl describe node k8s-w1 | grep -A5 Conditions
# Step 6b. 对象:Node —— 看节点资源用量
$ kubectl top nodes
# Step 7. 对象:Pod 内的容器 —— 实在搞不定,进容器看
$ kubectl exec -it web-xxx -n production -- sh
14.15 本章小结
K8s 命令虽多,但 80% 的日常运维只用到这些:
| 场景 | 对象 | 命令 |
|---|---|---|
| 看资源 | Pod / Svc / Deploy | kubectl get pods/svc/deploy -o wide |
| 看日志 | Pod | kubectl logs <pod> -f / --previous |
| 看事件 | Pod / Event | kubectl describe pod <pod> / kubectl get events --sort-by=.lastTimestamp |
| 进容器 | Pod 内容器 | kubectl exec -it <pod> -- sh |
| 改副本 | Deployment | kubectl scale deploy <deploy> --replicas=N |
| 改镜像 | Deployment | kubectl set image deploy/<deploy> <container>=<image> |
| 重启 | Deployment | kubectl rollout restart deploy/<deploy> |
| 回滚 | Deployment | kubectl rollout undo deploy/<deploy> |
| 转发 | Service / Pod | kubectl port-forward svc/<svc> 8080:80 |
| 维护节点 | Node | kubectl drain <node> --ignore-daemonsets |
剩下的 20%,记住两件事:
kubectl api-resources查所有可用资源名kubectl <command> --help永远比搜索引擎快