AI Infra 训练营
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • CI/CD 实战(MySQL+Go+Vue)
  • HPA/Ingress/Hubble 实战
  • 面试速查 + 真实踩坑
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
  • Day 0 · 环境与硬件

    • Day 0 新手现场接管 Runbook:先看懂,再动手
    • Day 0:5 节点裸 Ubuntu → K8s 装机基线
  • Week 1:K8s 内核 + 周边基础设施

    • Day 1:3 CP HA 集群 + CNI 选型 + DNS 调优
    • Day 2:控制面 deep dive + etcd 内核 + chaos drill
    • Day 3:CRD + Operator (kubebuilder 从 0 写)
    • Day 4:Longhorn 存储 + Cilium 二探(Hubble / NetworkPolicy / L7)
    • Day 5:PVC 在线扩容 + K8s 安全基线(RBAC / PSA / Secret 加密 / Kyverno)
    • Day 6:调度策略 + Prometheus / Loki 观测栈
    • Day 7:Harbor 私有镜像 + ArgoCD GitOps + Cilium WireGuard
  • Week 2:制品 + GitOps + AI Infra + 综合

    • Day 8:k3s 单节点 + NVIDIA Device Plugin + vLLM 跑 Qwen2.5-3B
    • Day 8(attempt 1):跨 WAN GPU 加入主集群(失败复盘)
    • Day 8:AlertManager 真接入 + PrometheusRule 实战
    • Day 8:集群内 CI 闭环 — Gitea + Jenkins + Kaniko
    • Day 9:Triton 多框架推理 + DCGM 跨集群可观测 + vLLM 实测
    • Day 10:MIG 硬切片 + AWQ 量化 + HPA Custom Metrics
    • Day 11:AI 业务端到端 —— chainlit + GitOps + 跨 WAN vLLM
    • Day 12:灾难恢复 + 生产事故注入
    • Day 13:LLM Operator + 多集群联邦 + Ambient Mesh + RAG
    • Day 14:CKA / CKS 真题演练 + 14 天技术栈横向汇总

Day 7:Harbor 私有镜像 + ArgoCD GitOps + Cilium WireGuard

集群已经在跑了,但还差三件事才像生产平台:镜像没地方放、部署还在 kubectl apply 手动操作、节点之间 Pod 流量是明文走 VXLAN。这一天把这三件事补上。

整篇分 A / B / C 三段:

  • A. Harbor —— helm 装 + 创 project + push 镜像 + K8s pull。踩三个坑(TLS commonName 强制、NodePort 端口当 internal port 用、containerd 默认 HTTPS 假设)
  • B. ArgoCD —— helm 装 + Application + 从 GitHub 自动 sync 30 秒完成
  • C. Cilium Service Mesh —— helm upgrade 开 WireGuard,5 节点 full-mesh 透明加密 Pod 流量

每段先讲做什么、给完整命令 + yaml,最后讲为什么这么做和踩到的坑。


A. Harbor 私有镜像仓库

A.1 helm 装 Harbor

走 helm.goharbor.io 官方 chart。NodePort 暴露,HTTP only(学习场景),存储全走 Day 4 装好的 Longhorn:

helm repo add harbor https://helm.goharbor.io

helm install harbor harbor/harbor \
  --namespace harbor --create-namespace \
  --set expose.type=nodePort \
  --set expose.tls.enabled=false \
  --set expose.nodePort.ports.http.port=30002 \
  --set persistence.persistentVolumeClaim.registry.storageClass=longhorn \
  --set persistence.persistentVolumeClaim.registry.size=10Gi \
  --set persistence.persistentVolumeClaim.database.storageClass=longhorn \
  --set persistence.persistentVolumeClaim.database.size=2Gi \
  --set persistence.persistentVolumeClaim.jobservice.jobLog.storageClass=longhorn \
  --set persistence.persistentVolumeClaim.jobservice.jobLog.size=1Gi \
  --set persistence.persistentVolumeClaim.redis.storageClass=longhorn \
  --set persistence.persistentVolumeClaim.redis.size=1Gi \
  --set persistence.persistentVolumeClaim.trivy.storageClass=longhorn \
  --set persistence.persistentVolumeClaim.trivy.size=1Gi \
  --set harborAdminPassword=bootcamp \
  --set externalURL=http://10.0.24.31:30002

