服务器运维

k8s常用命令大全:kubectl 查看、排错与运维速查

k8s常用命令几乎都是 kubectl 的子命令,按用途分五组:查看(get、describe)、日志与进入容器(logs、exec)、部署与更新(apply、rollout)、扩缩容(scale)、节点维护(cordon、drain)。排错记住一个顺序:先 get 看状态,再 describe 看事件,最后 logs 看程序输出。

作者 顶联产品团队发布于 5 分钟阅读

k8s常用命令基本都是 kubectl 的子命令,按日常用途可以分成五组:查看资源用 get、describe,看日志和进容器用 logs、exec,发版和回滚用 apply、rollout,扩缩容用 scale,维护节点用 cordon、drain、uncordon。排错时按“先 get 看状态、再 describe 看事件、最后 logs 看程序输出”的顺序走,大多数问题在这三步里就能定位。下面按组整理成速查表,每条命令都说明输出里该看哪一列、哪一段。示例统一使用命名空间 shop、Deployment web。

先记住格式:动词、资源、名称、参数

kubectl 命令的结构是 kubectl 动词 资源类型 [名称] [参数],例如 kubectl get pods web-7d9c8b6f5-2xkqp -n shop -o wide。资源类型可以用缩写:

资源 缩写 资源 缩写
pods po services svc
deployments deploy statefulsets sts
daemonsets ds replicasets rs
nodes no namespaces ns
configmaps cm persistentvolumeclaims pvc
ingresses ing horizontalpodautoscalers hpa

kubectl api-resources 会列出集群里全部资源类型和缩写。几个几乎每条命令都会用到的参数:

参数 作用
-n 命名空间 指定命名空间,不写就用当前上下文的默认值,通常是 default
-A 所有命名空间
-l app=web 按标签筛选
-o wide 多显示 Pod IP、所在节点等列
-o yaml、-o json 输出完整对象,包括 spec 和 status
-o name 只输出“类型/名称”,方便交给其他命令处理
-w 持续观察变化,Ctrl+C 退出
--field-selector 按字段筛选,例如 spec.nodeName=node-2

常用别名和补全,写进 ~/.bashrc:

alias k=kubectl
source <(kubectl completion bash)
complete -o default -F __start_kubectl k        # 让别名 k 也能 Tab 补全
alias kgp='kubectl get pods -o wide'
export dry='--dry-run=client -o yaml'           # 用法:k create deploy web --image=nginx $dry > web.yaml

-o 的几种进阶用法,在写脚本和做巡检时很省事:

kubectl get deploy web -n shop -o yaml > web-live.yaml   # 导出线上对象;含 status 等字段,复用前要删掉
kubectl get pods -n shop -o custom-columns='NAME:.metadata.name,NODE:.spec.nodeName,IMAGE:.spec.containers[*].image'
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.addresses[?(@.type=="InternalIP")].address}{"\n"}{end}'
kubectl get pods -A --sort-by='.status.containerStatuses[0].restartCount'   # 按重启次数排序
kubectl explain deployment.spec.strategy                 # 查某个字段的含义和可选值

查看资源:get 与 describe 的输出看什么

命令 用途 输出要看什么
kubectl get nodes -o wide 节点列表 STATUS 是否为 Ready;Ready,SchedulingDisabled 表示被 cordon 了;VERSION 各节点是否一致
kubectl get pods -n shop -o wide Pod 列表 READY 分子是否等于分母、STATUS、RESTARTS 是否在涨、NODE 是否都挤在一台上
kubectl get pods -A --field-selector=status.phase!=Running 全集群不在运行中的 Pod 已正常结束的 Job Pod 也会列出,状态为 Completed
kubectl get deploy -n shop 部署状态 READY 为 2/3 表示有副本没就绪;UP-TO-DATE 小于期望值表示更新还没走完
kubectl get svc -n shop 服务 TYPE、CLUSTER-IP、PORT(S);LoadBalancer 类型的 EXTERNAL-IP 一直是 pending,说明集群里没有可用的负载均衡实现,自建机房的集群常见
kubectl get endpointslices -n shop -l kubernetes.io/service-name=web Service 的后端 ENDPOINTS 一列没有地址,说明选择器没有选中可用的 Pod;有地址仍不通,用 -o yaml 看各后端的 conditions.ready
kubectl describe pod 名称 -n shop Pod 详情 末尾的 Events;容器的 State、Last State、Reason、Exit Code
kubectl describe node node-2 节点详情 Conditions 里的 MemoryPressure、DiskPressure;Taints;Allocated resources 里 requests 的占比
kubectl top nodes、kubectl top pods -n shop 实时 CPU 和内存 需要集群装有 metrics-server,否则报 Metrics API not available

