跳转至

Cilium 运维学习与实验手册

适用对象:已经搭建过 Cilium VXLAN、Native Routing、Hubble 的 Kubernetes 运维人员。

0. 接下来到底要学什么

已经做过:

  • VXLAN 模式:理解跨节点 Pod 流量可以通过 overlay 封装转发。
  • Native Routing 模式:理解 PodCIDR 可以直接通过底层网络路由转发。
  • Hubble:能观察 Pod 间、Pod 到外部、Service 相关流量。

接下来建议按这个顺序学:

  1. Cilium Network Policy:会做默认拒绝、精确放行、DNS/FQDN、HTTP L7。
  2. 排障命令体系:会用 cilium status、cilium connectivity test、hubble observe、cilium-dbg monitor。
  3. 升级与回滚:会看 Helm values、preflight、版本路径、风险点。
  4. kube-proxy replacement:理解 Service、NodePort、LoadBalancer 由谁处理。
  5. 监控告警:Prometheus/Grafana/Hubble metrics。
  6. Egress Gateway:固定出口 IP,满足防火墙白名单和审计需求。
  7. 裸金属入口:LB IPAM、L2 Announcements、BGP Control Plane,根据环境选择。

官方文档入口:

  • Cilium 文档首页:https://docs.cilium.io/
  • Network Policy:https://docs.cilium.io/en/stable/security/policy/
  • Deny Policy:https://docs.cilium.io/en/stable/security/policy/deny/
  • L7/DNS/FQDN Policy:https://docs.cilium.io/en/stable/security/policy/layer7/
  • Troubleshooting:https://docs.cilium.io/en/stable/operations/troubleshooting/
  • Hubble Setup:https://docs.cilium.io/en/stable/observability/hubble/setup/
  • Metrics:https://docs.cilium.io/en/stable/observability/metrics/
  • Upgrade:https://docs.cilium.io/en/stable/operations/upgrade/
  • kube-proxy replacement:https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/
  • Egress Gateway:https://docs.cilium.io/en/stable/network/egress-gateway/egress-gateway/
  • BGP Control Plane:https://docs.cilium.io/en/stable/network/bgp-control-plane/bgp-control-plane/
  • L2 Announcements:https://docs.cilium.io/en/stable/network/l2-announcements/
  • LB IPAM:https://docs.cilium.io/en/stable/network/lb-ipam/

1. 实验前提

1.1 集群要求

建议用测试集群做实验,至少 2 个节点更好:

  • Kubernetes 集群已安装 Cilium。
  • 你有 kubectl 管理权限。
  • 已安装 cilium CLI。
  • 已安装 hubble CLI,或者能进入 Cilium Pod 内执行 Hubble 相关命令。
  • Cilium agent 状态正常。

检查:

kubectl get nodes -o wide
kubectl get pods -n kube-system -l k8s-app=cilium -o wide
cilium version
cilium status

预期:

  • cilium status 显示 Cilium、Operator 正常。
  • 每个节点有一个 Cilium agent Pod。
  • 如果启用了 Hubble,状态里能看到 Hubble OK。

1.2 不建议直接在生产做的实验

以下内容可能影响集群转发路径或生产流量,优先在测试/预发环境执行:

  • 升级、降级、回滚。
  • kube-proxy replacement 开关调整。
  • Egress Gateway 全局启用。
  • BGP Control Plane、L2 Announcements。
  • Clusterwide 默认拒绝策略。

1.3 创建实验命名空间

kubectl create namespace cilium-lab
kubectl label namespace cilium-lab purpose=cilium-lab

部署基础服务:

kubectl -n cilium-lab run client --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/curlimages/curl:8.8.0 --labels=app=client -- sleep 365d

kubectl -n cilium-lab run client2 --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/curlimages/curl:8.8.0 --labels=app=client2 -- sleep 365d

kubectl -n cilium-lab create deployment web --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/nginx-slim:0.21
kubectl -n cilium-lab label deployment web app=web
kubectl -n cilium-lab expose deployment web --port=80 --target-port=80
kubectl -n cilium-lab get pods -o wide
kubectl -n cilium-lab get svc

验证没有策略时的默认连通性:

kubectl -n cilium-lab exec deploy/web -- sh -c 'echo ok > /usr/share/nginx/html/index.html'
kubectl -n cilium-lab exec client -- curl -sS --max-time 3 http://web
kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

预期:

ok
ok

理论点:

  • Cilium 没有匹配策略时,默认允许 Pod 通信。
  • 一旦某个 Pod 被 ingress 或 egress policy 选中,它会进入对应方向的 default-deny。
  • Cilium 的 identity 基于标签,不是简单基于 Pod IP。Pod 重建后 IP 变了,只要标签没变,策略仍然有效。

2. 实验一:L3/L4 Ingress Policy

2.1 理论目标

你要掌握:

  • endpointSelector 选择被保护的目标 Pod。
  • fromEndpoints 选择允许访问的来源 Pod。
  • toPorts 限制端口和协议。
  • 只要策略选中了目标 Pod,未显式允许的同方向流量就会被拒绝。

