第 3 章

kubectl 与资源管理

·约 10 分钟

集群搭好了,接下来的问题是:怎么用它? 这一章把 kubectl 的核心操作走一遍——从查看节点状态、部署应用、暴露服务到验证自愈,覆盖日常操作和考试中最常用的命令。


kubectl 速查

资源缩写

打全名太慢,kubectl 支持缩写:

全名缩写示例
podspokubectl get po
deploymentsdeploykubectl get deploy
servicessvckubectl get svc
nodesnokubectl get no
namespacesnskubectl get ns
endpointsepkubectl get ep

CKA 考试环境预设了 alias k=kubectl,所以 k get po 就够了。

输出格式

-o 控制输出格式,不同场景用不同格式:

参数输出什么什么时候用
-o wide多几列(IP、节点名等)快速查看 Pod 跑在哪个节点
-o yaml完整 YAML导出资源配置做模板
-o json完整 JSON程序化处理
-o jsonpath='{...}'自定义字段精确提取某个值

节点管理

查看节点

kubectl get nodes              # 节点列表
kubectl get nodes -o wide      # 含 IP、OS、容器运行时
kubectl describe node <名>     # 完整详情

describe 输出很长。不加节点名会把所有节点的信息拼在一起输出,所以几乎永远要配合 grep 过滤或指定节点名。

Node Conditions — 排障第一眼

kubectl describe node 里的 Conditions 是排障入口:

Condition正常值含义反了会怎样
NetworkUnavailableFalse网络插件正常True → Pod 无法通信
MemoryPressureFalse内存够用True → kubelet 驱逐低优先级 Pod
DiskPressureFalse磁盘够用True → 驱逐 Pod + 清理镜像
PIDPressureFalse进程数够用True → 拒绝创建新 Pod
ReadyTruekubelet 健康False/Unknown → 节点"掉线",不再接受调度

规律:前四个是"坏事",False = 没问题;最后一个是"好事",True = 正常。

Ready 变成 Unknown 是个特殊情况——说明 kubelet 停止发心跳了(默认 40 秒判定),需要 SSH 到节点上用 systemctl status kubelet 排查。

Taint 管理

Taint 阻止 Pod 调度到某个节点。kubeadm init 自动给 Control Plane 打上 NoSchedule taint。

# 查看
kubectl describe node | grep -i taint

# 删除(末尾减号 - 是"删除"语法)
kubectl taint nodes cp node-role.kubernetes.io/control-plane:NoSchedule-

# 添加
kubectl taint nodes cp node-role.kubernetes.io/control-plane:NoSchedule

不用记那串长名字——describe node | grep -i taint 输出里直接复制,加个 - 就行。

三种效果:

Effect含义
NoSchedule新 Pod 不调度到这里,已有的不受影响
PreferNoSchedule尽量不调度,没地方了也行
NoExecute最狠——新的不调度,已有的也驱逐

Deployment 生命周期

创建

kubectl create deployment nginx --image=nginx

一条命令创建三层对象:Deployment → ReplicaSet → Pod。

查看

kubectl get deploy                  # 列表
kubectl describe deployment nginx   # 详情(副本数、策略、事件)
kubectl get events                  # 集群事件日志,看部署经历了哪些步骤

kubectl get events 会按时间列出所有事件:Scheduled → Pulling → Pulled → Created → Started → ScalingReplicaSet,完整还原一次部署的路径。

YAML 模板生成(考试高频)

两种方式拿到 YAML:

方式一:从现有资源导出

kubectl get deployment nginx -o yaml > first.yaml

导出后需要手动删除运行时字段(creationTimestamp、resourceVersion、uid)和整个 status: 段,否则拿去创建新资源会冲突。

方式二:dry-run 直接生成干净模板(推荐)

kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > nginx.yaml

--dry-run=client = 只在本地生成 YAML,不提交给集群。输出天生就是干净的,没有运行时字段,不用手动清理。

导出dry-run
需要手动清理是否
需要资源已存在是否
考试推荐度备选首选

扩缩容

kubectl scale deployment nginx --replicas=3

更新与替换

修改了 YAML 文件后有两种方式应用:

kubectl apply -f file.yaml             # 智能合并(推荐)
kubectl replace -f file.yaml --force   # 先删后建(改了不可变字段时)

replace --force 会导致 Pod 重建,有短暂中断。

删除

kubectl delete deployment nginx

删 Deployment 会连带删掉它管理的 ReplicaSet 和所有 Pod。


Service — 暴露服务

Pod IP 是动态的,死了重建就变。Service 给一组 Pod 提供稳定的访问入口。

创建 Service

kubectl expose deployment/nginx

