HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 代理技术全栈手册

    • 代理技术全栈手册 - HiHuo
    • 原理篇

      • 第01章 代理是什么:正向 / 反向 / 透明 / 隧道的统一模型
      • 第02章 代理与网络层级:L3 / L4 / L5 / L7 在哪里截断流量
      • 第03章 一个请求穿过代理的一生:连接生命周期全景
    • 协议篇

      • 第04章 HTTP 代理协议:绝对 URI、CONNECT 隧道、转发头与连接池
      • 第05章 HTTPS 与 TLS 代理:终止 / 透传 / MITM / SNI / mTLS
      • 第06章 SOCKS 协议:SOCKS4/4a/5 与 UDP ASSOCIATE 报文级解析
      • 第07章 HTTP/2、gRPC 与 HTTP/3(QUIC) 代理的挑战
      • 第08章 代理自动配置:PAC / WPAD / 系统代理 / NO_PROXY
    • 层级与转发篇

      • 第09章 L4 代理:TCP/UDP 转发与连接级负载均衡
      • 第10章 L7 代理:协议感知与基于内容的路由
      • 第11章 透明代理:iptables REDIRECT/DNAT、TPROXY 与 eBPF 劫持
      • 第12章 数据搬运的艺术:splice / sendfile / 零拷贝 / io_uring
    • 组件横评篇

      • 第13章 Nginx / OpenResty:反向代理、upstream 与 Lua 可编程
      • 第14章 HAProxy:L4/L7、ACL、健康检查与 stick table
      • 第15章 Envoy:xDS 动态配置与 filter chain,为何是云原生数据面
      • 第16章 Traefik / Caddy:自动服务发现与自动 HTTPS
      • 第17章 Squid 与正向/缓存代理:企业出网、缓存与审计
      • 第18章 mitmproxy:抓包、改包、脚本化调试
      • 第19章 内网穿透与隧道:frp / gost / SSH 隧道 / ngrok
      • 第20章 科学上网生态的技术原理(技术中立)
    • 多语言手写篇

      • 第21章 Go:100 行手写 HTTP/CONNECT + SOCKS5 代理
      • 第22章 Rust:基于 tokio 的高性能 TCP 代理
      • 第23章 Python:asyncio 实现,适合调试与脚本
      • 第24章 C:epoll 裸写与零拷贝,及语言选型对比
    • 容器与K8s篇

      • 第25章 Docker 里的代理:HTTP_PROXY、build/pull 与 daemon 配置
      • 第26章 Sidecar 与流量劫持:Istio init-container 的 iptables 原理
      • 第27章 Ingress 与南北流量:Ingress-nginx 与 Gateway API
      • 第28章 Egress 与出网治理:出口网关、registry mirror、审计
      • 第29章 Service Mesh 数据面:Envoy Sidecar 全链路
    • 进阶篇

      • 第30章 可编程代理:Lua / Wasm / eBPF / xDS,代理的"软件定义"
      • 第31章 性能调优:并发模型、连接池、超时与重试、压测
      • 第32章 排错决策树:502 / 504 / 握手失败 / 环路 / 泄漏
      • 第33章 代理安全:开放代理、SSRF、凭证泄漏与攻击面
    • 底层机制篇

      • 第34章 代理的背压与流控:一个代理最难的部分
      • 第35章 socket 与 TCP 状态机:半关闭、超时、连接生命周期
      • 第36章 HTTP/2 帧、流控与 HPACK:h2 代理的内部机制
      • 第37章 负载均衡算法推导与韧性状态机
      • 第38章 Capstone:把玩具代理改造成生产级骨架
    • 综合实战篇

      • 第39章 企业多跳转发链:拓扑、协议矩阵与贯穿性难题
      • 第40章 端到端实战:把 6 类流量全代理通
      • 第41章 更刁钻的流量:gRPC、长轮询、WebRTC、大文件、双向流
      • 第42章 可落地完整参考实现:一套能跑的多协议转发栈
    • 附录

      • 附录 A:代理协议报文速查(HTTP / SOCKS / PAC / PROXY protocol)
      • 附录 B:组件选型决策树
      • 附录 C:抓包与命令速查