运维场景:

  • 只允许某个业务访问数据库。
  • 只允许网关访问后端服务。
  • 阻断同命名空间内非授权横向访问。

2.2 应用策略

创建只允许 app=client 访问 app=web 的 80/TCP 策略:

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-client-to-web
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: client
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

2.3 验证

kubectl -n cilium-lab exec client -- curl -sS --max-time 3 http://web
kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

预期:

  • client 成功。
  • client2 超时或连接失败。

进一步观察策略映射:

kubectl -n cilium-lab get cnp
kubectl -n kube-system exec ds/cilium -- cilium-dbg endpoint list

2.4 Hubble 验证

另开一个终端:

hubble observe --namespace cilium-lab --follow

再执行:

kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

你应该能看到 DROPPED 或 policy denied 相关记录。

2.5 结论

这个实验支撑的理论:

  • 策略不是绑定 IP,而是绑定标签身份。
  • Ingress policy 选中服务端 Pod 后,默认拒绝未匹配来源。
  • L4 端口必须显式写清楚,否则容易出现“能 ping 但 curl 不通”或“同服务不同端口不通”。

3. 实验二:Egress Default Deny 与 DNS 放行

3.1 理论目标

你要掌握:

  • Egress 策略保护的是“从 Pod 发出去”的方向。
  • 一旦 Pod 被 egress policy 选中,未允许的外联会被拒绝。
  • 很多外联依赖 DNS,放行 HTTP/HTTPS 但忘了 DNS,是常见故障。

运维场景:

  • 限制业务 Pod 只能访问指定外部域名。
  • 防止 Pod 随意访问公网。
  • 排查“外网不通但 Service 正常”的问题。

3.2 先验证当前外联

kubectl -n cilium-lab exec client -- nslookup cilium.io
kubectl -n cilium-lab exec client -- curl -I --max-time 5 https://cilium.io

如果 curlimages/curl 镜像没有 nslookup,可用:

kubectl -n cilium-lab exec client -- curl -v --max-time 5 https://cilium.io

3.3 应用只允许 DNS 的 egress 策略

下面策略只允许 client 查询 kube-dns,不允许真正访问外部 HTTP/HTTPS:

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: client-egress-dns-only
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: client
  egress:
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
        k8s:k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP
      - port: "53"
        protocol: TCP
      rules:
        dns:
        - matchPattern: "*"
EOF

验证:

kubectl -n cilium-lab exec client -- curl -I --max-time 5 https://cilium.io

预期:

  • DNS 可能解析成功。
  • 连接 https://cilium.io 失败,因为 443/TCP 没放行。

3.4 放行指定 FQDN 的 HTTPS

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: client-egress-cilium-io
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: client
  egress:
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
        k8s:k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP
      - port: "53"
        protocol: TCP
      rules:
        dns:
        - matchPattern: "*"
  - toFQDNs:
    - matchName: cilium.io
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP
EOF

验证:

kubectl -n cilium-lab exec client -- curl -I --max-time 5 https://cilium.io
kubectl -n cilium-lab exec client -- curl -I --max-time 5 https://example.com

预期:

  • https://cilium.io 成功。
  • https://example.com 失败。

3.5 结论

这个实验支撑的理论:

  • Egress default-deny 后,DNS 和目标连接要分别放行。
  • toFQDNs 依赖 DNS 代理学习域名解析结果。
  • 官方文档提醒,DNS L7 策略应优先拦截集群 DNS 服务,避免把不可信 DNS 响应纳入策略决策。

清理:

kubectl -n cilium-lab delete cnp client-egress-dns-only client-egress-cilium-io  allow-client-to-web --ignore-not-found

4. 实验三:HTTP L7 Policy

4.1 理论目标

你要掌握:

  • Cilium 可以在 L7 HTTP 层按方法和路径放行。
  • L7 policy 会通过 Envoy 代理相关流量。
  • HTTP L7 不匹配通常返回应用层拒绝,比如 HTTP 403,而不是简单网络超时。

运维场景:

  • 只允许调用 /healthz、/public。
  • 内部服务之间按 API 路径做最小权限。
  • 审计某个接口是否被非授权服务访问。

4.2 准备测试页面

kubectl -n cilium-lab exec deploy/web -- sh -c 'echo public > /usr/share/nginx/html/public'
kubectl -n cilium-lab exec deploy/web -- sh -c 'echo private > /usr/share/nginx/html/private'

4.3 应用 L7 策略

只允许 app=client 对 app=web 执行 GET /public:

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-client-get-public
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: client
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/public"
EOF

4.4 验证

kubectl -n cilium-lab exec client -- curl -i --max-time 3 http://web/public
kubectl -n cilium-lab exec client -- curl -i --max-time 3 http://web/private
kubectl -n cilium-lab exec client2 -- curl -i --max-time 3 http://web/public

预期:

  • client 访问 /public 成功。
  • client 访问 /private 返回 403 或被拒绝。
  • client2 访问 /public 失败,因为来源身份不匹配。

4.5 结论

这个实验支撑的理论:

  • L3/L4 决定谁可以连接到哪个端口。
  • L7 决定连接到端口后可以访问哪个 HTTP 方法和路径。
  • L7 policy 会引入代理链路,排障时要关注 Cilium Envoy 状态。

