容器编排的艺术
第十一本《从单体到微服务》里,小哲的公司把微服务拆好了;第十三本,这些服务该「住」哪、怎么管?周师傅把压箱底的 K8s 知识体系拿出来——从「容器是什么」一路讲到生产落地与 CKA 认证。学完这一本,你就能看懂 K8s 的世界地图。
五十个服务怎么管
容器编排:为什么需要 K8s师傅!微服务拆好了,一共 50 个服务——现在部署噩梦开始了:登录 50 台机器手动启容器?一个服务挂了谁能发现?流量大了怎么扩?ELK 也要跑……这活没法干了!
这正是 Kubernetes(K8s) 存在的意义——它是「容器编排系统」的霸主:自动部署、自动伸缩、自动自愈、统一管理。一句话:你告诉它「要什么」,它负责「让现实变成你要的」——声明式管理的典范。
来,十站路线,从容器地基一路到生产落地——
记住一句话:K8s 的核心哲学是「声明式」——你描述期望状态,系统自动调和(Reconcile)到那个状态。挂了一个 Pod?控制器自动补一个——这就是自愈。走,第一站,先看容器。
容器与镜像:地基
容器 · 镜像 · Dockerfile · 容器 vs 虚拟机K8s 管的是「容器」——所以第一课先把容器搞明白:它是什么、和虚拟机什么区别、镜像怎么来。
镜像(Image):应用的「施工图纸 + 材料清单」——代码 + 运行时 + 依赖,打包成不可变的文件。
容器(Container):镜像「跑起来」的实例——进程级隔离(Namespace 隔离视图 + Cgroups 限资源),秒级启动。
容器 vs 虚拟机:虚拟机模拟整台电脑(重,分钟级启动,隔离强);容器共享宿主机内核(轻,秒级启动)——微服务的密度靠容器。
镜像由 Dockerfile 定义,构建后推到镜像仓库(Docker Hub/私有 Harbor)——K8s 部署时从仓库拉镜像。
# Dockerfile(示例:一个 Python 服务)
FROM python:3.11-slim # 基础镜像
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt # 构建期
COPY . .
EXPOSE 8080
CMD ["python", "app.py"] # 启动命令
# 构建并推送
docker build -t ledger/order:v1.2 .
docker push ledger/order:v1.2
【容器 vs 虚拟机】
虚拟机 容器
启动 分钟级 秒级
资源 每个带 OS 共享内核,只装应用
隔离 强(独立内核) 进程级(Namespace+Cgroups)
密度 一台几十个 一台几百个
场景 强隔离/异构 微服务/云原生
【K8s 时代的容器运行时】
Docker → 已内置为 containerd(CNCF 标准)
镜像标准:OCI(Open Container Initiative)——不绑定 Docker
【镜像最佳实践】
小镜像(slim/distroless)→ 拉取快、攻击面小
多阶段构建 → 只留运行所需
版本 tag 固定(v1.2.0),别用 latest!
容器术语
- 镜像(Image):只读模板——代码+运行时+依赖打包。
- 容器(Container):镜像的实例——进程级隔离、秒级启动。
- Dockerfile:镜像的「配方」——构建指令。
- 镜像仓库:Docker Hub / Harbor——镜像的「货架」。
- OCI 标准:镜像/容器运行时标准——不绑定厂商。
- containerd:当前主流的容器运行时(K8s 内置)。
- 多阶段构建 / 最小镜像:构建优化两件套。
本站收获:容器 = 轻量进程隔离(秒级启动、高密度),镜像 = 不可变模板(Dockerfile 构建、仓库分发)。地基稳了,K8s 才有得管。
K8s 架构:控制面与节点
API Server · etcd · Scheduler · kubeletK8s 集群 = 一个「大脑」(控制面)+ 一群「手脚」(工作节点)。搞懂组件分工,排障时才知道找谁。
集群分两半:
- 控制面(Master):集群的大脑——API Server(唯一入口,所有命令都走它)、etcd(存储集群状态的小数据库,相当于「记账本」)、Scheduler(决定 Pod 放哪台机器)、Controller Manager(各种控制器,盯着状态调和)。
- 工作节点(Node):干活的机器——kubelet(每台机器上的「管家」,听 API Server 指挥)、kube-proxy(网络规则,Service 负载均衡的执行者)、容器运行时(containerd,真正跑容器)。
你用 kubectl 敲命令 → 发给 API Server → etcd 记录 → 控制器调和 → kubelet 执行——一条完整的「命令流水线」。
┌──────────── 控制面(Master ×3 高可用)────────────┐
│ API Server(唯一入口,kubectl 都走这) │
│ etcd(状态记账本——集群的「真相」) │
│ Scheduler(决定 Pod 放哪个节点) │
│ Controller Manager(控制器:盯着期望状态调和) │
└──────────────────────┬────────────────────────────┘
│
┌─────────┬─────────┼─────────┬─────────┐
▼ ▼ ▼ ▼ ▼
┌ Node1 ─┐ ┌ Node2 ─┐ ┌ Node3 ─┐ ┌ Node4 ─┐ ┌ Node5 ─┐
│ kubelet │ │ kubelet │ │ kubelet │ │ kubelet │ │ kubelet │ ← 每台机器管家
│ kube-proxy│ │ ... │ │ ... │ │ ... │ │ ... │
│ containerd│ │ │ │ │ │ │ │ │ ← 真正跑容器
│ Pod×N │ │ Pod×N │ │ Pod×N │ │ Pod×N │ │ Pod×N │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
【一次部署的旅程】
kubectl apply -f deploy.yaml
→ API Server 校验 → 存 etcd → Scheduler 选节点
→ 该节点 kubelet 拉镜像 → 起容器 → 汇报状态
→ Controller 发现期望=现实 → 完成
【etcd:一切状态的真相】
集群任何状态都记在 etcd——它是 K8s 的「数据库」
备份 etcd = 备份整个集群(第 10 站重点讲)
架构术语
- 控制面:API Server / etcd / Scheduler / Controller Manager——集群大脑。
- 工作节点:kubelet / kube-proxy / 容器运行时——干活的机器。
- API Server:唯一入口——所有操作都过它(安全管控点)。
- etcd:状态数据库——「记账本」,备份它=备份集群。
- kubelet:节点管家——执行指令、上报状态。
- 控制器模式(Controller):期望状态 vs 实际状态,循环调和——K8s 的灵魂。
本站收获:架构 = 控制面管「想」(API/记账/调度/调和)+ 节点管「做」(kubelet/proxy/运行时)。记住控制器模式:描述期望,自动调和——K8s 一切设计的出发点。
核心对象:Pod / Deployment / Service
三剑客 · Label/Selector · 滚动更新K8s 的世界里,一切皆「对象」,而对象用 YAML 描述。三剑客是每天都要写的:Pod(最小单元)、Deployment(管理副本)、Service(访问入口)。
三剑客各司其职:
- Pod:K8s 的最小调度单元——一个或多个容器共享网络/存储。一般不直接建 Pod,而是交给 Deployment 管。
- Deployment:声明「我要 3 个副本」——它负责创建/更新/自愈 Pod(挂一个自动补一个、发布时滚动更新)。
- Service:Pod 的「稳定入口」——Pod 的 IP 会变(重建就换),Service 提供固定 VIP + 负载均衡,把流量分给一组 Pod。
连接它们的钥匙是 Label/Selector:给 Pod 贴标签(app: order),Service 用选择器找到它们——松耦合的「贴纸寻人」机制。
# Deployment:管理副本,负责自愈与发布
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3 # 期望 3 个副本
selector:
matchLabels: { app: order } # 管理哪些 Pod
template:
metadata:
labels: { app: order } # 给 Pod 贴标签
spec:
containers:
- name: order
image: ledger/order:v1.2
ports: [{ containerPort: 8080 }]
---
# Service:稳定入口 + 负载均衡
apiVersion: v1
kind: Service
metadata:
name: order-svc
spec:
selector: { app: order } # 通过标签找到 Pod
ports:
- port: 80 # 集群内访问端口
targetPort: 8080 # 转发到 Pod 的端口
【命令速查】
kubectl apply -f deploy.yaml # 声明式应用
kubectl get pods / deploy / svc # 查看状态
kubectl logs -f pod/xxx # 看日志
kubectl describe pod/xxx # 详细信息(排障第一招)
【Deployment 滚动更新】
改镜像版本 → apply → 逐个替换 Pod,不中断服务
失败自动回滚(rollout undo)
【排障第一课】
Pod 起不来?kubectl describe 看事件!
CrashLoopBackOff?kubectl logs 看日志!
凌晨 2 点订单服务一个 Pod OOM 崩溃——Deployment 控制器 3 秒内自动补了一个新 Pod;Service 自动把流量从坏 Pod 摘走、指向新 Pod。用户无感知,值班同学早上才在告警记录里看到——「自愈」就是这么朴实无华。
核心对象术语
- Pod:最小调度单元——一个或多个容器。
- Deployment:副本管理 + 滚动更新 + 自愈——无状态应用标配。
- Service:稳定入口 + 负载均衡——Pod IP 变了不用怕。
- Label / Selector:贴标签 / 按标签选——对象之间的「胶水」。
- YAML 声明:K8s 的「代码」——一切对象用 YAML 描述。
- kubectl:操作 K8s 的命令行——工程师的「方向盘」。
- 滚动更新 / 回滚:发布不中断 / 出问题一键退回。
本站收获:三剑客 = Deployment 管「活几个」(自愈+发布)+ Service 管「怎么找」(入口+负载均衡)+ Pod 管「跑什么」。Label 是胶水,YAML 是语言——这就是 K8s 的日常。
配置与存储:ConfigMap/Secret/PVC
配置外置 · 密钥安全 · 持久化存储镜像里不能写死配置(改了要重新打包);密钥不能进镜像(会泄露);Pod 重启数据不能丢。这三个问题,由「配置、密钥、存储」三兄弟解决。
三兄弟:
- ConfigMap:普通配置(URL、开关、参数)——挂载成文件或环境变量。镜像不变,改配置就行——「配置外置」。
- Secret:敏感信息(密码、Token、证书)——Base64 存储 + 权限管控 + 可选加密(etcd 加密)。
- PV / PVC:持久化存储——PVC 是「申请单」(我要 10GB),PV 是「实际存储」(云盘/NFS),StorageClass 负责自动供应(按需创建云盘)。Pod 挂了数据不丢。
# ConfigMap:普通配置
apiVersion: v1
kind: ConfigMap
metadata: { name: order-config }
data:
REDIS_URL: redis://redis-svc:6379
LOG_LEVEL: info
---
# Secret:敏感信息
apiVersion: v1
kind: Secret
metadata: { name: order-secret }
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM= # base64(不是加密!)
---
# Deployment 里挂载使用
spec:
containers:
- name: order
envFrom:
- configMapRef: { name: order-config }
- secretRef: { name: order-secret }
【持久化存储(数据库这类有状态应用)】
PVC 申请 → StorageClass 自动创建云盘(动态供应)
Deployment 换成 StatefulSet(有状态应用专用):
稳定的网络标识(order-0, order-1…)、稳定的存储绑定
【存储类型】
emptyDir:临时(Pod 生命周期内,缓存用)
hostPath:节点本地盘(测试用)
云盘/分布式存储:生产首选(AWS EBS / 阿里云云盘 / Ceph)
【Secret 安全要点】
Secret 是「混淆」不是「加密」——生产要开启 etcd 加密
访问控制走 RBAC(第 9 站)
别把 Secret 提交进 Git!(密钥扫描——第七本老朋友)
日志级别要从 info 改成 debug——传统方式:改代码、重新构建镜像、重新发布;K8s 方式:改 ConfigMap → kubectl rollout restart → 30 秒生效,镜像完全没动。「配置外置」让环境差异(dev/test/prod)变成「三份 ConfigMap」而不是「三个镜像」。
配置存储术语
- ConfigMap:普通配置外置——镜像不重打。
- Secret:敏感信息——Base64 + RBAC + etcd 加密。
- PV / PVC / StorageClass:存储申请 / 实际存储 / 自动供应。
- StatefulSet:有状态应用(数据库)的控制器——稳定身份 + 稳定存储。
- emptyDir / hostPath / 云盘:临时 / 本地 / 生产存储。
- 配置即环境:同一镜像 + 不同 ConfigMap = 不同环境。
本站收获:配置外置(ConfigMap)、密钥隔离(Secret)、数据持久(PVC)——镜像「干净不可变」,环境差异全在集群配置层。数据库这类有状态应用用 StatefulSet。
网络:Service 与 Ingress
ClusterIP · NodePort · Ingress · CNI · CoreDNS「外部流量怎么进集群?服务之间怎么互相访问?」——网络是 K8s 最抽象、也最常考的一站。别怕,一层层剥开。
K8s 网络分三层(由内到外):
- 服务之间:ClusterIP(集群内部虚拟 IP,Service 默认类型)+ CoreDNS(服务名 → IP 的「通讯录」,所以服务间用名字访问:order-svc:80)。
- 节点外访问:NodePort(每个节点开个端口,外部用 节点IP:端口 访问)或 LoadBalancer(云厂商自动创建负载均衡器,生产首选)。
- 七层入口:Ingress——统一的外部网关(nginx-ingress 等),按域名/路径路由:api.example.com/order → 订单服务。相当于「K8s 的 API 网关」(第十一本老朋友)。
底层靠 CNI 插件(Calico/Flannel)实现 Pod 间互通与网络策略(第 9 站讲)。
用户请求 api.example.com/order/123
↓ DNS 解析到 Ingress 控制器
↓ Ingress(七层网关):按域名/路径路由
↓ Service(ClusterIP):负载均衡
↓ Pod × 3(订单服务):真正处理
【Service 三种类型(必考)】
ClusterIP:集群内虚拟 IP(默认)——服务间访问
NodePort :每节点开端口——测试/临时用
LoadBalancer:云厂商 LB——生产对外入口(配 Ingress 用)
【Ingress 配置示例】
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: api-ingress }
spec:
rules:
- host: api.example.com
http:
paths:
- path: /order
pathType: Prefix
backend:
service: { name: order-svc, port: { number: 80 } }
【CNI 插件】
Calico(生产主流):网络策略 + BGP 路由
Flannel:简单 overlay(VXLAN)——小集群够用
Cilium:eBPF 新一代(性能强,趋势)
【网络排障口诀】
服务不通?先查:Service 选择器对不对 → Pod 起来了没 → DNS 能不能解析 → CNI 通不通
新拆的「报表服务」上线:Deployment + Service 就位后,在 Ingress 加一行 `path: /report → report-svc`——外部立即可以访问。内部服务之间用 CoreDNS 名字互调(order-svc:80),IP 随便变都不用改代码。
网络术语
- ClusterIP / NodePort / LoadBalancer:Service 三种类型——内 / 测试 / 对外。
- Ingress:七层统一入口——域名/路径路由。
- CoreDNS:服务名 → IP——服务间用名字通信。
- CNI(容器网络接口):Calico / Flannel / Cilium——Pod 互通的地基。
- Service 负载均衡:kube-proxy 实现的四层转发(iptables/IPVS/eBPF)。
- 网络策略(NetworkPolicy):Pod 级防火墙——第 9 站展开。
本站收获:网络 = 内部 ClusterIP+DNS、对外 LoadBalancer+Ingress、底层 CNI。流量路径:Ingress → Service → Pod——这条链路背熟,网络排障就有方向。
调度与弹性:Requests/HPA
requests/limits · QoS · 节点亲和 · HPA 自动伸缩「服务流量暴涨怎么办?」——手动加副本?不,K8s 的 HPA 会自己扩。但前提是:你得告诉它每个 Pod 需要多少资源。
资源管理两兄弟:
- requests(请求):告诉调度器「这个 Pod 至少要多少资源」——调度依据(找得下的节点才放)。
- limits(上限):告诉运行时「最多能用多少」——超了杀(CPU 限流 / 内存 OOM Kill)。
HPA(水平自动伸缩):监控 Pod 的 CPU/内存使用率,超过阈值自动加副本,降下来自动减——「弹性」的精髓。再配合 节点亲和(Pod 想待在哪类节点)、污点容忍(节点拒绝/允许特定 Pod)——调度的高级玩法。
# Deployment 里声明资源
spec:
containers:
- name: order
resources:
requests: { cpu: "500m", memory: "512Mi" } # 最少要多少
limits: { cpu: "1", memory: "1Gi" } # 最多用多少
---
# HPA:自动伸缩
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: order-hpa }
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 70 }
【QoS 三等级(requests/limits 组合决定)】
Guaranteed:requests == limits(最高保障)
Burstable :requests < limits(常见)
BestEffort:都没设置(最低,先被杀)
【调度高级特性】
节点亲和(nodeAffinity):Pod 想待在「有 GPU」的节点
污点与容忍(Taint/Toleration):节点标记「特殊」,只让特定 Pod 来
反亲和(podAntiAffinity):两个副本别放同一台机器(高可用)
【HPA 扩展思考】
指标源不止 CPU:自定义指标(QPS/队列长度,KEDA)
垂直伸缩(VPA):自动调 requests/limits
节点级伸缩:Cluster Autoscaler 自动加机器
【排障提醒】
Pod 一直 Pending?→ 节点资源不够(requests 放不下)
Pod 反复 OOM?→ limits 内存给小了 / 内存泄漏
大促开始,订单服务 CPU 飙到 90%——HPA 检测到超过 70% 阈值,自动从 3 个副本扩到 18 个;大促结束,流量回落,自动缩回 3 个。全程无人值守,成本跟着流量走——「弹性伸缩」是云原生的最大红利之一。
调度弹性术语
- requests / limits:最少资源(调度依据)/ 最多资源(运行时限制)。
- QoS 等级:Guaranteed / Burstable / BestEffort——OOM 时谁先死。
- HPA:水平自动伸缩——按负载自动加/减副本。
- 节点亲和 / 污点容忍:调度的高级「意愿表达」。
- Pod 反亲和:副本分散到不同节点——高可用。
- Cluster Autoscaler:节点级自动伸缩——Pod 不够位置自动加机器。
- KEDA:基于自定义指标(QPS/队列)的伸缩器。
本站收获:弹性 = requests 声明需求 + limits 设上限 + HPA 按负载扩缩。记得声明资源!不声明 = BestEffort = OOM 时最先死——「别让系统猜你需要多少」。
服务治理:探针与发布
探针 · 优雅终止 · 滚动与金丝雀「发布时服务不中断」「挂了自动重启」「流量切到就绪的 Pod」——服务治理三件套:探针、优雅终止、发布策略。
三件套:
- 探针(Probe):K8s 给 Pod 做「体检」——liveness(还活着吗?挂了重启)、readiness(能接流量了吗?没就绪不往这分流量)、startup(启动慢的服务的「宽限期」)。
- 优雅终止:Pod 要下线时,先发 SIGTERM(应用自己清理),等 grace 时间再强制杀——请求处理完再走(preStop 钩子做最后清理)。
- 发布策略:滚动更新(默认,逐个替换)+ 金丝雀发布(先 1 个新版试水,验证后再全量)——第十一本的老朋友在这里落地。
spec:
containers:
- name: order
# 就绪探针:能接流量吗?(没就绪,Service 不分流量)
readinessProbe:
httpGet: { path: /healthz, port: 8080 }
initialDelaySeconds: 5
periodSeconds: 10
# 存活探针:还活着吗?(失败 3 次 → 重启容器)
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 3
# 启动探针:启动慢的应用给宽限
startupProbe:
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 30 # 给 30×5s 的启动时间
# 优雅终止:下线时等请求处理完
terminationGracePeriodSeconds: 30 # 给 30 秒优雅时间
# (应用内处理 SIGTERM:停止接新请求 → 处理完存量 → 退出)
【发布策略】
滚动更新(默认):maxSurge 多起几个 + maxUnavailable 少停几个
金丝雀:先发 1 个新版 → 观察指标 → 全量
蓝绿:两个版本并存,切 Service 选择器(简单粗暴)
【状态速查】
Running(正常)/ Pending(等待调度)/ CrashLoopBackOff(起不来循环)
ImagePullBackOff(拉镜像失败)/ OOMKilled(内存超限被杀)
→ 90% 的故障排查:describe + logs
新版本发布:滚动更新先起新 Pod(readiness 探针通过才接流量)→ 旧 Pod 收到 SIGTERM → 处理完手头请求 → 30 秒内优雅退出。全程用户请求 0 中断;如果新版启动失败,探针发现后自动回滚——「发布像呼吸一样自然」。
治理术语
- liveness / readiness / startup 探针:活着吗 / 能接流量吗 / 启动完没。
- 优雅终止:SIGTERM + grace 期——请求处理完再走。
- 滚动更新 / 金丝雀 / 蓝绿:三种发布策略——从保守到可控。
- CrashLoopBackOff:启动即崩循环——排查第一现场。
- ImagePullBackOff:镜像拉不到——tag 写错/仓库权限。
- maxSurge / maxUnavailable:滚动更新节奏控制。
本站收获:治理 = 探针定「健不健康」+ 优雅终止定「怎么退场」+ 发布策略定「怎么换血」。三件套配齐,发布不用熬夜、故障自动恢复。
多环境:命名空间与隔离
Namespace · ResourceQuota · LimitRange · 多集群dev / test / prod 三个环境共用一个集群?Namespace 就是「虚拟集群」——资源隔离、权限隔离、环境分离。
Namespace(命名空间):一个集群里的「虚拟分区」——把 dev/test/prod 拆开:
- 资源隔离:每个 NS 一套 Deployment/Service,互不干扰。
- 配额控制:ResourceQuota 限制「这个 NS 最多用多少资源」(防 dev 抢 prod 的资源)。
- 默认限制:LimitRange 给没声明资源的 Pod 兜底(没设 requests 就按默认来)。
- 权限隔离:RBAC 按 NS 授权(第 9 站)——开发只能动自己的 NS。
规模再大,就上多集群:dev/test 一个集群、prod 独立集群(故障隔离 + 合规要求)——大厂标准姿势。
一个集群(中小公司起步):
┌─ ns/dev ─┐ ┌─ ns/test ─┐ ┌─ ns/prod ─┐
│ 订单服务 │ │ 订单服务 │ │ 订单服务 │
│ 配置:dev │ │ 配置:test │ │ 配置:prod │ ← 同一镜像,不同 ConfigMap
│ 配额:小 │ │ 配额:中 │ │ 配额:大 │
└─────────┘ └──────────┘ └──────────┘
【ResourceQuota 示例】
apiVersion: v1
kind: ResourceQuota
metadata: { name: dev-quota, namespace: dev }
spec:
hard:
requests.cpu: "8"
requests.memory: 16Gi
pods: "50" # dev 最多 50 个 Pod,超了拒绝
【LimitRange:没声明资源的兜底】
→ 默认 requests/limits——防止「裸奔 Pod」抢资源
【命令速查】
kubectl get ns
kubectl -n prod get pods # 指定命名空间
kubectl config set-context ... # 切换上下文(当前 NS)
【多集群 vs 单集群多 NS(决策)】
单集群多 NS:省钱省事(中小团队起步)
多集群:故障隔离强、合规要求、团队大——规模大了再上
管理工具:Rancher / KubeSphere / ArgoCD(GitOps 部署)
没配配额前:开发同学的压测任务把集群资源吃光,生产服务被挤到 Pending——事故!配了 ResourceQuota 后:dev 配额 8 核 16G,超了直接拒绝,压测随便跑——dev 抢不到 prod 的资源,井水不犯河水。
多环境术语
- Namespace:虚拟集群——环境/团队/项目的隔离单元。
- ResourceQuota:NS 级资源配额——防资源抢占。
- LimitRange:默认资源限制——防裸奔 Pod。
- 上下文(Context):kubectl 当前操作的集群/NS 组合。
- 多集群:prod 独立集群——故障隔离 + 合规。
- GitOps:Git 仓库描述集群期望状态,ArgoCD 自动同步——声明式哲学的极致。
本站收获:多环境 = Namespace 分区 + Quota 限配额 + 同镜像不同配置。dev 别抢 prod 的饭,prod 独立集群保安全——环境隔离是生产纪律的第一条。
安全加固:RBAC 与策略
RBAC · ServiceAccount · NetworkPolicy · PodSecurityK8s 是「平台级」的系统——不安全就是全公司裸奔。安全四件套:谁能操作(RBAC)、谁能被访问(NetworkPolicy)、Pod 怎么跑(PodSecurity)、密钥怎么管(Secret 加密)。
K8s 安全四层:
- RBAC(基于角色的访问控制):谁能对集群做什么——用户/ServiceAccount 绑角色(Role/ClusterRole),角色里定义权限(get pods、create deploy…)。「最小权限」是铁律(第七本老朋友)。
- NetworkPolicy(网络策略):Pod 级防火墙——默认全部互通,策略收紧成「只有订单能访问支付」——微服务东西向安全(第十一本的微隔离在 K8s 落地)。
- PodSecurity(Pod 安全标准):限制 Pod 怎么跑——禁止 root 运行、禁止特权容器、只读根文件系统——防「提权逃逸」。
- Secret 安全:etcd 加密 + 最小授权 + 别提交 Git(密钥扫描,第七本老朋友)。
# RBAC:给开发角色「只看 prod」权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: dev-readonly, namespace: prod }
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"] # 只读!不能改
# 绑定用户/ServiceAccount
kind: RoleBinding
metadata: { name: dev-readonly-bind, namespace: prod }
subjects: [{ kind: User, name: "xiaozhe" }]
roleRef: { kind: Role, name: dev-readonly, apiGroup: rbac.authorization.k8s.io }
---
# NetworkPolicy:只允许订单 → 支付
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: allow-order-to-pay }
spec:
podSelector: { matchLabels: { app: payment } } # 目标:支付服务
ingress:
- from:
- podSelector: { matchLabels: { app: order } } # 只放行订单
ports: [{ port: 8080 }]
【PodSecurity 标准(baseline/restricted)】
禁止 privileged 容器、禁止 root 用户、只读根文件系统
→ 镜像里用非 root 运行应用(USER appuser)
【镜像安全】
镜像扫描(Trivy/Clair)→ 有 CVE 漏洞不让上线
只从受信仓库拉取(Harbor 私有仓 + 签名)
【审计日志】
API Server 审计——谁在什么时候干了什么(第七本审计老朋友)
某开发手滑 `kubectl delete ns prod`(有权限!)——事故!整改后:开发账号只给 prod 命名空间的只读 Role;部署走 CI/CD(有专门 ServiceAccount),人不能直接改 prod;再加 NetworkPolicy 收紧服务间访问——之后同类事故归零。权限最小化,比「祈祷别手滑」靠谱一万倍。
安全术语
- RBAC:Role/ClusterRole + Binding——谁对集群有什么权限。
- ServiceAccount:应用/流程在集群内的「身份」——CI/CD 用独立账号。
- NetworkPolicy:Pod 级网络白名单——东西向微隔离。
- PodSecurity:Pod 运行标准——防 root、防特权、防逃逸。
- 镜像扫描:Trivy/Clair——带病镜像不让上线。
- 审计日志:API Server 全留痕——出事能追责。
- 最小权限:给最少的、够用的——安全第一原则。
本站收获:安全 = RBAC 管「谁能动」(最小权限)+ NetworkPolicy 管「谁能通」(微隔离)+ PodSecurity 管「怎么跑」(防逃逸)+ Secret 加密。K8s 安全没做好,等于把家门钥匙挂在门口。
生产落地:实战与认证
高可用 · Helm · 排障 · CKA/CKAD知识点学完,怎么上生产?这一站给出生产化 checklist、Helm 包管理、排障思路,以及最实际的问题:CKA 认证值不值得考。
生产落地五件事:
- ① 高可用:控制面多副本(3 个 master + etcd 集群)——控制面挂了集群就「脑死亡」;工作节点多台 + 反亲和(副本分散)。
- ② 备份:etcd 定期快照 + 恢复演练——etcd 就是集群的「命根子」(第 2 站说过)。
- ③ 包管理(Helm):把「一堆 YAML」打包成 Chart——一条命令部署整套服务、参数化配置、版本管理。像「应用商店里的安装包」。
- ④ 可观测:metrics-server/Prometheus 监控 + 日志(第十二本 ELK 就跑 K8s 上)+ 告警。
- ⑤ GitOps:ArgoCD 从 Git 自动同步部署——代码即配置,回滚就是 revert。
【上线前 Checklist】
□ 控制面 3 节点高可用(etcd 备份 + 恢复演练)
□ 所有对象声明了 requests/limits(QoS 不低于 Burstable)
□ 探针配齐(readiness + liveness)
□ 镜像扫描通过 + 非 root 运行
□ RBAC 最小权限 + 审计开启
□ 日志/监控/告警接入(ELK + Prometheus)
□ Secret 加密 + 不落 Git
□ 备份恢复演练做过一次(不是「备份了」而是「恢复过」)
【Helm 速览】
helm create my-app # 创建 Chart
helm install my-app ./chart # 一键部署整套
helm upgrade / rollback # 升级 / 回滚
→ 把「50 个 YAML」变成「1 个命令」
【排障思路(体系化)】
① Pod 起不来:kubectl describe pod → 事件!
② 服务不通:Service selector 对不对 → DNS → NetworkPolicy
③ 集群异常:控制面健康 → etcd 健康 → 节点状态
④ 性能问题:资源不够 → 加副本/调 requests → 查慢查询
【认证(要不要考)】
CKA(管理员)/ CKAD(应用开发)——K8s 官方认证
CKA:集群运维、排障、etcd 备份恢复(实操考试)
CKAD:应用部署、Pod/Service/存储(偏开发)
→ 含金量:招聘硬通货,考一次管 3 年
→ 建议:先 CKAD 入门,再 CKA 进阶
【避坑清单(血泪)】
✗ latest 标签(不可复现)
✗ 不声明资源(OOM 先死)
✗ 有状态应用用 Deployment(要用 StatefulSet)
✗ 直接改生产(要走 CI/CD + 审计)
✗ 没备份就升级 etcd(备份是底线!)
小哲团队用 3 个月把 K8s 从「测试环境能跑」推进到「生产敢跑」:3 节点高可用 + etcd 备份演练 + Helm 管理 + GitOps 发布 + ELK/Prometheus 监控告警全接上。上线半年零重大事故——「生产化不是买保险,是把每一项 Checklist 都真正做过」。
生产落地术语
- 控制面高可用:3 master + etcd 集群——集群的命根子。
- etcd 备份:定期快照 + 恢复演练——「备份过」不等于「能恢复」。
- Helm:K8s 的包管理——Chart 打包整套应用。
- GitOps(ArgoCD):Git 即真相,自动同步部署——声明式的极致。
- 可观测集成:Prometheus 指标 + ELK 日志 + 告警。
- CKA / CKAD:官方认证——K8s 能力的硬通货。
- 生产 Checklist:上线前逐项过——每一项都要「真正做过」。
本站收获:生产落地 = 高可用 + 备份演练 + Helm/GitOps 管理 + 可观测 + 安全加固。认证是门票、Checklist 是保命符——「能跑」和「敢跑」之间,隔着一整份生产化清单。
核心对象速查 + YAML 模板
考前/实操前最后一页核心对象一句话速查
| 对象 | 一句话人话 | 典型场景 |
|---|---|---|
| Pod | 最小调度单元(1 或多个容器) | 跑一个应用实例 |
| Deployment | 无状态副本管理(自愈+滚动发布) | 普通服务 |
| StatefulSet | 有状态副本(稳定标识+存储) | 数据库/中间件 |
| Service | 稳定入口 + 负载均衡 | 服务间访问 |
| Ingress | 七层网关(域名/路径路由) | 外部流量入口 |
| ConfigMap / Secret | 配置 / 敏感信息 | 配置外置 |
| PV / PVC | 存储资源 / 存储申请 | 数据持久化 |
| Namespace | 虚拟分区(环境隔离) | dev/test/prod |
| HPA | 自动伸缩副本 | 弹性扩缩容 |
| RBAC / NetworkPolicy | 权限控制 / 网络策略 | 安全加固 |
| Helm Chart | 打包好的应用安装包 | 一键部署 |
面试/考试高频点速记
- Pod 和容器的区别?→ 容器是最小运行单位,Pod 是 K8s 最小调度单位(可含多个共享网络的容器)。
- Deployment 为什么能自愈?→ 控制器循环调和:期望副本 vs 实际副本,差异就补。
- Service 怎么找到 Pod?→ Label Selector + Endpoints(kube-proxy 实现转发)。
- Pod 重建后 IP 变,服务怎么不受影响?→ Service 提供稳定 VIP/DNS,Pod IP 变了自动更新 Endpoints。
- 为什么 Pod Pending?→ 调度器找不到满足 requests 的节点(资源不足/污点)。
- liveness 和 readiness 区别?→ 活着吗(挂了重启)/ 能接流量吗(没就绪不分流)。
- etcd 挂了会怎样?→ 集群无法读写状态 = 脑死亡;必须多副本 + 备份。
- 有状态应用为什么不用 Deployment?→ 需要稳定网络标识和固定存储——StatefulSet。
你描述期望状态,系统自动调和到那个状态。
把「运维的手工活」变成「平台的自动化」,
这就是容器编排的艺术;
而掌握它的钥匙,是理解「控制器模式」和「一切皆对象」。