外观
K8s 入门:最小概念与排障
K8s 的概念很多,但日常 90% 的操作只涉及 Pod / Deployment / Service / Ingress / ConfigMap 五个对象。
一、五个对象的关系
text
Ingress(域名/路径 → Service)
↓
Service(稳定 VIP + 负载均衡)
↓
Deployment(副本数、滚动更新)
↓
ReplicaSet → Pod(真正运行的容器)| 对象 | 一句话 |
|---|---|
| Pod | 最小调度单元,一个或多个容器共享网络 |
| Deployment | 管副本数和滚动更新,不直接管 Pod |
| Service | 一组 Pod 的稳定入口(ClusterIP/NodePort/LoadBalancer) |
| Ingress | 七层路由,按域名/路径转发到 Service |
| ConfigMap / Secret | 配置与密钥,挂载或注入环境变量 |
二、最小可用清单
yaml
# app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-api
namespace: shop
spec:
replicas: 3
selector:
matchLabels:
app: order-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: order-api
spec:
containers:
- name: app
image: registry.internal:5000/shop/order-api:1.4.2
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: order-api-config
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: "2"
memory: 2Gi
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"]
---
apiVersion: v1
kind: Service
metadata:
name: order-api
namespace: shop
spec:
selector:
app: order-api
ports:
- port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-api
namespace: shop
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-api
port:
number: 80bash
kubectl apply -f app.yaml
kubectl -n shop rollout status deploy/order-apitext
deployment "order-api" successfully rolled out关键点:
| 配置 | 为什么重要 |
|---|---|
requests | 调度依据,不设会被塞到资源不足的节点 |
limits.memory | 超过就 OOMKilled |
readinessProbe | 没通过就不接流量,滚动更新不中断的关键 |
livenessProbe | 失败会重启容器,不要配得太激进 |
maxUnavailable: 0 | 滚动时先起新的再停旧的 |
preStop sleep 5 | 给 Service 摘流量留时间,避免请求打到正在退出的 Pod |
三、日常命令
bash
kubectl get pods -n shop -o wide
kubectl describe pod order-api-7d9c8f6b5-x2k4m -n shop
kubectl logs -f order-api-7d9c8f6b5-x2k4m -n shop --tail 100
kubectl logs -n shop -l app=order-api --tail=20 --prefix
kubectl exec -it order-api-7d9c8f6b5-x2k4m -n shop -- sh
kubectl rollout history deploy/order-api -n shop
kubectl rollout undo deploy/order-api -n shop
kubectl rollout restart deploy/order-api -n shop
kubectl get events -n shop --sort-by=.lastTimestamp | tail -20text
NAME READY STATUS RESTARTS AGE IP NODE
order-api-7d9c8f6b5-x2k4m 1/1 Running 0 12m 10.244.1.42 node-2
order-api-7d9c8f6b5-m8p7q 1/1 Running 0 12m 10.244.2.18 node-3
order-api-7d9c8f6b5-t5r9s 1/1 Running 0 12m 10.244.1.51 node-2kubectl get events 是排查的第一现场:调度失败、拉镜像失败、探针失败都会在这里留记录。
四、四种常见异常状态
Pending
bash
kubectl describe pod <pod> -n shop | tail -20text
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m default-scheduler 0/3 nodes are available:
2 Insufficient cpu, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }原因:资源不够、节点有污点、亲和性不满足、PVC 没绑定。
ImagePullBackOff
text
Warning Failed 1m kubelet Failed to pull image "registry.internal:5000/shop/order-api:1.4.2":
rpc error: code = Unknown desc = Error response from daemon: manifest unknown三种原因:
- 镜像 tag 不存在(最常见)。
- 私有仓库没配
imagePullSecrets。 - 节点到 registry 的网络不通 / 证书不受信。
bash
kubectl create secret docker-registry regcred \
--docker-server=registry.internal:5000 \
--docker-username=admin --docker-password='xxx' -n shopCrashLoopBackOff
容器启动后立刻退出,K8s 指数退避重启(10s、20s、40s…最多 5 分钟)。
bash
kubectl logs <pod> -n shop --previous--previous 看上一次崩溃前的日志,这是关键。
OOMKilled
bash
kubectl describe pod <pod> -n shop | grep -A2 'Last State'text
Last State: Terminated
Reason: OOMKilled
Exit Code: 137limits.memory 太小,或 JVM 没按容器限额调整(-XX:MaxRAMPercentage=70)。
五、探针的三个坑
| 坑 | 后果 | 正确做法 |
|---|---|---|
liveness 用 /health 且依赖数据库 | 数据库抖动 → 全部 Pod 被重启 → 雪崩 | liveness 只查自身存活 |
| readiness 没配 | 滚动更新时新 Pod 未就绪就接流量 | 必配 readiness |
initialDelaySeconds 太小 | Java 冷启动 40s,20s 就开始探测 → 反复重启 | 或用 startupProbe |
yaml
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30
periodSeconds: 5startupProbe 成功前,liveness/readiness 都不生效——专门解决"启动慢"。
六、ConfigMap 与 Secret
bash
kubectl create configmap order-api-config -n shop \
--from-file=application-prod.yml
kubectl create secret generic order-api-secret -n shop \
--from-literal=DB_PASSWORD='xxx'yaml
envFrom:
- configMapRef:
name: order-api-config
- secretRef:
name: order-api-secretSecret 默认是 base64,不是加密
kubectl get secret -o yaml 直接能看到明文(base64 解码即可)。要真正保护:
- 开启 etcd 静态加密。
- 用外部密钥管理(Vault、云 KMS)。
- 至少限制 RBAC,别让所有人能读 secret。
七、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
| Pod 一直 Pending | 资源/污点/亲和性 | describe 看 Events |
ImagePullBackOff | tag 错 / 没 secret | 查镜像名与 imagePullSecrets |
CrashLoopBackOff | 应用启动失败 | logs --previous |
OOMKilled | limit 太小或堆外超限 | 调 limit,JVM 用 MaxRAMPercentage |
| 滚动更新期间 502 | 没配 readiness / 没 preStop | 补探针与优雅退出 |
| Pod 重启但没日志 | 启动就崩 | --previous + describe |
| Service 访问不通 | selector 不匹配 | kubectl get endpoints 看是否为空 |
| 改了 ConfigMap 不生效 | 环境变量注入只在启动时读 | 重启 Pod,或用 volume 挂载 |
kubectl exec 进不去 | distroless 无 shell | 用 kubectl debug 临时容器 |