清理:

kubectl -n cilium-lab delete cnp allow-client-get-public --ignore-not-found

4.6 只允许baidu出战

client -->baidu

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: client-egress-fqdn-only
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: client
  egress:
  - toEndpoints:
    - matchLabels:
        k8s:io.kubernetes.pod.namespace: kube-system
        k8s:k8s-app: kube-dns
    toPorts:
    - ports:
      - port: "53"
        protocol: UDP
      - port: "53"
        protocol: TCP
      rules:
        dns:
        - matchPattern: "*"

  - toFQDNs:
    - matchPattern: "*.baidu.com" #- matchName: baidu.com  为匹配单个不可以泛匹配
    - matchPattern: "baidu.com"   
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP

4.7验证

kubectl -n cilium-lab exec client -- curl -sS --max-time 3 https://jd.com
curl: (28) Connection timed out after 3001 milliseconds
command terminated with exit code 28


kubectl -n cilium-lab exec client -- curl -sS --max-time 3 https://baidu.com
<a href="https://www.baidu.com/">Moved Permanently</a>.

5. 实验四:Deny Policy 优先级

5.1 理论目标

你要掌握:

  • Deny policy 优先级高于 allow policy。
  • Deny policy 适合做明确禁止,例如禁止来自 world、禁止某个命名空间访问敏感服务。
  • 官方文档说明 Deny policy 不支持 L7 deny 和 toFQDNs deny。

运维场景:

  • 明确阻断某类东西,即使其它 allow policy 放行了。
  • 做临时封禁。
  • 做安全兜底。

5.2 先放行 client 和 client2 到 web

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-all-lab-clients-to-web
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: client
    - matchLabels:
        app: client2
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

验证两者都能访问:

kubectl -n cilium-lab exec client -- curl -sS --max-time 3 http://web
kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

5.3 增加 Deny Policy 禁止 client2

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-client2-to-web
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: web
  ingressDeny:
  - fromEndpoints:
    - matchLabels:
        app: client2
EOF

验证:

kubectl -n cilium-lab exec client -- curl -sS --max-time 3 http://web
kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

预期:

  • client 成功。
  • client2 失败。

5.4 结论

这个实验支撑的理论:

  • 多条 allow policy 不能覆盖 deny policy。
  • 当你看到“明明有 allow 但流量还是被拒绝”,要检查是否存在 deny。

清理:

kubectl -n cilium-lab delete cnp allow-all-lab-clients-to-web deny-client2-to-web --ignore-not-found

6. 实验五:Hubble 观测与排障

6.1 理论目标

你要掌握:

  • Hubble 看的是 Cilium 管理端点的 flow。
  • 它可以告诉你流量方向、来源 identity、目标 identity、协议、端口、是否转发、是否丢弃、被什么策略影响。
  • 官方排障文档强调,Pod 必须由 Cilium 管理才可被 Hubble 观测。

运维场景:

  • 业务报“服务不通”,你要判断是 DNS、策略、Service、节点、外部网络哪一层。
  • 安全报“某 Pod 访问外网”,你要快速定位来源和目的地。

6.2 基础状态

cilium status
hubble status

如果本地 hubble 无法连接 Relay:

cilium hubble port-forward &
hubble status

6.3 观察 namespace 流量

hubble observe --namespace cilium-lab

指定 Pod:

hubble observe --namespace cilium-lab --pod client

只看 drop:

hubble observe --namespace cilium-lab --verdict DROPPED

只看 HTTP:

hubble observe --namespace cilium-lab --protocol http

6.4 制造一次策略拒绝

应用只允许 client 到 web,然后用 client2 访问:

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: hubble-drop-demo
  namespace: cilium-lab
spec:
  endpointSelector:
    matchLabels:
      app: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: client
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

观察:

hubble observe --namespace cilium-lab --verdict DROPPED --follow

触发:

kubectl -n cilium-lab exec client2 -- curl -sS --max-time 3 http://web

6.5 Cilium agent 本地观察

进入任意 Cilium Pod:

kubectl -n kube-system exec ds/cilium -- cilium-dbg status --verbose
kubectl -n kube-system exec ds/cilium -- cilium-dbg endpoint list
kubectl -n kube-system exec ds/cilium -- cilium-dbg monitor --type drop

说明:

  • hubble observe 更适合日常按 namespace/pod/service 过滤。
  • cilium-dbg monitor --type drop 更底层,适合确认 datapath 丢包原因。

6.6 结论

这个实验支撑的理论:

  • Cilium 排障不要只看 Kubernetes Event。
  • 先看 flow verdict,再看策略,再看 endpoint identity,再看 datapath drop reason。
  • Hubble 能把“网络不通”转换成“谁访问谁、在哪一层被拒绝”。

清理:

kubectl -n cilium-lab delete cnp hubble-drop-demo --ignore-not-found

7. 实验六:标准连通性测试

7.1 理论目标