Harbor 不是单进程,是 8 组件 / 11 Pod 的小集群:

组件作用PVC
coreAPI + 业务逻辑—
portalWeb UI(React)—
registry真正的 OCI registry(docker distribution)10Gi(镜像数据)
databasePostgres,meta / project / user2Gi
redissession + queue cache1Gi
jobservice异步任务(replication、scan)1Gi
trivy漏洞扫描 + 漏洞库1Gi
nginx入口反代 + 前端 routing—

总 PVC ~15 GiB,Longhorn 3 副本实际占盘 ~45 GiB。

A.2 真坑 #1:chart 2.15 强制 TLS commonName

第一次执行直接挂:

Error: INSTALLATION FAILED: execution error at
  (harbor/templates/nginx/secret.yaml:4:12):
  The "expose.tls.auto.commonName" is required!

Harbor chart 2.15 起把 expose.tls.auto.commonName 列为必填,即使根本走 HTTP NodePort 也强制要给一个名字。两条路:

  1. 彻底关掉 TLS:--set expose.tls.enabled=false —— 学习场景直接关
  2. 给个假 commonName + 用 self-signed:--set expose.tls.auto.commonName=harbor.local,生产 cert-manager 接 Let's Encrypt 或内 CA

教训:helm chart 的 required: 字段会随版本悄悄变化,挂掉时先看报错指向的模板行号,不要照着旧博客的 --set 列表抄。

A.3 真坑 #2:NodePort 端口直接当 internal port

Harbor 起来后看 Service:

ports:
- name: http
  nodePort: 30002
  port: 30002        # 不是 80
  targetPort: 8080

NodePort 上设的端口号直接也变成了 Service 的 port。这意味着集群内访问 Harbor 必须带 :30002:

# 错的,404
curl http://harbor.harbor/v2/

# 对的
curl http://harbor.harbor:30002/v2/

教训:Service 的 nodePort 和 port 是两个独立字段,但 Harbor chart 把它们绑成同一个值。后面 ArgoCD Application 引用 Harbor 镜像、配 imagePullSecret 时这个端口跑不掉。

A.4 验健康 + 进 UI

curl http://10.0.24.28:30002/api/v2.0/health | jq
# {"status": "healthy", "components": [...]}  共 8 个 healthy

UI:http://10.0.24.28:30002,admin / bootcamp。

A.5 创 project + push 镜像

K8s 节点上没装 docker(containerd 只跑容器不带 CLI),用 google 的 crane(go-containerregistry 二进制版)push —— 单二进制、支持 HTTP push、不依赖 daemon。

# 装 crane
curl -sL https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz \
  | tar -xz -C /tmp crane && mv /tmp/crane /usr/local/bin/

# 创 public project bootcamp(curl API,JSON body 写到文件避免 shell 嵌套引号地狱)
cat > /tmp/proj.json <<'EOF'
{"project_name":"bootcamp","metadata":{"public":"true"},"storage_limit":-1}
EOF
curl -u admin:bootcamp http://10.0.24.28:30002/api/v2.0/projects \
  -X POST -H 'Content-Type: application/json' -d @/tmp/proj.json

# crane copy:直接从 Docker Hub 拉 + push 到 Harbor,不落本地
crane copy nginx:1.27-alpine 10.0.24.28:30002/bootcamp/nginx:1.27-alpine --insecure

--insecure 让 crane 走 HTTP(生产 TLS 去掉)。push 20 秒完成,输出最后一行带 digest: sha256:65645c7b... size: 10333。

A.6 真坑 #3:containerd 默认假设 HTTPS

push 完立刻试在 K8s 里 pull kubectl run harbor-pull-test --image=10.0.24.28:30002/bootcamp/nginx:1.27-alpine → ErrImagePull。kubectl describe pod 看到根因:

failed to do request: Head "https://10.0.24.28:30002/v2/...":
  http: server gave HTTP response to HTTPS client

containerd 看到 host:port 格式默认就当 HTTPS,Harbor 配的是 HTTP。Day 1 给 docker.io 配 mirror 用过 certs.d,这里复用同一套机制告诉 containerd「这个 registry 是 HTTP」。

每个节点写 /etc/containerd/certs.d/10.0.24.28:30002/hosts.toml:

server = "http://10.0.24.28:30002"
[host."http://10.0.24.28:30002"]
  capabilities = ["pull", "resolve", "push"]
  skip_verify = true