第28章 Egress 与出网治理:出口网关、registry mirror、审计

学习目标

  • 理解为什么要治理 K8s 出网:安全、合规、稳定(固定出口 IP)、成本
  • 掌握五种出网治理手段:NetworkPolicy、出口网关、正向代理、FQDN 策略、镜像缓存
  • 理解"按域名管控出网"为什么难,及 Cilium FQDN/Istio ServiceEntry 的解法
  • 会为第三方白名单需求实现"固定出口 IP"

前置知识

  • 第17章 Squid 正向代理、第01章 正向代理、第25章 Docker registry mirror
  • 网络手册 · NetworkPolicy、k8sLab · NetworkPolicy 与零信任

原理

为什么治理出网(Egress)

第27章 管"进",本章管"出"。默认情况下 K8s 的 Pod 可以访问任意外部地址——这在生产是危险的:

  • 安全:被入侵的 Pod 可向外传数据(数据外泄)、连 C2(命令控制)
  • 合规:需要审计"哪个服务访问了哪些外部地址"
  • 稳定:第三方 API 要求白名单固定 IP,但 Pod 出网 IP 是节点 IP、不固定
  • 成本:重复拉取外部资源(镜像/依赖)浪费带宽——用缓存

手段一:NetworkPolicy egress(L3/L4,按 IP)

K8s 原生的 NetworkPolicy 能限制 Pod 的出站,但只在 L3/L4(IP/CIDR/端口):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: restrict-egress }
spec:
  podSelector: { matchLabels: { app: myapp } }
  policyTypes: [Egress]
  egress:
  - to: [{ ipBlock: { cidr: 203.0.113.0/24 } }]    # 只允许访问这个外部网段
    ports: [{ protocol: TCP, port: 443 }]
  - to: [{ namespaceSelector: {} }]                 # 允许集群内
    ports: [{ protocol: UDP, port: 53 }]            # DNS

致命局限:NetworkPolicy 不能按域名。因为它工作在 IP 层,而域名对应的 IP 经常变(CDN、云服务)。"只允许访问 api.github.com"这种需求,原生 NetworkPolicy 做不到——这引出了下面的方案。

手段二:按域名管控(FQDN 策略 / ServiceEntry)

要按域名管控出网,需要 DNS 感知的方案:

  • Cilium FQDN Policy:Cilium 用 eBPF 拦截 DNS 响应,学习"域名→IP"映射,从而支持 toFQDNs: api.github.com(网络手册 · Cilium/eBPF)
# CiliumNetworkPolicy:按域名放行(原生 NetworkPolicy 做不到)
egress:
- toFQDNs: [{ matchName: "api.github.com" }]
- toEndpoints: [{}]                              # 配合放行 DNS
  toPorts: [{ ports: [{ port: "53", protocol: UDP }] }]
  • Istio ServiceEntry:把外部服务"注册"进 mesh,从而能对它做路由、监控、策略——出网也纳入 sidecar 治理

手段三:正向代理出网(呼应 Squid)

让所有 Pod 配 HTTP_PROXY 指向集群内的正向代理(Squid 等,第17章),统一出网口:

  Pod(HTTP_PROXY=squid.egress.svc:3128)
       │
       ▼ 所有出网走 Squid
  [集群内 Squid 正向代理] ──审计/缓存/ACL──▶ 外部

好处:统一审计(access.log)、域名级 ACL、缓存、认证——把企业出网那套(第17章)搬进集群。注意 NO_PROXY 必须含集群内域名(.svc、.cluster.local、Pod/Service CIDR、169.254.169.254),否则内部调用也走代理 → 全超时(第08章、第25章)。

手段四:出口网关 + 固定出口 IP

第三方 API 要白名单时,需要所有 Pod 出网都从一个固定 IP 出去。做法是 Egress Gateway:把出网流量都汇聚到一组专用网关节点/Pod,在那里做 SNAT 成固定 IP。

  各业务 Pod(出网 IP 随机=节点 IP)
       │  路由/mesh 强制走出口网关
       ▼
  [Egress Gateway 节点] ──SNAT 成固定 IP 203.0.113.10──▶ 第三方(白名单认这个 IP)
  • Istio Egress Gateway:mesh 内强制出网流量经过专用 gateway,统一出口、统一策略、可观测
  • Cilium Egress Gateway:用 eBPF 把选定 Pod 的出网 SNAT 到固定 IP