你要掌握:

  • cilium connectivity test 是 Cilium 官方推荐的连通性验证工具。
  • 它会自动创建测试 workload,覆盖 Pod-to-Pod、Service、DNS、NetworkPolicy、NodePort 等场景。
  • 升级前后、变更前后都应该跑。

7.2 执行测试

cilium connectivity test

如果你的集群没有公网访问,部分镜像拉取或外部访问测试可能失败。可以先记录失败项,区分是环境限制还是 Cilium 问题。

7.3 变更前后对比

建议每次重大变更都记录:

cilium status > cilium-status-before.txt
cilium connectivity test | tee cilium-connectivity-before.txt

变更后:

cilium status > cilium-status-after.txt
cilium connectivity test | tee cilium-connectivity-after.txt

7.4 结论

这个实验支撑的理论:

  • 运维变更需要可重复验证,而不是凭感觉。
  • connectivity test 可以作为升级、参数调整、内核升级后的冒烟测试。

8. 实验七:升级与回滚演练

风险等级:高。只建议测试/预发环境执行。
官方升级文档要求先完整阅读目标版本升级说明,并执行 preflight。官方文档也说明,经过测试的升级/回滚路径通常是相邻 minor 版本。

8.1 理论目标

你要掌握:

  • Cilium 升级不只是换镜像,还涉及 CRD、agent、operator、Envoy、Helm values。
  • 升级前要保存现有 values。
  • 不应盲目使用 helm upgrade --reuse-values,因为旧 values 可能与新 chart 行为不匹配。
  • kube-proxy-free 集群生成 preflight 时需要设置 Kubernetes API Server 地址和端口。

8.2 记录当前状态

cilium version
cilium status
helm -n kube-system list
helm -n kube-system get values cilium -o yaml > cilium-values-current.yaml
helm -n kube-system get manifest cilium > cilium-manifest-current.yaml
kubectl get ciliumnetworkpolicies --all-namespaces
kubectl get ciliumclusterwidenetworkpolicies
cilium connectivity test | tee cilium-connectivity-before-upgrade.txt

8.3 查看当前 Helm values 中的关键项

重点检查:

grep -E "tunnel|routingMode|kubeProxyReplacement|hubble|ipam|bpf|egressGateway|operator|envoy" cilium-values-current.yaml

如果 PowerShell:

Select-String -Path .\cilium-values-current.yaml -Pattern "tunnel|routingMode|kubeProxyReplacement|hubble|ipam|bpf|egressGateway|operator|envoy"

8.4 Preflight

示例,实际版本请替换为目标版本:

helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium-preflight cilium/cilium \
  --version <target-version> \
  --namespace kube-system \
  --set preflight.enabled=true \
  --set agent=false \
  --set operator.enabled=false

检查:

kubectl -n kube-system get ds cilium cilium-pre-flight-check
kubectl -n kube-system get deploy cilium-pre-flight-check

预期:

  • cilium-pre-flight-check DaemonSet READY 数量等于 Cilium DaemonSet READY 数量。
  • preflight Deployment READY 为 1/1。

清理 preflight:

helm -n kube-system uninstall cilium-preflight

8.5 升级演练

不要直接复制这条命令到生产。先根据你的 cilium-values-current.yaml 和目标版本 release notes 修正 values。

helm upgrade cilium cilium/cilium \
  --version <target-version> \
  --namespace kube-system \
  -f cilium-values-current.yaml

观察:

kubectl -n kube-system rollout status ds/cilium
kubectl -n kube-system rollout status deploy/cilium-operator
cilium status
cilium connectivity test | tee cilium-connectivity-after-upgrade.txt

8.6 回滚思路

生产前必须准备:

  • 当前 chart 版本。
  • 当前 image 版本。
  • 当前 Helm values。
  • 当前 Cilium CRD 版本和备份。
  • 回滚验证命令。

回滚一般使用:

helm -n kube-system history cilium
helm -n kube-system rollback cilium <revision>
kubectl -n kube-system rollout status ds/cilium
cilium status
cilium connectivity test

8.7 结论

这个实验支撑的理论:

  • Cilium 是集群网络平面,升级失败影响面很大。
  • 升级必须可验证、可回滚、可对比。
  • 版本路径和 preflight 不是形式主义,是为了提前发现镜像、CRD、策略兼容问题。

9. 实验八:kube-proxy replacement

风险等级:中到高。不要在生产临时开关。
如果你的集群已经开启 kube-proxy replacement,本实验只做验证;如果没开启,先在测试集群安装或重装时启用。

9.1 理论目标

你要掌握:

  • kube-proxy 原本处理 Kubernetes Service 转发。
  • Cilium kube-proxy replacement 开启后,ClusterIP、NodePort、LoadBalancer、externalIPs、HostPort 等 Service 行为由 Cilium eBPF datapath 处理。
  • Service 故障排查时,要同时看 Kubernetes Service/EndpointSlice 和 Cilium service map。

9.2 查看是否启用

cilium status
kubectl -n kube-system exec ds/cilium -- cilium-dbg status --verbose | grep -i kube

PowerShell:

kubectl -n kube-system exec ds/cilium -- cilium-dbg status --verbose | Select-String -Pattern "kube|proxy|replacement"