关键三点:

  1. 5 个节点都要写 —— 任一节点都可能调度到拉 Harbor image 的 Pod
  2. 目录名带端口 —— 10.0.24.28:30002,不是只写 IP
  3. 不用重启 containerd —— containerd 监听 certs.d 目录,写完文件立刻生效,这是新 certs.d 模式相对老 registry.mirrors 的最大优势

再 kubectl run 一次,734ms 拉完,kubectl describe 看到 Image ID: 10.0.24.28:30002/bootcamp/nginx@sha256:65645c7b... —— 自动带 digest。生产 Pod 应该用 image@sha256:... 替代 image:tag,tag 可以被覆盖(push 同 tag 不同内容),digest 是内容寻址防止镜像被静默替换。

A.7 Trivy 漏洞扫描

UI 点 artifact 旁的 Scan 触发 trivy 扫这一个镜像,CI 走 API:

curl -u admin:bootcamp -X POST \
  http://10.0.24.28:30002/api/v2.0/projects/bootcamp/repositories/nginx/artifacts/sha256:65645c7b.../scan

trivy 维护 CVE 数据库(jobservice 定期 update),扫完按 Critical / High / Medium / Low 分级。CI/CD 用 API 配「High 以上不让上线」的卡口。


B. ArgoCD GitOps

B.1 为什么 pull 模式比 push 模式安全

传统 CI/CD 是 push 模式:git push → CI 跑测试 + build → CI 拿 kubectl 凭证 → kubectl apply 到集群。三个问题:凭证存在 CI runner 里(CI 被打穿 npm 供应链 / Jenkins 0day 凭证立刻泄漏);漂移检测难(有人手动 kubectl edit Git 里看不到);多集群难(N 集群 N 套凭证发给 CI)。

GitOps pull 模式反过来:git push → ArgoCD 从集群内 watch repo → 拉到本地 → diff 当前集群状态 → reconcile。凭证不出集群,漂移由 ArgoCD 自己检测(OutOfSync),新集群只需要装一份 ArgoCD 指同一个 Git,N 集群零额外凭证。

B.2 ArgoCD 的 4 个核心 CRD

CRD作用类比
Application一个待同步目标:repo + path + dest namespace一个「应用」
AppProject一组 Application 的边界:限定 source repo / dest namespace / 资源类型一个「租户」
Repositorygit / helm / oci 的凭证(私库才需要)「代码源」
ApplicationSet用一份模板批量生成 Application(dev/staging/prod 三套)「环境矩阵」

B.3 helm 装 ArgoCD

helm repo add argo https://argoproj.github.io/argo-helm

helm install argocd argo/argo-cd \
  --namespace argocd --create-namespace \
  --set server.service.type=NodePort \
  --set server.service.nodePortHttp=30080 \
  --set 'configs.params.server\.insecure=true'

server.insecure=true 让 argocd-server 走 HTTP。装完起来 7 个 Pod:application-controller(StatefulSet,reconcile 主引擎)+ applicationset-controller / dex-server / notifications-controller / redis / repo-server / server(Deployment)。架构是微服务 —— Git 拉取(repo-server)和 reconcile(application-controller)分开,避免一个 huge repo 阻塞所有 sync。

进 UI:

kubectl get secret argocd-initial-admin-secret -n argocd \
  -o jsonpath='{.data.password}' | base64 -d
# EfqU4EiWmQ9frc6B

http://10.0.24.31:30080,admin / 上面输出的密码。

B.4 第一个 Application:guestbook auto-sync

跑通端到端的最小例子,从 ArgoCD 官方示例 repo 同步一个 guestbook:

# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc        # 本集群
    namespace: argocd-demo
  syncPolicy:
    automated:
      prune: true       # Git 里删了的 yaml → 集群里也删
      selfHeal: true    # 集群被手改 → 强制 sync 回 Git 版本
    syncOptions:
    - CreateNamespace=true

三个字段决定 GitOps 行为:selfHeal: true 漂移防护(kubectl edit 改了 30 秒内强制 sync 回 Git 版本);prune: true Git 里删了 yaml 集群里也删(不开会变 Orphaned 残留);CreateNamespace=true ArgoCD 自动建 destination namespace。