一段典型的 kubectl get pods -n shop -o wide 输出:

NAME                  READY   STATUS             RESTARTS      AGE   IP            NODE     NOMINATED NODE   READINESS GATES
web-7d9c8b6f5-2xkqp   1/1     Running            0             3d    10.244.1.12   node-1   <none>           <none>
web-7d9c8b6f5-8wz4m   0/1     CrashLoopBackOff   14 (2m ago)   47m   10.244.2.31   node-2   <none>           <none>
api-6c5f9d7b8-qtl7n   0/1     Pending            0             12m   <none>        <none>   <none>           <none>

第二个 Pod 已经重启 14 次、最近一次在 2 分钟前,是程序启动后反复退出,下一步看它的上一次日志;第三个 Pod 没有 IP 也没有节点,说明还没被调度,原因在 describe 的 Events 里。较新版本的 kubectl 还可以用 kubectl events -n shop --types=Warning 只看告警事件。

日志与进入容器:logs、exec

kubectl logs web-7d9c8b6f5-8wz4m -n shop                  # 容器当前的标准输出
kubectl logs web-7d9c8b6f5-8wz4m -n shop --previous       # 上一次退出前的日志,CrashLoopBackOff 必看
kubectl logs -f deploy/web -n shop --tail=100             # 跟踪输出,从最后 100 行开始
kubectl logs web-7d9c8b6f5-2xkqp -n shop -c nginx         # 多容器 Pod 用 -c 指定容器
kubectl logs -l app=web -n shop --since=30m --tail=200 --prefix   # 按标签取多个 Pod 的日志,每行标出来源
kubectl exec -it web-7d9c8b6f5-2xkqp -n shop -- sh        # 进入容器;镜像里没有 bash 时用 sh
kubectl exec web-7d9c8b6f5-2xkqp -n shop -- cat /etc/resolv.conf     # 不进入,直接执行一条命令
kubectl cp shop/web-7d9c8b6f5-2xkqp:/app/logs/error.log ./error.log  # 从容器拷出文件,容器里需要有 tar
kubectl port-forward svc/web 8080:80 -n shop              # 本机 8080 转到 Service 的 80 端口,临时调试用

要点:

  • --previous 是排查 CrashLoopBackOff 的关键。 容器已经重启过,kubectl logs 默认看的是新启动的实例,它可能还没来得及输出错误;上一次崩溃的原因在 --previous 里。
  • logs deploy/web 只取其中一个 Pod。 要看全部副本用 -l 按标签取;按标签取日志时,每个 Pod 默认只显示最后 10 行,要看更多就加 --tail。
  • exec 后面的 -- 不能省,它把 kubectl 自己的参数和容器里要执行的命令分开。
  • 精简镜像里没有 shell,exec 会报找不到可执行文件。可以用 kubectl debug -it 名称 -n shop --image=busybox:1.36 --target=web 往 Pod 里加一个临时调试容器,--target 填业务容器的名字,就能看到它的进程。
  • 日志只保存在节点上。 Pod 被删除后 kubectl logs 就查不到了,需要长期保留的日志要接入集中日志系统。

部署、更新、回滚与扩缩容:apply、rollout、scale