9.3 ClusterIP 验证

kubectl -n cilium-lab get svc web -o wide
kubectl -n cilium-lab get endpoints web -o wide
kubectl -n cilium-lab get endpointslice -l kubernetes.io/service-name=web -o wide
kubectl -n cilium-lab exec client -- curl -sS --max-time 3 http://web

查看 Cilium service:

kubectl -n kube-system exec ds/cilium -- cilium-dbg service list

9.4 NodePort 验证

创建 NodePort:

kubectl -n cilium-lab patch svc web -p '{"spec":{"type":"NodePort"}}'
kubectl -n cilium-lab get svc web

拿到 Node IP 和 NodePort 后,从集群外或节点上访问:

curl -sS --max-time 3 http://<node-ip>:<node-port>

观察:

hubble observe --namespace cilium-lab --service web
kubectl -n kube-system exec ds/cilium -- cilium-dbg service list

清理:

kubectl -n cilium-lab patch svc web -p '{"spec":{"type":"ClusterIP"}}'

9.5 结论

这个实验支撑的理论:

  • Service 不通时不要只查 Pod。
  • 需要按 Service -> EndpointSlice -> Cilium service map -> Hubble flow -> node datapath 顺序定位。
  • kube-proxy replacement 开启后,节点内核、Cilium 配置和 Service 类型都会影响结果。

10. 实验九:Prometheus Metrics 与告警

10.1 理论目标

你要掌握:

  • Hubble 用于实时流量观察,Prometheus 用于长期趋势和告警。
  • Cilium agent、operator、Hubble 都可以暴露 metrics。
  • 生产中要监控 agent 健康、drop、policy verdict、endpoint 数量、IPAM、API 延迟、Hubble flow。

10.2 查看是否启用 metrics

cilium status
helm -n kube-system get values cilium -o yaml | grep -i metrics

PowerShell:

helm -n kube-system get values cilium -o yaml | Select-String -Pattern "metrics|prometheus|hubble"

10.3 Helm values 示例

不同版本 values 可能有差异,先以 helm show values cilium/cilium --version <version> 为准。常见启用方式:

helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --version <your-version> \
  -f cilium-values-current.yaml \
  --set prometheus.enabled=true \
  --set operator.prometheus.enabled=true \
  --set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,http}"

10.4 验证 metrics service

kubectl -n kube-system get svc | grep -E "cilium|hubble"
kubectl -n kube-system get pods -l k8s-app=cilium -o wide

PowerShell:

kubectl -n kube-system get svc | Select-String -Pattern "cilium|hubble"

如果你使用 Prometheus Operator,还需要确认是否创建 ServiceMonitor:

kubectl get servicemonitor --all-namespaces | grep -E "cilium|hubble"

10.5 建议告警项

生产建议至少覆盖:

  • Cilium agent Pod 非 Ready。
  • Cilium operator 非 Ready。
  • Cilium endpoint regeneration 失败。
  • Drop 流量突增。
  • Policy denied 突增。
  • Hubble Relay 不可用。
  • IPAM 可用地址不足。
  • Cilium API error 或 Kubernetes API client error 突增。
  • 节点上 Cilium DaemonSet desired 与 ready 不一致。

10.6 实验验证告警数据

复用实验五制造 drop:

hubble observe --namespace cilium-lab --verdict DROPPED --follow

然后查询 Prometheus 中 Hubble/Cilium drop 相关指标。指标名随版本和启用项可能变化,原则是用 Prometheus UI 搜索:

cilium
hubble
drop
verdict
policy

10.7 结论

这个实验支撑的理论:

  • Hubble 适合现场分析,Prometheus 适合趋势和告警。
  • 运维不能只在故障发生后手动 hubble observe,要提前把关键指标接入告警。

11. 实验十:Egress Gateway 固定出口 IP

风险等级:中到高。需要测试集群。
官方文档说明 Egress Gateway 需要启用 BPF masquerading 和 kube-proxy replacement;并且 gateway node 上的 egress IP 必须真实配置在网卡上。

11.1 理论目标

你要掌握:

  • Egress Gateway 可以让指定 Pod 访问指定外部 CIDR 时,从指定节点和指定源 IP 出口。
  • 它适合对接传统防火墙白名单。
  • 如果没有匹配 gateway node,或 egress IP 不存在,匹配流量可能被丢弃。
  • 新 Pod 创建后,策略生效有短暂延迟,刚启动瞬间的流量可能还没有按 gateway 出口。

11.2 检查前置条件

cilium status
helm -n kube-system get values cilium -o yaml | grep -E "egressGateway|bpf.masquerade|kubeProxyReplacement"

PowerShell:

helm -n kube-system get values cilium -o yaml | Select-String -Pattern "egressGateway|bpf.masquerade|kubeProxyReplacement"

预期:

  • egressGateway.enabled=true
  • bpf.masquerade=true
  • kubeProxyReplacement=true 或对应版本支持的开启值

11.3 标记 gateway node

选择一个节点作为出口:

kubectl get nodes -o wide
kubectl label node <gateway-node-name> egress-gw=true

确认该节点有可用于出口的 IP:

kubectl describe node <gateway-node-name> | grep -A5 Addresses

如果你指定 egressIP,该 IP 必须已经配置在该节点网卡上。

11.4 部署外部回显服务

你需要一个能显示来源 IP 的外部服务。可以使用:

  • 公司测试机上的 nginx,记录 $remote_addr。
  • 云主机上运行 tcpdump 或简单 HTTP 服务。
  • 测试环境可访问的 ifconfig.me、icanhazip.com 等公网服务。

示例:

kubectl -n cilium-lab exec client -- curl -sS --max-time 5 https://ifconfig.me

记录未启用 Egress Gateway policy 前的出口 IP。

11.5 创建 Egress Gateway Policy

以下示例把 app=client 访问 203.0.113.0/24 的流量经由带 egress-gw=true 标签的节点出口。请替换目的 CIDR 和 egress IP。

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
  name: client-egress-gateway
spec:
  selectors:
  - podSelector:
      matchLabels:
        app: client
    namespaceSelector:
      matchLabels:
        purpose: cilium-lab
  destinationCIDRs:
  - "203.0.113.0/24"
  egressGateway:
    nodeSelector:
      matchLabels:
        egress-gw: "true"
    egressIP: "192.0.2.10"
EOF

注意:

  • 203.0.113.0/24 和 192.0.2.10 是文档示例地址,不能直接用于真实环境。
  • 如果不指定 egressIP,Cilium 会使用默认路由接口上的地址,具体行为以版本文档为准。

11.6 验证

从 client 访问目标外部服务:

kubectl -n cilium-lab exec client -- curl -sS --max-time 5 http://<external-test-ip-or-domain>

在外部服务上确认来源 IP 是指定 egress IP。

Hubble 观察:

hubble observe --namespace cilium-lab --pod client --follow

如果不通,检查:

kubectl get ciliumegressgatewaypolicies
kubectl describe ciliumegressgatewaypolicy client-egress-gateway
kubectl get nodes --show-labels | grep egress-gw
kubectl -n kube-system exec ds/cilium -- cilium-dbg monitor --type drop

11.7 结论

这个实验支撑的理论:

  • Egress Gateway 是“哪些 Pod 到哪些外部 CIDR 从哪个节点哪个 IP 出去”。
  • 它不是简单的 NetworkPolicy,也不是 Service。
  • 出口 IP 必须和底层网络真实匹配,Cilium 不能凭空让上游网络认识一个不存在的源 IP。

12. 实验十一:裸金属入口流量选择

这部分取决于你的环境。你不是网工,但需要能和网络同事讲清楚你需要什么。

12.1 三种常见方案

方案 A:云厂商 LoadBalancer

适合:

  • EKS、GKE、AKS 或私有云 CCM。
  • 你创建 type: LoadBalancer,云平台分配 LB。

你要学:

  • Service annotations。
  • 安全组/防火墙。
  • 后端健康检查。

方案 B:LB IPAM + L2 Announcements

适合:

  • 小型裸金属。
  • 没有 BGP。
  • 同一个二层网络内通过 ARP/NDP 宣告 LoadBalancer IP。

风险:

  • L2 Announcements 在部分版本中仍有 beta 特性,生产前要验证 failover。
  • 不适合复杂三层网络。

方案 C:LB IPAM + BGP Control Plane

适合:

  • 裸金属机房。
  • 上游交换机/路由器支持 BGP。
  • 希望 LoadBalancer IP 或 PodCIDR 被网络设备学习。

你要和网工确认:

  • ASN。
  • peer IP。
  • 宣告哪些 CIDR。
  • 是否需要 BGP password。
  • 路由收敛时间。
  • 网络设备是否过滤前缀。

12.2 LB IPAM 实验

创建一个 LoadBalancer IP Pool。请使用你测试网络中真实可用、不会冲突的地址段。

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: lab-lb-pool
spec:
  blocks:
  - cidr: "192.168.5.200/28"
EOF

把 web 改成 LoadBalancer:

kubectl -n cilium-lab patch svc web -p '{"spec":{"type":"LoadBalancer"}}'
kubectl -n cilium-lab get svc web -w

预期:

  • Service 获得一个 EXTERNAL-IP。

  • 是否能从外部访问,取决于你是否配置了 L2 Announcements、BGP 或云 LB。

L2 宣告策略

#lab-l2-announcement.yaml

apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
  name: lab-lb-l2