kubectl apply -f argocd-app.yaml
# 30 秒后
kubectl get application -n argocd
# NAME        SYNC STATUS   HEALTH STATUS
# guestbook   Synced        Healthy

kubectl get all -n argocd-demo
# pod/guestbook-ui-7689b675bc-99qhk   1/1   Running
# service/guestbook-ui                ClusterIP
# deployment.apps/guestbook-ui        1/1

30 秒内完成:ArgoCD 自动 clone GitHub → render yaml → 创 namespace → apply Deployment + Service。Application 的 history.initiatedBy.automated: true 字段表明是完全自动 sync,没有人手介入。

B.5 App of Apps:管 100+ Application

Production 集群 50-200 个 Application,一个个 kubectl apply 不现实,标准姿势是 App of Apps:

git repo root/
├── apps/
│   ├── prod/{frontend,backend,...}.yaml   # 每个文件是一个 Application 资源
│   ├── staging/...
│   └── dev/...
├── infra/{ingress-nginx,cert-manager,...}.yaml
└── apps-of-apps.yaml                      # ONE Application 指向 apps/

apps-of-apps.yaml 是个特殊 Application,source path 是 apps/。apply 后 ArgoCD 把整个 apps/ 当 K8s yaml 渲染 —— 里面是一堆 Application 资源 —— 这些 Application 又被 ArgoCD 拉起,各自同步真实业务。一层 bootstrap → N 个 Application 自动生成。集群被炸,重装 ArgoCD + apply 这一个根 Application,整个平台自动复原。

B.6 AppProject:多团队隔离

多团队场景用 AppProject 限定边界:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata: {name: team-a, namespace: argocd}
spec:
  sourceRepos: ['https://github.com/orgname/team-a-*']         # 只许从这些 repo 同步
  destinations:
  - {server: 'https://kubernetes.default.svc', namespace: 'team-a-*'}
  clusterResourceWhitelist:
  - {group: '', kind: 'Namespace'}                              # cluster 级资源只允许 Namespace
  namespaceResourceBlacklist:
  - {group: '', kind: 'ResourceQuota'}                          # 禁改 ResourceQuota

team-a 工程师只能从 team-a-* repo 同步、只能往 team-a-* namespace 部署、不能动 cluster 级资源。


C. Cilium Service Mesh:WireGuard 透明加密

Day 1 装 Cilium 时只开了 dataplane,没启加密。VXLAN 封装的内层 Pod 流量是明文 —— 节点之间网络一旦被中间人嗅探,所有 Pod 通信暴露。这一段把 WireGuard 加密打开。

C.1 sidecar-less 和加密方案选型

Istio / Linkerd 每 Pod 一个 sidecar(Envoy / Linkerd-proxy):应用透明、能做 L7 mTLS / retry,但 Pod 数 × 2 资源爆炸、启动顺序 race、升级要重启所有 Pod。

Cilium Service Mesh 是 sidecar-less:每节点 cilium-agent(eBPF)+ 一个 cilium-envoy DaemonSet(只在需要 L7 时走)。0 sidecar、eBPF 在 socket layer hook 性能近原生、跟 CNI 一体没 race。代价:复杂 L7 retry / outlier detection 还是 Istio 强项。

加密方案 Cilium 提供两种:

WireGuardIPsec
协议层UDP 上封装(L3 over UDP)内核 IPsec ESP/AH
密钥协商Noise Protocol(静态)IKEv2(动态)
性能极佳(内核态、流式 crypto)中(IKE 协商开销)
配置一行 helm 开关要管 PSK / cert
FIPS 合规否是

学习场景选 WireGuard:性能最好、配置最简、Cilium 默认推荐。FIPS 合规才上 IPsec。

C.2 helm upgrade 启用 WireGuard

helm repo add cilium https://helm.cilium.io

helm upgrade cilium cilium/cilium --reuse-values \
  --namespace kube-system \
  --version 1.16.5 \
  --set encryption.enabled=true \
  --set encryption.type=wireguard

--reuse-values 保留 Day 1 装 Cilium 时设的一堆参数(镜像 mirror、VXLAN tunnel、k8sServiceHost、Hubble),只追加 encryption 两条。生产推荐 helm get values > cilium-values.yaml 编辑后 helm upgrade -f 把 value 进 Git。

C.3 真坑 #4:helm upgrade 不触发 DaemonSet rolling