kubectl diff -f web.yaml                     # 先看会改动什么,没有输出说明与线上一致
kubectl apply -f web.yaml                    # 创建或更新,重复执行是安全的
kubectl apply -f ./manifests/ -R             # 整个目录,-R 包含子目录
kubectl set image deploy/web web=registry.example.internal/shop/web:1.4.3 -n shop
kubectl annotate deploy/web -n shop kubernetes.io/change-cause="upgrade to 1.4.3"   # 给这次变更写说明
kubectl rollout status deploy/web -n shop    # 观察滚动更新进度
kubectl rollout history deploy/web -n shop   # 历史版本和 CHANGE-CAUSE
kubectl rollout undo deploy/web -n shop      # 回到上一版
kubectl rollout undo deploy/web -n shop --to-revision=3
kubectl rollout restart deploy/web -n shop   # 镜像不变,逐个重建 Pod
kubectl scale deploy/web -n shop --replicas=5

rollout status 会持续输出类似 Waiting for deployment "web" rollout to finish: 1 of 3 updated replicas are available... 的进度,全部替换完显示 successfully rolled out。新 Pod 一直起不来时,超过 Deployment 的 progressDeadlineSeconds(默认 600 秒)会报 exceeded its progress deadline。Kubernetes 不会自动回滚,这时先 rollout undo 恢复业务,再排查新版本。

几种写入方式的区别:

命令 行为 适合
kubectl create -f 只创建,对象已存在就报错 一次性创建
kubectl apply -f 不存在就创建,存在就按文件合并更新 日常发布,YAML 放在版本库里
kubectl replace -f 用文件整体替换对象,对象必须已存在 少数需要整体覆盖的场景
kubectl edit 在编辑器里直接改线上对象 临时应急;改完要同步回 YAML,否则下次 apply 会被覆盖

扩缩容的几个注意点:

  • kubectl scale deploy/web --replicas=0 停掉全部 Pod 但保留配置,恢复时再改回原来的数量。
  • 有 HPA 管理的 Deployment,手工 scale 的结果会被 HPA 改回去,要调整的是 HPA 的最小、最大副本数。
  • YAML 里写了 replicas,下一次 apply 会把手工 scale 的数量改回文件里的值。
  • kubectl get hpa 的 TARGETS 列显示 <unknown>/70%,说明 metrics-server 没装好,或者 Pod 没有设置 CPU requests。

节点维护:cordon、drain、uncordon

物理服务器换内存、升级内核、更新固件之前,先把节点上的 Pod 迁走:

kubectl cordon node-2                        # 标记为不可调度,已有 Pod 不动
kubectl drain node-2 --ignore-daemonsets --delete-emptydir-data --timeout=10m
# 关机维护、开机,确认 kubectl get nodes 里 node-2 重新变成 Ready
kubectl uncordon node-2                      # 恢复调度
命令或参数 作用 注意
cordon 禁止新 Pod 调度到该节点 节点 STATUS 变为 Ready,SchedulingDisabled
drain 先 cordon,再驱逐节点上的 Pod,由控制器在其他节点重建 驱逐会遵守 PodDisruptionBudget
--ignore-daemonsets 跳过 DaemonSet 的 Pod 不加时,节点上有 DaemonSet Pod 会直接报错退出
--delete-emptydir-data 允许驱逐使用 emptyDir 卷的 Pod emptyDir 里的数据会丢失
--force 连没有控制器管理的裸 Pod 也删除 裸 Pod 删除后不会在别处重建
uncordon 恢复调度 已迁走的 Pod 不会自动迁回

drain 卡住不动时,输出里通常反复出现 Cannot evict pod as it would violate the pod's disruption budget,说明某个应用的 PodDisruptionBudget 不允许再少一个副本。用 kubectl get pdb -A 找到它,如果副本数本来就等于 minAvailable,先给该应用扩容一个副本,drain 才能继续。维护结束 uncordon 之后,Pod 不会自己回来,节点之间负载不均时,可以对相关 Deployment 执行一次 rollout restart 让调度器重新分布。节点要永久下线,drain 之后执行 kubectl delete node node-2;用 kubeadm 部署的集群,再到这台机器上执行 kubeadm reset 清理。

排错常用组合:按 Pod 状态找原因

