从 docker run 到 K8s,多出来的是什么
会 docker run 之后看 Kubernetes,容易被一堆概念劝退:Pod、Deployment、ReplicaSet、Service、Ingress、ConfigMap、Namespace。其实它们回答的是四个问题:容器跑在哪、跑几个、怎么访问、配置从哪来。把这四个问题想清楚,对象模型就不难记了。
这篇按 1.28 之后的版本讲,重点放在日常 kubectl 用法和排障,不讲控制平面原理。
最小对象模型
| 对象 | 作用 | 一句话理解 |
|---|---|---|
| Pod | 最小调度单元 | 一个或多个共享网络的容器 |
| Deployment | 管理副本和滚动更新 | 保证“始终有 N 个 Pod 在跑” |
| Service | 稳定访问入口 | 给一组 Pod 一个固定 ClusterIP |
| Ingress | 七层路由 | 把域名和路径映射到 Service |
| ConfigMap/Secret | 配置注入 | 环境变量或文件挂载 |
| Namespace | 逻辑隔离 | 团队、环境的分区 |
Pod 本身很“脆”,删了就没了,所以生产上不直接建 Pod,而是用 Deployment。Deployment 创建 ReplicaSet,ReplicaSet 再创建 Pod;滚动更新时新建一个 ReplicaSet,逐步替换旧的。Service 通过 selector 找到 Pod,靠 kube-proxy 做转发,所以 Service 和 Pod 的标签必须对得上,这是新手最常见的“服务不通”原因。
标签(label)是 K8s 的“查询语言”,Service、Deployment、NetworkPolicy 都靠它关联对象;注解(annotation)用来放不参与选择的元数据,比如 Ingress 的 rewrite 配置、Prometheus 的抓取开关。标签至少固定 app、env、version 三个维度,后面的排查、灰度和监控都靠它。
一份能跑起来的配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: prod
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: app
image: registry.example.com/order-service:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
memory: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: prod
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
两个细节:requests 决定调度,limits 决定上限,内存 limit 一定要大于 JVM 堆加上堆外内存,否则会被内核 OOMKill;CPU 不设 limit 可以避免被限流,靠 requests 保证基本配额,这在 Java 服务里通常比设死 limit 更稳。
kubectl 日常命令
kubectl config current-context
kubectl get pods -n prod -o wide
kubectl describe pod order-service-7d9c8f-abcde -n prod
kubectl logs -f order-service-7d9c8f-abcde -n prod --tail=200
kubectl logs order-service-7d9c8f-abcde -n prod --previous
kubectl exec -it order-service-7d9c8f-abcde -n prod -- sh
kubectl port-forward svc/order-service 8080:80 -n prod
kubectl get events -n prod --sort-by=.lastTimestamp
kubectl apply -f deployment.yaml
kubectl rollout status deploy/order-service -n prod
kubectl rollout undo deploy/order-service -n prod
排障有个“四板斧”顺序:get 看状态,describe 看事件和探针,logs 看应用报错,exec 进去验证网络和配置。--previous 能看上一次崩溃前的日志,容器反复重启时尤其有用。kubectl get events 经常被忽略,但镜像拉取失败、调度失败、探针失败都记在这里。
输出格式也值得记几个:-o wide 看节点和 IP,-o yaml 看完整对象,-o jsonpath='{.status.podIP}' 适合脚本取值。写脚本时优先用 -o jsonpath 或 -o name,不要解析表格文本,列宽和版本一变就崩。
常见坑
坑一:CrashLoopBackOff。 容器启动后立刻退出,先看 logs --previous,再 describe 看退出码。退出码 137 通常是 OOMKilled 或收到 SIGKILL,1 是应用异常退出,143 是正常终止。
坑二:ImagePullBackOff。 私有仓库要先建 docker-registry 类型的 Secret 并配 imagePullSecrets,镜像地址、tag、架构(amd64/arm64)都要对。用 latest 标签会让回滚变得不可靠。
坑三:Service 访问不通。 按 Service selector → Pod labels → Endpoints → 容器端口 → NetworkPolicy 的顺序查。kubectl get endpoints order-service 是空的话,问题一定在 selector 或 Pod 没就绪。
坑四:Ingress 404。 先确认集群里装了 ingress controller,再看 ingressClassName、pathType 和 rewrite 注解。路径前缀和后端服务的 context-path 叠在一起,很容易多一层或少一层。
坑五:Pod Pending。 资源不足、节点亲和性、污点容忍、PVC 没绑定,都会导致调度失败。describe 最后一段的 Events 会直接告诉你原因。
坑六:用错集群。 kubectl config current-context 一定要在危险操作前确认。生产环境建议按最小权限发 kubeconfig,配合 --context 或 kubens 明确切换。
坑七:没设 requests。 不写 requests,调度器会把 Pod 当成“零需求”塞进任意节点,节点超卖后互相抢 CPU,表现为所有服务一起变慢。Java 服务至少给 CPU 和内存都设合理的 requests,limit 再按实际水位给。
排查步骤
kubectl get pod看 STATUS、RESTARTS、AGE,先分类是起不来、起来了但不 Ready,还是 Running 但业务不通。kubectl describe pod看 Events 和 Conditions,重点看探针失败、镜像拉取、调度、OOM。kubectl logs看应用日志,重启过的加--previous。kubectl get endpoints确认 Service 有没有后端;没有就回查 selector 和 readiness。- 进容器
curl一下自己的健康检查地址,排除应用端口和路径写错。
评论