upgrade 完跑:

kubectl get pods -n kube-system -l k8s-app=cilium
# cilium-xxxx   1/1   Running   0   14h    <- 14h 没重启

cilium status 显示 Encryption: Disabled。根因:helm 更新了 ConfigMap(enable-wireguard: "true"),但 DaemonSet 的 Pod template 没改(env、args 都没变),generation 不变 → kubelet 不触发 rolling。

手动滚:

kubectl rollout restart ds cilium -n kube-system

经验:helm upgrade 改 ConfigMap 但 Pod 是启动时读 env / volumeMount,运行中不刷新。改了 ConfigMap 影响 Pod 行为的场景都要手动 rollout restart,不要假设 helm 帮你做。

C.4 验证 5 节点 WireGuard 跑起来

三个验证维度:

# 1. 每节点的 cilium_wg0 接口存在
for h in m1 m2 m3 m4 m5; do
  ssh $h 'ip -br addr show cilium_wg0'
done

# 2. 每节点 51871/UDP 在监听(WireGuard 端口)
for h in m1 m2 m3 m4 m5; do
  ssh $h 'ss -ulnp | grep 51871'
done

# 3. Cilium 自报加密状态
kubectl exec -n kube-system ds/cilium -- cilium encrypt status

预期输出:

1. 5 节点都有 cilium_wg0(UNKNOWN 是 WireGuard 接口的正常 state,没有 link 概念)
2. 5 节点都监听 0.0.0.0:51871 UDP
3. cilium encrypt status:
   Encryption: Wireguard
   Interface: cilium_wg0
   Public key: pXDFi7SuGrm1ezq+IlAJWiB4WumMJbhl3oOGjXZ0mi8=
   Number of peers: 4         <- 4 个,自己不算 peer,5 节点全 mesh

peers: 4 是关键:每节点跟其他 4 个建立 WireGuard tunnel,5 节点 full-mesh,新加节点 cilium-agent 自动协商不用人手配密钥。

C.5 数据面流程和性质

Pod A (cp-1, 10.244.3.x) ──HTTP──>
  cilium-agent: 查 endpoint map, Pod B 在 cp-2
  ↓ eBPF redirect 到 cilium_wg0
  WireGuard 内核模块: 用 cp-1 私钥加密
  ↓ UDP 51871 → 10.0.24.29:51871 (cp-2)
  cp-2 内核 WireGuard 解密
  ↓ cilium-agent → Pod B (10.244.4.x)

关键性质:

  • 完全应用透明 —— Pod 不需任何改动,没有 sidecar 也没有 SDK
  • 加密仅节点间 —— 同节点 Pod 间通信走 eBPF 内存拷贝,不走 wg
  • VXLAN 包嵌在 wg 里 —— Day 1 配的 VXLAN tunnel 还在,外层 IP → UDP(wg) → IP → UDP(vxlan) → payload。多一层 crypto 的 CPU 开销 ~5-10%,比 mTLS(30%+)轻量
  • 没有证书过期 —— Noise Protocol 静态密钥 cilium-agent 启动时生成写入 ConfigMap,不像 mTLS 要管 cert rotation
  • NodeEncryption 默认关 —— 只 Pod-to-Pod 加密,host network 流量(kubelet → apiserver、etcd peer)不加。合规要求全加加 --set encryption.nodeEncryption=true,代价 control-plane CPU 多一份

wg 跟 L7 mTLS 不冲突而是叠加:wg 保「节点间链路不被嗅探」,mTLS 保「服务间身份验证」(攻陷 Pod 没合法 SPIFFE ID 也连不上目标)。学习场景只开 wg 够。


总结:Day 7 后平台形态

集群上新增三件能力:

模块状态验证
HarborOK8 component healthy,crane push + K8s pull 734ms,Trivy 漏洞扫描可用
ArgoCDOK7 Pod,Application Synced + Healthy,30 秒自动 sync 完成
Cilium WGOK5 节点 cilium_wg0,51871/UDP 监听,4 peers full-mesh,应用透明

累计开放端口:

服务NodePort凭据
Grafana32380admin / bootcamp
Longhorn UI31172—
Hubble UI30527—
Harbor30002admin / bootcamp
ArgoCD30080admin / EfqU4EiWmQ9frc6B

面试常见题

Q1:Harbor 比 Docker Hub 优势在哪?什么场景必须自建?