STATUS 或现象 常见原因 下一步看什么
Pending 资源不够、节点有污点、PVC 没绑定 describe 的 Events 里的 FailedScheduling,例如 0/3 nodes are available: 3 Insufficient cpu
ContainerCreating 很久 拉镜像慢、存储卷挂载失败、网络插件异常 describe 的 Events
ErrImagePull、ImagePullBackOff 镜像名或标签写错、私有仓库没配凭据、节点访问不了仓库 describe 里 Failed to pull image 后面的原因
CreateContainerConfigError 引用的 ConfigMap 或 Secret 不存在 kubectl get cm,secret -n shop
CrashLoopBackOff 程序启动后退出,kubelet 按递增间隔反复重启,最长间隔 5 分钟 kubectl logs --previous
Last State 的 Reason 为 OOMKilled,退出码 137 内存超过 limits 调高 limits,或排查程序的内存占用
Running 但 READY 为 0/1 就绪探针失败,Service 不会把流量转给它 describe 里的 Readiness probe failed
Evicted 节点内存或磁盘紧张,Pod 被驱逐 kubectl describe node 的 Conditions
Terminating 删不掉 节点失联,或对象上有 finalizer kubectl get pod 名称 -n shop -o yaml 里的 finalizers,以及所在节点的状态

Service 访问不通时,按下面的顺序查:

# 1. 后端 Pod 是否都已就绪
kubectl get pods -n shop -l app=web -o wide
# 2. Service 是否选中了 Pod
kubectl get endpointslices -n shop -l kubernetes.io/service-name=web
# 3. Service 的选择器与 Pod 标签是否一致
kubectl get svc web -n shop -o yaml | grep -A3 selector
kubectl get pods -n shop --show-labels
# 4. 从集群内部直接访问
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -n shop -- wget -qO- http://web.shop.svc.cluster.local
# 5. 报权限错误时,检查某个账号能不能做这个操作
kubectl auth can-i create deployments -n shop --as=system:serviceaccount:shop:deployer

第 1 步 Pod 都正常、第 2 步却为空,几乎总是选择器和标签对不上;第 4 步能访问而外部不通,问题在 Ingress、NodePort 或机房防火墙这一层,和 Pod 本身无关。

在机房里怎么落地

集群跑在自有物理服务器上时,kubectl 管得到 Pod 和节点对象,管不到节点的硬件和操作系统。典型的维护流程是:kubectl drain 把节点上的业务迁走,在 Toplink DCIM 的 IPMI 远程管理里远程关机、设置下次从 PXE 或 ISO 启动来重装系统、打开 VNC 控制台看开机自检,处理完再 uncordon。节点 NotReady、kubelet 连不上 apiserver 时,从控制台本地登录能直接看到网卡和系统状态,不受集群网络影响。节点地址、apiserver 的虚拟 IP 要在机房地址台账里登记,避免被分配给其他服务器:在 IP 地址管理里把这些地址登记为已占用,或把所在的段锁定,开通新服务器自动取址时就会跳过它们。

常见问题

每次都要写 -n,能不能设一个默认命名空间?

可以修改当前上下文的默认命名空间:kubectl config set-context --current --namespace=shop,之后不写 -n 就操作 shop,用 kubectl config view --minify | grep namespace 确认当前值。在多个集群、多个命名空间之间来回切换时容易忘记自己在哪,执行删除类命令前先确认一遍。

kubectl delete pod 之后 Pod 又出现了,怎么彻底删掉?

Pod 由 Deployment、StatefulSet 或 DaemonSet 管理时,删掉 Pod 只会让控制器补一个新的。要停掉业务,删除上层对象,例如 kubectl delete deploy web -n shop,或者把副本数缩到 0。用 kubectl get pod 名称 -o yaml 查看 ownerReferences 能找到上层对象:Deployment 创建的 Pod 先指向 ReplicaSet,再往上才是 Deployment。

Pod 一直卡在 Terminating 怎么办?

先看原因:所在节点已经失联时,Pod 要等节点恢复或节点对象被删除才能清理;对象上有 finalizer 时,要等对应的控制器完成清理。确认容器确实已经停止后,可以用 kubectl delete pod 名称 -n shop --grace-period=0 --force 强制删除。StatefulSet 的 Pod 慎用强删,节点只是网络断开时,可能出现两个同名实例同时写同一份数据。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88