手段五:镜像与依赖缓存(registry mirror)

重复拉镜像/依赖浪费带宽,用 pull-through cache / registry mirror(第25章)——本质是给 registry 做反向代理+缓存(第17章 缓存思想)。常配合私有 Harbor 的 proxy cache。

一张表:选哪种

需求手段
按 IP/端口限制出网NetworkPolicy egress
按域名白名单Cilium FQDN / Istio ServiceEntry
统一审计 + 缓存 + 认证集群内正向代理(Squid)
固定出口 IP(第三方白名单)Egress Gateway + SNAT
镜像/依赖加速registry mirror / pull-through cache

️ 实现 / 命令

实验一:NetworkPolicy 默认拒绝出网 + 白名单

# 1) 默认拒绝所有出站(零信任起点)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny-egress }
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress: []          # 空 = 全拒
kubectl apply -f default-deny-egress.yaml
kubectl exec mypod -- curl -m 3 https://example.com   # 超时(被拒)
# 再叠加上面的 restrict-egress 放行特定网段 + DNS

实验二:Pod 走集群内 Squid 出网

# 给 Pod 注入代理环境变量(NO_PROXY 必须含集群内!)
env:
- { name: HTTP_PROXY,  value: "http://squid.egress.svc.cluster.local:3128" }
- { name: HTTPS_PROXY, value: "http://squid.egress.svc.cluster.local:3128" }
- { name: NO_PROXY,    value: "localhost,127.0.0.1,.svc,.cluster.local,10.0.0.0/8,169.254.169.254" }
# 在 Squid 上审计每个 Pod 的出网
kubectl logs -n egress squid-0 | tail
# ... 10.244.1.5 TCP_MISS/200 GET http://example.com/  ← 哪个 Pod 访问了哪里,一目了然

实验三:Cilium 按域名放行

kubectl apply -f - <<'EOF'
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata: { name: allow-github }
spec:
  endpointSelector: { matchLabels: { app: ci } }
  egress:
  - toFQDNs: [{ matchName: "api.github.com" }]
  - toEndpoints: [{ matchLabels: { "k8s:io.kubernetes.pod.namespace": kube-system, "k8s-app": kube-dns } }]
    toPorts: [{ ports: [{ port: "53", protocol: UDP }] }]
EOF
# 此后该 Pod 只能访问 api.github.com(按域名),其余被拒

排错

现象根因解决
加了 egress 策略后 DNS 全挂没放行 53 端口到 kube-dnsegress 放行 UDP/TCP 53
按域名策略不生效用了原生 NetworkPolicy(不支持域名)换 Cilium FQDN / Istio
Pod 配代理后内部调用超时NO_PROXY 没含集群内补 .svc/CIDR/元数据(第25章)
第三方仍看到多变 IP没走出口网关配 Egress Gateway + SNAT 固定 IP
FQDN 策略偶尔漏放行DNS TTL/IP 变化窗口调 DNS 策略、缩短缓存
元数据 169.254.169.254 被滥用出网没限制元数据阻断或限制其访问(第33章 SSRF)

本章小结

  • 治理出网是企业 K8s 的安全刚需:安全、合规、固定出口 IP、成本。
  • 五手段:NetworkPolicy(按 IP/L4)、FQDN/ServiceEntry(按域名)、正向代理(审计+缓存)、Egress Gateway(固定出口 IP)、registry mirror(缓存)。
  • 原生 NetworkPolicy 不能按域名(IP 会变),按域名要 Cilium FQDN / Istio。
  • Pod 走集群内 Squid 时 NO_PROXY 必须含集群内域名/网段,否则内部调用全超时。

下一章 第29章 Service Mesh 数据面,把本篇所有要素(sidecar 劫持 + Envoy + mTLS + xDS + L7)串成完整的东西流量治理全链路——容器与 K8s 篇的收官。

Prev
第27章 Ingress 与南北流量:Ingress-nginx 与 Gateway API
Next
第29章 Service Mesh 数据面:Envoy Sidecar 全链路