四点:

  1. 项目级 RBAC —— Docker Hub 的 org/team 粒度粗,Harbor 在 project 内分 admin/maintainer/developer/guest 四角色按团队隔离
  2. Trivy 漏洞扫描 —— Harbor 内嵌 trivy,CI 调 API 做「High 以上不让发布」的卡口;Docker Hub vulnerability scan 收费且只扫公共镜像
  3. 镜像复制 / GC —— Harbor 支持 replication 到多地 + 定时 GC 清未引用 layer
  4. 私有 + 内网 —— 没公网出口的离线环境、镜像不出公司的合规要求,必须自建

必须自建场景:金融 / 医疗 / 政府等合规要求、离线 / 弱外网 IDC、CI 频繁 push 想省外网带宽。

Q2:ArgoCD 的 pull 模式比传统 CI/CD 的 push 模式好在哪?

三层优势:

  1. 凭证不出集群 —— CI 不持有 kubectl 凭证,CI 被打穿(npm 供应链 / Jenkins 0day)不会失陷 K8s。pull 模式只 ArgoCD 在集群里读 Git
  2. 漂移检测 —— 有人手动 kubectl edit 改了 Deployment,push 模式 Git 不知道;ArgoCD reconcile loop 立刻看到 OutOfSync,selfHeal: true 强制改回
  3. 多集群零增量凭证 —— 加新集群只在那个集群装 ArgoCD 指同一个 Git,不用给 CI 再发凭证

代价:Git 必须是完整的「期望状态」,临时 kubectl edit 调试会被 selfHeal 吃掉,要先 disable auto-sync 再调。

Q3:containerd 的 certs.d 新机制比老 mirrors 配置区别在哪?

老 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 模式:配在 /etc/containerd/config.toml 主配置里,改完必须 systemctl restart containerd,重启会让正在拉镜像的 Pod 失败。

新 certs.d 模式(containerd 1.5+,需要 config_path = '/etc/containerd/certs.d' 打开):每个 registry 一个子目录(docker.io/、quay.io/、10.0.24.28:30002/),各一份 hosts.toml。containerd 监听目录 inotify,改 hosts.toml 立刻生效不用 restart。维护上每个 registry 独立文件,可单独 commit / ansible 分发。

Q4:Cilium WireGuard 跟 IPsec 加密怎么选?

WireGuardIPsec
性能优,UDP 流式 crypto中,IKE 协商开销
配置一行 helm 开关要管 PSK / cert
密钥Noise Protocol 静态IKEv2 动态
FIPS 合规否是

选型:一般业务 WireGuard(性能最好、配置最简);金融 / 政府合规要 FIPS 140-2 认证选 IPsec;老内核(CentOS 7,内核 < 5.6)wg 不稳定也得 IPsec。Day 0 装的 Ubuntu 22 内核 5.15 完美支持 wg。

Q5:为什么 Pod 应该用 image digest pinning 而不是 tag?

image: nginx:1.27-alpine 两个问题:

  1. 同一 tag 可被覆盖 —— 作者可以 push nginx:1.27-alpine 推新 build(修 bug / 加后门),下次 Pod 重启拉到不同内容
  2. 缓存不一致 —— 节点 A 是 cached 旧版本、节点 B 新拉是新版本,同一 Deployment 跑出两个不同 image

image: nginx@sha256:65645c7b... 用 digest pinning:sha256 哈希内容寻址,任何字节修改会改变 digest,5 节点必定拉到同一字节序列。供应链攻击场景上游被打穿换镜像,digest 对不上 K8s 直接 ErrImagePull 暴露异常。

操作:CI build 完拿到 @sha256:xxx,写回 git,ArgoCD 用 digest 引用 sync。配 argocd-image-updater 可以自动从 Harbor 拉新 digest 提 PR。


下一步

Day 7 之后平台具备私有镜像、GitOps 部署、节点间 Pod 加密三件套。Day 8 进入 Pod 安全和准入控制:PodSecurityStandard、Kyverno / OPA Gatekeeper 写策略卡口、image 准入(必须从 Harbor 拉、必须带 digest、Trivy High 以上禁上线)、secret 管理(External Secrets Operator + Vault)。

在 GitHub 上编辑此页
Prev
Day 6:调度策略 + Prometheus / Loki 观测栈