Day 14:CKA / CKS 真题演练 + 14 天技术栈横向汇总
走到第 14 天,集群已经是一个能装、能跑、能挂、能救的完整平台:3 CP HA + 2 worker + 1 个跨 WAN GPU 节点,Cilium / Longhorn / Harbor / ArgoCD / Prometheus / Loki / Hubble / vLLM / Kyverno / 自研 Operator 全部就位。
这一天不再装新东西。把 CKA / CKS 真题按 Day 0-13 的能力切片走一遍,每题给场景 + 解法 + 卡点,再把 14 天踩过的真坑横向汇总。
整篇分三段:
- CKA 真题段:12 题,每题对应一个 Day 的实操
- CKS 真题段:8 题,全部对应 Day 5(安全)+ Day 12(灾备)+ 准入控制
- 全程踩坑横向汇总:5 类反复出现的真坑泛化
14 天技术栈一张表
主集群 5 节点 K8s 1.30(10.0.24.0/24)+ 跨 WAN 1 个 GPU 节点 k3s(A800-40G):
| 层 | 组件 | 关键事实 |
|---|---|---|
| Control Plane(Day 0-1) | 3 CP + per-node HAProxy + etcd raft | VIP 漂不动只能 per-node;etcd 单点损毁 2 分钟恢复(实测) |
| CNI / DNS(Day 1) | Cilium 1.16 eBPF + Hubble + node-local-dns | 私有 IDC 必须 VXLAN Always;DNS 9 跳解析链 |
| 存储(Day 4) | Longhorn 5 节点 634GB 池,3-replica | VolumeSnapshot 秒级 + PVC 在线扩容 |
| 安全(Day 5) | RBAC + PSA restricted + Kyverno + Secret aescbc | etcd 直查从明文到密文实测 |
| 调度(Day 6) | HPA + KEDA + topologySpreadConstraints | metrics-server 自签集群要 --kubelet-insecure-tls |
| CI/CD(Day 7-8) | Harbor + Jenkins + Kaniko + ArgoCD | GitOps selfHeal + prune;Kaniko 无 docker daemon |
| GPU / 推理(Day 8-10) | NVIDIA Device Plugin + DCGM + vLLM | MIG 3×2g.10gb;Qwen2.5-3B 30 并发 2901 tok/s P99 1.3s |
| Operator(Day 11/13) | kubebuilder v4:SimpleApp + LLMService CRD | Reconcile 三件套 + Finalizer + OwnerReference |
| Mesh / 联邦(Day 11/13) | Cilium ClusterMesh 设计 + SSH tunnel 实操 | 跨 WAN VXLAN UDP 4789 不通走 tunnel |
| 观测(Day 6/9) | kube-prometheus-stack + Loki + AlertManager | 28 target up;DCGM 跨 WAN 19 个 GPU metric |
| 灾备(Day 12) | etcd snapshot + OOM / Cilium / cert SOP | 5 类生产事故 SOP 实测注入恢复 |
Part 1:CKA 真题演练(12 题)
CKA 限时 2 小时 17 题,平均每题 < 8 分钟,所有命令必须能盲打。每题给场景 + 解法 + 卡点。
Q1(Day 1)kubeadm join token 丢了
新 worker 准备加入,但当时 kubeadm init 输出的 join 命令已经过期或丢失。
# 在任一 cp 上重新生成(包含 token + ca-cert-hash)
kubeadm token create --print-join-command
# token 默认 TTL 24h。要永久 token(不推荐生产):
kubeadm token create --ttl 0 --print-join-command
卡点:默认 token 24 小时过期,老 token 已失效;不要去 kubeadm token list 然后手拼命令,--print-join-command 一行出全部。
Q2(Day 0)节点 NotReady,runtime is down
# 1. kubelet 是否在跑
systemctl status kubelet
journalctl -u kubelet --since '5min ago' | tail -50
# 2. containerd 是否 healthy
systemctl status containerd
crictl info | jq '.status'
# 3. cgroup driver 一致性(最常见根因)
grep SystemdCgroup /etc/containerd/config.toml # 应为 true
grep cgroupDriver /var/lib/kubelet/config.yaml # 应为 systemd
# 4. 重启
systemctl restart containerd kubelet
卡点:kubelet 和 containerd 的 cgroup driver 不一致是 90% 的根因(一个 systemd,一个 cgroupfs)。Pod 会启动但行为异常(OOM 触发不对、limit 不生效)。
Q3(Day 1)节点优雅下线
kubectl cordon <node> # 阻止新 Pod
kubectl drain <node> \
--ignore-daemonsets \
--delete-emptydir-data \
--timeout=300s # evict 现有
# 维护操作(重启 / 升级内核 / 换盘)
kubectl uncordon <node> # 恢复调度
卡点:忘 --ignore-daemonsets,drain 会卡在 DaemonSet(kube-proxy / cilium-agent)。--delete-emptydir-data 必须显式给,否则有 emptyDir 的 Pod drain 不动。
Q4(Day 0/1)集群升级 1.30 → 1.31
每台 cp 先升(apt unhold kubeadm → apt install kubeadm=1.31.* → kubeadm upgrade apply v1.31.0 → apt install kubelet kubectl → restart kubelet → hold 回来),然后每台 worker drain → kubeadm upgrade node → 升 kubelet → uncordon。
# cp 上的关键三行
apt-mark unhold kubeadm && apt-get install -y kubeadm=1.31.0-*
kubeadm upgrade apply v1.31.0
apt-get install -y kubelet=1.31.0-* kubectl=1.31.0-* && systemctl restart kubelet
卡点:K8s 一次只能 +1 minor。1.30 → 1.32 必须经过 1.31,否则 apiserver 起不来。apt-mark hold 是 Day 0 装的时候就该做的(防 unattended-upgrades 自动跨版本升)。
Q5(Day 6)Pod Pending:5 Insufficient cpu
kubectl get pod <p> -o jsonpath='{.spec.containers[*].resources.requests}'
kubectl describe nodes | grep -A5 'Allocated resources'
三种解法:减 Pod request(最快)/ 加节点 / PriorityClass + preemption 抢占。
卡点:kubectl top 看实际使用,describe nodes 的 Allocated 才是已 request。Pending 的根因永远是 request 不是实际使用。
Q6(Day 6)Pod 跨 zone 均匀分布
spec:
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule # 严格,不行就 Pending
labelSelector:
matchLabels: { app: my-app }
卡点:ScheduleAnyway 是软约束,要严格用 DoNotSchedule。labelSelector 必须跟 Pod label 匹配,否则约束全没生效(skew 永远 0)。
Q7(Day 8/10)Pod 必须跑在 GPU 节点上
spec:
template:
spec:
nodeSelector:
accelerator: gpu
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: app
image: vllm/vllm-openai:latest
resources:
limits:
nvidia.com/gpu: 1
卡点:nodeSelector + toleration 缺一不可。漏 toleration 会 Pending,漏 nodeSelector 会跑到 CPU 节点。
Q8(Day 6)HPA TARGETS unknown
# 99% 是 metrics-server 没装或证书问题
kubectl get pod -n kube-system | grep metrics-server
kubectl logs -n kube-system <metrics-server>
# 常见:x509: cannot validate certificate
# 修:加 --kubelet-insecure-tls
kubectl patch deploy metrics-server -n kube-system --type=json \
-p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
卡点:自签集群 metrics-server 默认验证 kubelet cert 会失败。--kubelet-insecure-tls 是 kubeadm 集群的标准配方。
Q9(Day 5)namespace CPU 总额限制
apiVersion: v1
kind: ResourceQuota
metadata: { name: cpu-limit, namespace: my-ns }
spec:
hard:
requests.cpu: "5"
limits.cpu: "10"
---
apiVersion: v1
kind: LimitRange
metadata: { name: default-limits, namespace: my-ns }
spec:
limits:
- type: Container
default: { cpu: "200m", memory: "256Mi" }
defaultRequest: { cpu: "100m", memory: "128Mi" }
卡点:只设 ResourceQuota 不行 —— Pod 没显式写 request 会被 Quota 拒绝。LimitRange 补默认值,两个一起用才完整。
Q10(Day 1/4)Service connection refused
按下面顺序查:
kubectl get endpoints <svc> # 空 → selector 不匹配 / Pod readiness 没过
kubectl get networkpolicy -n <ns> # 有没有把流量拦了
sudo ipvsadm -L -n | grep <svc-ip> # kube-proxy 是否生成了规则
kubectl logs -n kube-system <kube-proxy>
卡点:80% 的 Service 不通是 Endpoint 为空(selector / label 不匹配 或 readiness 没过)。先查 kubectl get endpoints 再查别的。
Q11(Day 4)NetworkPolicy deny-all 后 DNS 也挂了
# deny-all 之后必须显式 allow DNS egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: allow-dns, namespace: my-ns }
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to:
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: kube-system }
podSelector:
matchLabels: { k8s-app: kube-dns }
ports:
- { protocol: UDP, port: 53 }
- { protocol: TCP, port: 53 }
卡点:default deny + 白名单的模式必须首先放 DNS,否则 Pod 连解析都做不到,所有请求 fail。CKS 必考。
Q12(Day 4/5)PVC Pending
kubectl describe pvc <pvc> # 看 events
kubectl get sc # SC 存在 + default?
kubectl get pod -n longhorn-system | grep -E 'manager|csi'
kubectl get nodes.longhorn.io -n longhorn-system # node Schedulable?
卡点:Longhorn 节点的 Schedulable: false 是最隐蔽的(节点磁盘空间不够 / replica 数对不上 / disk tag 不匹配)。kubectl describe pvc 的 event 是入口。
PVC 扩容后 df 没变大:
kubectl get pvc <pvc> -o yaml | grep -A2 conditions
# FileSystemResizePending → 重启 Pod 让 kubelet 触发 resize2fs
kubectl delete pod <pod-using-pvc>
Part 2:CKS 真题演练(8 题)
Q13(Day 5)只读 SA:get / list pods + configmaps
apiVersion: v1
kind: ServiceAccount
metadata: { name: only-view, namespace: my-ns }
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: pod-cm-reader, namespace: my-ns }
rules:
- apiGroups: [""]
resources: ["pods", "configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: { name: only-view-binding, namespace: my-ns }
subjects:
- kind: ServiceAccount
name: only-view
namespace: my-ns
roleRef:
kind: Role
name: pod-cm-reader
apiGroup: rbac.authorization.k8s.io
验证:
kubectl auth can-i list pods -n my-ns \
--as=system:serviceaccount:my-ns:only-view
# yes
kubectl auth can-i delete pods -n my-ns \
--as=system:serviceaccount:my-ns:only-view
# no
卡点:Role 是 namespace 级,ClusterRole 是集群级。题目「在 my-ns 只读」必须用 Role + RoleBinding,写 ClusterRole + ClusterRoleBinding 等于权限放大。
Q14(Day 5)PSA restricted 让 Pod 合规
namespace 标 pod-security.kubernetes.io/enforce: restricted 后 Pod 起不来,补齐 5 项:
spec:
securityContext: # Pod 级
runAsNonRoot: true
runAsUser: 65534
seccompProfile: { type: RuntimeDefault }
containers:
- securityContext: # 容器级
allowPrivilegeEscalation: false
runAsNonRoot: true
readOnlyRootFilesystem: true
capabilities: { drop: [ALL] }
卡点:5 项必须全配齐,缺一个就拒。seccompProfile 是 v1.25+ 引入的 restricted 硬要求,老题库经常漏。
Q15(Day 5)Secret at-rest 加密
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: [secrets]
providers:
- aescbc:
keys:
- name: key1
secret: <base64 32-byte 密钥> # head -c 32 /dev/urandom | base64
- identity: {} # 兜底读旧明文
五步:三 cp 都放配置文件 → apiserver static pod manifest 加 --encryption-provider-config + volume mount → 滚动重启三 cp → rewrite 历史 Secret → 直查 etcd 验证。
# 4. rewrite 历史 Secret(关键,否则只对新写的生效)
kubectl get secrets -A -o json | kubectl replace -f -
# 5. 直查 etcd 看到 "k8s:enc:aescbc:v1:key1:" 前缀就对
etcdctl get /registry/secrets/default/my-secret --print-value-only | hexdump -C | head
卡点:
providers列表里 aescbc 在前 identity 在后,否则新写的 Secret 不加密。- 步骤 4 必须做,否则历史 Secret 仍是明文,加密只对新写的生效。
- 三 cp 滚动重启时,第一个重启的 cp 加密了新 Secret,其他 cp 还在用 identity 读 —— 这就是 identity 兜底为什么必须留。
Q16(Day 5)Kyverno:禁用 image:latest
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: { name: disallow-latest-tag }
spec:
validationFailureAction: Enforce
rules:
- name: require-image-tag
match:
any:
- resources: { kinds: [Pod] }
validate:
message: "Image must have an explicit tag (not :latest, not empty)"
pattern:
spec:
containers:
- image: "!*:latest & *:*"
卡点:!*:latest & *:* 是 Kyverno anchor 语法 —— 第一段排除 :latest,第二段要求必须有 :tag。只写第一段会让 nginx(无 tag)通过。
Q17(Day 11/12)apiserver cert 即将过期
kubeadm certs check-expiration # 看每张 cert 到期日
kubeadm certs renew all # 续所有
systemctl restart kubelet # 让 static pod 重启
# 或在每 cp 上:
kill $(pgrep kube-apiserver) # static pod 自重启
卡点:renew all 续的是 kubeadm 管理的那些 cert(apiserver / controller-manager / scheduler / etcd / front-proxy)。kubelet cert 不在里面 —— kubelet 用 RotateCertificates: true 自动续,要在 /var/lib/kubelet/config.yaml 里开。
Q18(Day 12)etcd 单节点数据全毁
剩 2/3 quorum 时 5 步:
# 1. 在活的 cp 上移除死成员
etcdctl member remove <dead-id>
# 2. 死节点清 data dir
mv /var/lib/etcd /var/lib/etcd-broken-backup
# 3. add learner
etcdctl member add <cp-name> --peer-urls=https://<cp-ip>:2380 --learner
# 4. 改 etcd manifest:--initial-cluster-state=existing + 完整三节点列表
# 5. mv manifest 回原位,kubelet 拉起 etcd,同步完自动 promote voter
卡点:必须先 remove 再 add,否则同名同 ID 冲突。--learner 是 etcd 3.4+ 的安全机制(同步完才有投票权,避免 quorum 计算错误)。实测含同步 2 分钟。
Q19(Day 12)整个 cluster 死了,只剩 snapshot
# 1. 在 cp-1 restore(单节点新集群)
ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \
--name k8s-cp-1 \
--initial-cluster k8s-cp-1=https://10.0.24.31:2380 \
--initial-cluster-token new-token \
--initial-advertise-peer-urls https://10.0.24.31:2380 \
--data-dir /var/lib/etcd-new
# 2. mv /var/lib/etcd-new → /var/lib/etcd
# 3. 改 etcd manifest:--initial-cluster-state=new(注意是 new,不是 existing)
# 4. kubelet 拉起单节点 etcd
# 5. cp-2 / cp-3 kubeadm reset → 重新 join
卡点:从 snapshot 起的是新 cluster(token 都换了),--initial-cluster-state=new 不是 existing。其他 cp 必须 reset 后 rejoin,不能直接 start。
Q20(Day 4/5)NetworkPolicy 多租户隔离
team-a 的 Pod 只能访问 team-a 的 Service + DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: team-a-isolation, namespace: team-a }
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector: {} # 同 ns
egress:
- to:
- podSelector: {} # 同 ns
- to: # DNS
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: kube-system }
podSelector:
matchLabels: { k8s-app: kube-dns }
ports: [{ protocol: UDP, port: 53 }]
卡点:podSelector: {} 是「所有 Pod in this namespace」,不是全集群。多个 egress rule 之间是 OR 关系。
Part 3:全程踩坑横向汇总
14 天里反复出现的 5 类坑,泛化到「面试讲故事」可以套的程度。
坑 1:IDC source-IP filter 系列
私有 IDC 网关 / 交换机做 source-IP 白名单 + MAC-IP 静态绑定,跟 K8s 网络抽象冲突。
| Day | 现象 | 根因 | 修复 |
|---|---|---|---|
| Day 1.B | keepalived VIP 10.0.24.100 其他节点 100% 丢包 | 网关只放分配给本机的 IP | per-node HAProxy 替代 VIP |
| Day 1.E | Calico IPIPCrossSubnet 跨节点 Pod ping 全丢,tcpdump 看到包源 IP 是裸 Pod IP | 网关看到 src 不在白名单直接 drop | Calico encap 切 VXLAN Always |
| Day 9 | GPU 节点跨 WAN 加入主集群 Cilium VXLAN UDP 4789 不通 | 公网防火墙阻 UDP | 改 SSH tunnel + Service + Endpoints |
通用规律:私有 IDC 默认就用 overlay 封装(VXLAN),别想着省那 50B overhead。源 IP 必须是节点 IP,IDC 才放行。
坑 2:etcd ghost member
kubeadm join --control-plane 失败后,etcd 里残留半成品 member。
etcdserver: can only promote a learner member which is in sync with leader
etcdctl member list:
| 85047be2f29d3191 | unstarted | | https://10.0.24.29:2380 | ← ghost
| 953b8e085f0fea77 | started | k8s-cp-3 | ... |
修复:
etcdctl member remove 85047be2f29d3191
# 然后才能重新 join
通用规律:kubeadm 任何半失败都要看 etcd member list 有没有残留。kubeadm reset 不清 etcd member。
坑 3:BIRD / iptables / proto bird 残留路由
CNI 切换(Calico → Cilium)后跨节点带宽掉到 26 Mbps,根因是 Calico BIRD 学到的路由没清。
ip route | grep 'proto bird'
# 10.244.111.192 via 10.0.24.31 dev eth0 proto bird ← 残留
ip route flush proto bird
CNI 切换的完整 cleanup checklist:
/etc/cni/net.d/*配置/opt/cni/bin/*二进制- iptables 自定义链(
iptables-save | grep cali) ip route flush proto bird(Calico)- 接口:
vxlan.calico/tunl0/cali*veth /cilium*
漏任何一项都让新 CNI 半坏不坏。
坑 4:sshd_config.d override + remote heredoc 引号
两个看似无关其实同根的 SSH 坑:
4.1 Day 0 改 /etc/ssh/sshd_config 后 PubkeyAuthentication 仍然 no —— Ubuntu 22 的 /etc/ssh/sshd_config.d/*.conf override 主配置。
修复:
for f in /etc/ssh/sshd_config.d/*.conf; do
[ -f "$f" ] && sed -i 's/^PubkeyAuthentication.*/PubkeyAuthentication yes/' "$f"
done
sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sshd -t && systemctl reload sshd
4.2 远程 heredoc 用双引号,$(hostname) 被本地 shell 提前展开:
# 错的:本地 eval 后远端跑空命令
ssh root@$ip "bash -s" <<EOF
echo $(hostname) # 本地 hostname 被插入
EOF
# 对的:单引号包 EOF,远端真正展开
ssh root@$ip 'bash -s' <<'EOF'
echo $(hostname) # 远端 hostname
EOF
通用规律:SSH 配置改完必看 .d/*.conf,远程脚本永远用 <<'EOF' 单引号。
坑 5:containerd v3 schema 字段名
2024 后 Docker 官方源装的 containerd 是 2.x,config schema 升到 v3:
- v1/v2:
sandbox_image = 'registry.k8s.io/pause:3.9' - v3:
sandbox = 'registry.k8s.io/pause:3.10.1'
照搬老教程 sed 改 sandbox_image 完全没匹配。config_path 在 v3 里是 '' 默认值,只能改值不能 append(append 会 duplicate key,containerd 起不来)。
# 看实际字段名再改
containerd config dump | grep -E "pause|sandbox"
sed -i "s|config_path = ''|config_path = '/etc/containerd/certs.d'|" /etc/containerd/config.toml
通用规律:装 containerd 后先 dump 看真实 schema,不要按记忆 sed。
面试常见题(覆盖 14 天最高频)
Q1:你接手一台裸机准备装 K8s,前 30 分钟做什么?
四步:
- 探虚拟化(
systemd-detect-virt,LXC 直接换机器)+ cgroup 版本 - SSH 免密 + 关密码登录 + 关
unattended-upgrades(防自动跨 minor 升 kubelet 炸集群) - 装 chrony 同步时间(etcd raft 对时差 > 1s 敏感)
- hostname +
/etc/hosts+ 关无用服务(multipathd/iscsid/apport)
Q2:K8s HA 控制面方案怎么选?
3 种:
- VIP + keepalived / kube-vip ARP:小厂 IDC 几乎不让漂(source-IP filter)
- 外部 LB:云上简单,私有要多 1 台
- per-node HAProxy:localhost:16443 转 3 CP,kubespray / talos / k0s 默认
实战:私有 IDC ip addr add VIP 后其他节点 Destination Host Unreachable(L3 失败,不是 L2 ARP)= 网关白名单 block,只能 per-node HAProxy。
Q3:跨节点 Pod 不通你怎么排查?
5 步:
kubectl get pods -o wide看 IP 分配kubectl exec pod1 -- ping <podN-ip>看连通性ip route | grep <pod-cidr>看 host 路由表tcpdump -i eth0 host <对端节点>看真实包到没到 + 检查源 IP- 关键线索:源 IP 是裸 Pod IP(没封装)→ CNI encap 配错 → 切 VXLAN
故事:Calico IPIPCrossSubnet 在私有 IDC 被 source-IP filter drop,tcpdump 看到包源 IP 没封装是关键。
Q4:node-local-dns 为什么生产必装?
4 个收益:
- 延迟:本地 hairpin < 0.5ms vs kube-proxy DNAT 2-5ms(5-10×)
- conntrack 压力:NOTRACK 绕过 conntrack,大集群关键
- CoreDNS QPS 降 50-90%:大部分 query 节点本地命中
- 故障容忍:CoreDNS 全挂 cache 内 name 还能解析
部署坑:forward 上游必须指 kube-dns-upstream Service,不能指 kube-dns —— 否则 node-local-dns 自己 forward 给自己(都 bind 了 10.96.0.10),死循环 timeout。
Q5:etcd 灾备你怎么做?2 分钟恢复怎么测的?
snapshot save cron 每 4 小时 + 异地同步。
单节点损毁(剩 2/3 quorum,实测 2 分钟):member remove → 清 data dir → member add --learner → 改 manifest --initial-cluster-state=existing → 拉起,etcd 自动 promote voter。
整集群死从 snapshot 救:etcdctl snapshot restore + --initial-cluster-state=new(不是 existing),其他 cp kubeadm reset 后重 join。
Q6:Secret at-rest 加密怎么真生效?
4 步:
- 写 EncryptionConfiguration(aescbc 在前,identity 兜底读旧明文)
- 三 cp 放配置 + apiserver static pod 加
--encryption-provider-config+ volume mount - 滚动重启三 cp
kubectl get secrets -A -o json | kubectl replace -f -rewrite 历史 Secret,否则只对新写的生效
验证:etcdctl get /registry/secrets/... 看到 k8s:enc:aescbc:v1:key1: 前缀。
Q7:HPA 该用什么指标?vLLM 推理服务怎么扩?
普通应用:CPU / memory util。
LLM 推理:
- 不能用 CPU util:永远低,GPU 才是瓶颈
- 不能用 GPU util:永远 80%+,扩到 max 还是高
- 应该用
vllm:num_requests_waiting(队列深度,KEDA 接 Prometheus scaledobject)
Q8:CNI 切换需要清哪些残留?
K8s 层:Installation CR / DaemonSet / Deployment / Service / RBAC / CRD / Namespace(注意 finalizer,可能要 kubectl replace --raw .../finalize 强删)。
节点层(容易漏):
/etc/cni/net.d/*配置/opt/cni/bin/*二进制- iptables 自定义链
ip route flush proto bird(Calico 学到的路由)- 网络接口(
vxlan.calico/tunl0/cali*veth)
故事:装 Cilium 后跨节点带宽只有 Calico 的 20%,查路由表发现 BIRD proto 路由跟 Cilium 路由共存导致包走错下一跳,ip route flush proto bird 后反超 Calico 14%。
延伸
- CKA / CKS 真实考试:限时 2h,17-20 题,可查 kubernetes.io 文档但来不及现搜。把上面 20 题的 yaml 盲打练到 < 1 分钟。
- vimrc / kubectl alias:考前必备
k=kubectl+kn=kubectl -n+set ts=2 sw=2 etfor yaml。 - 进一步:CKA 之后看
kubectl debug/ ephemeral container / Gateway API(替代 Ingress)。CKS 之后看 falco runtime detection / OPA Gatekeeper(Kyverno 替代品对比)/ supply chain(cosign + SLSA)。