spec:
  serviceSelector:
    matchLabels:
      app: web
  nodeSelector:
    matchLabels:
      kubernetes.io/os: linux
  interfaces:
  - "^ens18$"
  loadBalancerIPs: true

 这个策略表示:

  - 只为 app=web 的 Service 宣告 VIP
  - 只在 Linux 节点上宣告
  - 通过 ens18 网卡发送 ARP
  - 宣告 LoadBalancer IP
 给 Cilium Agent 增加 Lease 权限

  L2 leader election 需要访问 Kubernetes Lease。执行下面这个 JSON Patch:

  kubectl patch clusterrole cilium \
    --type=json \
    --patch '[
      {
        "op": "add",
        "path": "/rules/-",
        "value": {
          "apiGroups": ["coordination.k8s.io"],
          "resources": ["leases"],
          "verbs": ["create", "get", "update", "patch"]
        }
      }
    ]'

  可以检查权限:

  kubectl auth can-i get leases \
    --as=system:serviceaccount:kube-system:cilium \
    -n kube-system

  应该返回:

  yes

  ———

  ### 6. 重启 Cilium 使配置生效

  kubectl -n kube-system rollout restart daemonset/cilium

  kubectl -n kube-system rollout status daemonset/cilium \
    --timeout=180s

  ———

  ### 7. 完整验证

  kubectl -n cilium-lab get svc web

  kubectl get ciliuml2announcementpolicy

  kubectl -n kube-system get lease \
    cilium-l2announce-cilium-lab-web \
    -o jsonpath='{.spec.holderIdentity}{"\n"}'

  curl -i --connect-timeout 3 http://192.168.5.192/

  预期:

  HTTP/1.1 200 OK

清理:

kubectl -n cilium-lab patch svc web -p '{"spec":{"type":"ClusterIP"}}'
kubectl delete ciliuml2announcementpolicy lab-l2-policy --ignore-not-found
kubectl delete ciliumbgpclusterconfig lab-bgp --ignore-not-found
kubectl delete ciliumloadbalancerippool lab-lb-pool --ignore-not-found

12.3 L2 Announcements 理论验证

如果你要走 L2 Announcements,需要创建 CiliumL2AnnouncementPolicy。实际字段请按当前版本官方文档确认。

验证思路:

kubectl get ciliuml2announcementpolicies
kubectl -n cilium-lab get svc web -o wide
arp -a | grep <loadbalancer-ip>
curl -sS --max-time 3 http://<loadbalancer-ip>

重点观察:

  • 哪个节点响应 ARP。
  • 节点故障后,LoadBalancer IP 是否切换到其它节点。
  • 切换期间客户端是否短暂中断。

12.4 BGP Control Plane 理论验证

如果你要走 BGP,需要网络设备配合。你的目标不是精通 BGP,而是能交付一张变更表:

Kubernetes cluster name:
Cilium version:
Cilium node IPs:
Local ASN:
Peer ASN:
Peer IP:
Advertised LB CIDR:
Advertised PodCIDR:
BGP password:
Expected route next-hop:
Rollback method:

验证:

kubectl get ciliumbgpclusterconfig
kubectl get ciliumbgpadvertisements
kubectl get ciliumbgppeerconfigs
kubectl -n cilium-lab get svc web -o wide

在网络设备侧验证:

show bgp summary
show ip route <loadbalancer-ip>
show bgp <prefix>

12.5 结论

这个实验支撑的理论:

  • LB IPAM 只负责给 Service 分配 IP,不负责让外部网络一定能访问这个 IP。
  • L2 Announcements 通过二层邻居发现解决入口可达。
  • BGP 通过三层路由宣告解决入口可达。
  • 运维要能判断“IP 已分配但外部不通”到底是 Cilium、L2、BGP、ACL 还是防火墙问题。

13. 运维排障路径

13.1 Pod 到 Pod 不通

按顺序查:

kubectl get pods -n <ns> -o wide
kubectl get svc,endpoints,endpointslice -n <ns>
cilium status
hubble observe --namespace <ns> --follow
hubble observe --namespace <ns> --verdict DROPPED
kubectl get cnp,ccnp --all-namespaces
kubectl -n kube-system exec ds/cilium -- cilium-dbg endpoint list
kubectl -n kube-system exec ds/cilium -- cilium-dbg monitor --type drop

判断:

  • 没有 flow:请求可能没发出,或 Pod 不由 Cilium 管理。
  • DROPPED 且 policy denied:查 NetworkPolicy/CNP/CCNP。
  • Service 有问题:查 EndpointSlice、selector、Cilium service list。
  • 跨节点才不通:查 tunnel/native routing、节点防火墙、MTU、路由。

13.2 Pod 到外网不通

按顺序查:

kubectl -n <ns> exec <pod> -- nslookup <domain>
kubectl -n <ns> exec <pod> -- curl -v --max-time 5 https://<domain>
hubble observe --namespace <ns> --pod <pod> --follow
hubble observe --namespace <ns> --pod <pod> --verdict DROPPED
kubectl get cnp,ccnp --all-namespaces

判断:

  • DNS 不通:查 DNS egress policy、CoreDNS、kube-dns 标签。
  • DNS 通但 TCP 不通:查 egress 443/TCP、toFQDNs、NAT、Egress Gateway。
  • 只有特定域名不通:查 FQDN 解析、TTL、Cilium DNS proxy。
  • 外部只允许固定源 IP:查 Egress Gateway 或节点 SNAT。

13.3 Service 不通

按顺序查:

kubectl -n <ns> get svc <svc> -o yaml
kubectl -n <ns> get endpoints <svc> -o wide
kubectl -n <ns> get endpointslice -l kubernetes.io/service-name=<svc> -o yaml
kubectl -n kube-system exec ds/cilium -- cilium-dbg service list
hubble observe --namespace <ns> --service <svc> --follow