前提:Deployment 的容器必须声明了 containerPort,否则报错 couldn't find port via --port flag or introspection。

ClusterIP vs Endpoint

kubectl get svc nginx     # 查看 Service(含 ClusterIP)
kubectl get ep nginx      # 查看 Endpoint(Pod 的实际 IP)
ClusterIPEndpoint
是什么Service 的虚拟 IP(如 10.98.208.226)Pod 的实际 IP(如 192.168.1.5:80)
会变吗不会——Service 存在就不变会——Pod 重建后 IP 变,endpoint 自动更新
谁提供kube-proxy(iptables 规则)kubelet 注册
能 ping 吗不能——虚拟 IP 只处理 TCP/UDP能

测试连通用 curl,不要用 ping:

curl 10.98.208.226:80    # 通过 ClusterIP 访问
curl 192.168.1.5:80      # 通过 Pod IP 直接访问

四种 Service 类型

类型谁能访问用途
ClusterIP集群内部(默认)内部微服务通信
NodePort集群外通过 节点IP:端口开发测试、简单暴露
LoadBalancer云厂商负载均衡器生产环境对外暴露
ExternalNameDNS 别名指向集群外部服务

从集群外部访问 — NodePort

ClusterIP 只能在集群内部访问。要让外部流量进来,需要 NodePort 或 LoadBalancer。

LoadBalancer 类型的 Service

kubectl delete svc nginx
kubectl expose deployment nginx --type=LoadBalancer

kubectl get svc 会看到类似这样的输出:

nginx   LoadBalancer   10.104.0.20   <pending>   80:32456/TCP
  • 80:32456/TCP:Service 端口 80 映射到 NodePort 32456
  • <pending>:没有云厂商提供负载均衡器,裸金属环境永远 pending,但 NodePort 仍然可用
  • NodePort 范围:30000-32767,K8s 自动分配

用 节点IP:NodePort 就能从外部访问:

curl <节点IP>:32456      # 每个节点都开了这个端口

服务发现 — 环境变量

K8s 自动把同 namespace 的 Service 信息注入到 Pod 的环境变量里:

kubectl exec <pod名> -- printenv | grep NGINX
NGINX_SERVICE_HOST=10.96.165.138
NGINX_SERVICE_PORT=80
NGINX_PORT=tcp://10.96.165.138:80

Pod 不用硬编码就能找到其他 Service——这是服务发现机制之一。另一种更常用的方式是 DNS:直接用 nginx.default.svc.cluster.local 访问。

kubectl exec — 在 Pod 里执行命令

kubectl exec <pod名> -- <命令>

-- 的作用:告诉 kubectl "后面的全部是传给容器的命令,不是 kubectl 的参数"。排障常用:

kubectl exec nginx-xxx -- printenv          # 查看环境变量
kubectl exec nginx-xxx -- cat /etc/hosts    # 查看 DNS 配置
kubectl exec -it nginx-xxx -- /bin/bash     # 进入容器交互式 shell

清理注意事项

删 Deployment 不会自动删 Service,要单独删:

kubectl delete deploy nginx
kubectl delete svc nginx        # 必须单独删

自愈机制验证

K8s 的核心设计思想——瞬态:假定任何东西随时会死,系统自动修复。

# 扩到 3 副本
kubectl scale deployment nginx --replicas=3

# 删掉一个 Pod
kubectl delete pod nginx-xxx-yyy

# 立刻查看——ReplicaSet 自动补了一个新的
kubectl get po

删掉 Pod 后:

  • ReplicaSet 发现实际 2 个 ≠ 期望 3 个,立刻创建新 Pod
  • Service endpoint 自动更新,把新 Pod 加进去、旧的移除
  • ClusterIP 不变,调用方完全无感

这就是第一章学的 watch-loop 在实际工作:Controller Manager 持续监控,发现偏差就纠正。


命令速查表

命令用途
kubectl create deployment <名> --image=<镜像>创建 Deployment
kubectl get deploy / po / svc / no / ep查看资源
kubectl describe <资源类型> <名>查看详情
kubectl scale deployment <名> --replicas=N扩缩容
kubectl expose deployment/<名>创建 Service
kubectl delete <资源类型> <名>删除资源
kubectl replace -f file.yaml --force强制替换
kubectl create ... --dry-run=client -o yaml生成干净 YAML 模板
kubectl get events查看集群事件
kubectl describe node | grep -i taint查看节点 taint
kubectl taint nodes <名> <taint名>-删除 taint
kubectl exec <pod> -- <命令>在 Pod 里执行命令
kubectl expose deployment/<名> --type=LoadBalancer创建 LoadBalancer Service(含 NodePort)