第 3 章
kubectl 与资源管理
集群搭好了,接下来的问题是:怎么用它? 这一章把 kubectl 的核心操作走一遍——从查看节点状态、部署应用、暴露服务到验证自愈,覆盖日常操作和考试中最常用的命令。
kubectl 速查
资源缩写
打全名太慢,kubectl 支持缩写:
| 全名 | 缩写 | 示例 |
|---|---|---|
| pods | po | kubectl get po |
| deployments | deploy | kubectl get deploy |
| services | svc | kubectl get svc |
| nodes | no | kubectl get no |
| namespaces | ns | kubectl get ns |
| endpoints | ep | kubectl 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 | 正常值 | 含义 | 反了会怎样 |
|---|---|---|---|
| NetworkUnavailable | False | 网络插件正常 | True → Pod 无法通信 |
| MemoryPressure | False | 内存够用 | True → kubelet 驱逐低优先级 Pod |
| DiskPressure | False | 磁盘够用 | True → 驱逐 Pod + 清理镜像 |
| PIDPressure | False | 进程数够用 | True → 拒绝创建新 Pod |
| Ready | True | kubelet 健康 | 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)
| ClusterIP | Endpoint | |
|---|---|---|
| 是什么 | 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 | 云厂商负载均衡器 | 生产环境对外暴露 |
| ExternalName | DNS 别名 | 指向集群外部服务 |
从集群外部访问 — 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) |