判断:

  • Service selector 错:EndpointSlice 为空。
  • Endpoint 有但不通:查策略、Pod readiness、Cilium service map。
  • NodePort/LoadBalancer 不通:查 kube-proxy replacement、LB IPAM、L2/BGP、节点防火墙。

13.4 策略生效不符合预期

按顺序查:

kubectl get networkpolicy --all-namespaces
kubectl get cnp --all-namespaces
kubectl get ccnp
kubectl describe cnp -n <ns> <name>
kubectl -n kube-system exec ds/cilium -- cilium-dbg endpoint list
hubble observe --namespace <ns> --verdict DROPPED --follow

重点:

  • 标签是否匹配。
  • namespace label 是否匹配。
  • 是否有 deny policy。
  • ingress 和 egress 是否只写了一边。
  • DNS 是否被遗漏。
  • CNP 与 Kubernetes NetworkPolicy 是否叠加。

14. 生产上线检查清单

14.1 安装模式

  • 明确使用 VXLAN、Geneve、Native Routing 或云厂商 ENI/IPAM。
  • 记录关键 Helm values。
  • 记录 PodCIDR、ServiceCIDR、节点网段。
  • 明确 MTU。
  • 明确是否启用 kube-proxy replacement。

14.2 策略

  • 是否存在默认拒绝策略。
  • 是否有 DNS 放行模板。
  • 是否区分 namespace 边界。
  • 是否允许必要的 kube-system 流量。
  • 是否有 deny policy。
  • 是否有策略变更审批和回滚方式。

14.3 观测

  • Cilium status 可采集。
  • Hubble Relay 正常。
  • Prometheus metrics 已启用。
  • Grafana dashboard 已导入。
  • drop/policy denied 有告警。
  • Cilium agent/operator Ready 有告警。

14.4 变更

  • 变更前保存 Helm values。
  • 变更前跑 connectivity test。
  • 变更后跑 connectivity test。
  • 有 rollback 命令和 values。
  • 知道哪些变更会滚动重启 Cilium agent。

14.5 外部访问

  • LoadBalancer IP 从哪里分配。
  • 外部网络如何到达这个 IP。
  • L2/BGP/云 LB 哪个组件负责可达性。
  • 节点防火墙是否允许。
  • 上游 ACL 是否允许。

14.6 出口访问

  • 普通 SNAT 还是 Egress Gateway。
  • 固定出口 IP 是否真实配置在节点上。
  • 外部防火墙是否放行该 IP。
  • 出口策略是否覆盖 DNS 和目标端口。

15. 建议学习路线

第一周:

  • 重做实验一到实验六。
  • 目标:能解释 default-deny、allow、deny、DNS/FQDN、L7、Hubble drop。

第二周:

  • 做升级演练和 connectivity test。
  • 目标:能写出 Cilium 升级 SOP。

第三周:

  • 做 kube-proxy replacement 验证和 Service 排障。
  • 目标:能处理 ClusterIP、NodePort、LoadBalancer 不通。

第四周:

  • 根据公司环境选择 Egress Gateway、L2 Announcements 或 BGP。
  • 目标:能处理固定出口和入口 IP 可达性。

16. 最终能力标准

你学完后应该能做到:

  • 看一条 Hubble flow,判断来源、目标、协议、端口、结果。
  • 写一个 namespace 级别的默认拒绝策略,并放行必要 DNS 和业务访问。
  • 解释为什么 toFQDNs 需要 DNS 策略配合。
  • 判断 deny policy 为什么覆盖 allow policy。
  • 在升级 Cilium 前保存 values、跑 preflight、跑 connectivity test。
  • 判断 Service 不通是 selector、EndpointSlice、策略、Cilium service map 还是外部网络问题。
  • 知道什么时候该找网工:BGP peer 不起来、上游路由没收到、ACL 拦截、二层 ARP/NDP 异常。
  • 知道什么时候不用找网工:标签写错、策略 default-deny、DNS 没放行、Service selector 错、Cilium agent 异常。

17. 清理实验环境

确认不再需要实验资源后:

kubectl delete namespace cilium-lab
kubectl delete ciliumegressgatewaypolicy client-egress-gateway --ignore-not-found
kubectl delete ciliumloadbalancerippool lab-lb-pool --ignore-not-found
kubectl delete ciliuml2announcementpolicy lab-l2-policy --ignore-not-found
kubectl delete ciliumbgpclusterconfig lab-bgp --ignore-not-found

如果给节点打过标签:

kubectl label node <gateway-node-name> egress-gw-

18. 附录:最小命令速查

cilium version
cilium status
cilium connectivity test
cilium hubble port-forward
hubble status
hubble observe --follow
hubble observe --namespace <ns> --verdict DROPPED
kubectl -n kube-system exec ds/cilium -- cilium-dbg status --verbose
kubectl -n kube-system exec ds/cilium -- cilium-dbg endpoint list
kubectl -n kube-system exec ds/cilium -- cilium-dbg service list
kubectl -n kube-system exec ds/cilium -- cilium-dbg monitor --type drop
helm -n kube-system get values cilium -o yaml
helm -n kube-system history cilium