本文帮助你开始使用 Cilium 启用的 Kubernetes 集群来运行 Istio。本文档涵盖了 Cilium 与 Istio 集成的以下几个常见方面:

  • Cilium 配置
  • Istio 配置
  • 演示应用程序

Cilium 配置

Cilium 配置的主要目标是确保重定向到 Istio 的 Sidecar 代理(sidecar mode)节点代理(ambient mode) 的流量不受干扰。当启用 Cilium 的 kubeProxyReplacement 功能(参见 无 kube-proxy 的 Kubernetes 文档)时,可能会发生干扰,该功能在 Pod 内启用基于套接字的负载均衡。

为了确保 Cilium 不干扰 Istio,重要的是在 Cilium 的 ConfigMap 中将 bpf-lb-sock-hostns-only 参数设置为 true。可以通过使用 --set socketLB.hostNamespaceOnly=true 的 Helm 值来实现。你可以用以下命令确认结果:

$ kubectl get configmaps -n kube-system cilium-config -oyaml | grep bpf-lb-sock-hostns
bpf-lb-sock-hostns-only: "true"

Istio 使用 CNI 插件来实现 Sidecar 和 Ambient 模式的功能。为确保 Cilium 不干扰节点上的其他 CNI 插件,重要的是在 Cilium 的 ConfigMap 中设置 cni-exclusive 参数为 false。这可以通过使用 --set cni.exclusive=false 的 Helm 值来实现。你可以用以下命令确认结果:

$ kubectl get configmaps -n kube-system cilium-config -oyaml | grep cni-exclusive
cni-exclusive: "false"

Istio 配置

部署 Cilium 和 Istio 时,请注意:

  • 可以使用 Cilium 或 Istio 的 L7 HTTP 策略控制,但不建议同时使用 两者 的 L7 HTTP 策略控制,以避免分裂脑问题。

    若要在 Istio(Sidecar 或 Ambient 模式)中使用 Cilium 的 L7 HTTP 策略控制(例如,第 7 层示例),你必须:

    • Sidecar 模式:通过在 Istio 的 PeerAuthentication 下配置 mtls.mode=DISABLE,禁用 Cilium L7 策略管理的工作负载的 Istio mTLS。
    • Ambient:通过从命名空间移除 istio.io/dataplane-mode 标签,或为 Cilium L7 策略管理的 Pod 添加 ambient.istio.io/redirection: disabled 注解,将工作负载从 Istio 环境中移除。

    否则,Istio 管理的工作负载之间的流量将由 Istio 使用 mTLS 加密,并且 Cilium 无法访问这些流量以执行 L7 策略。

    如果使用 Istio 的 L7 HTTP 策略控制,策略将在 Istio 中管理,不需要禁用工作负载之间的 mTLS。

  • 如果在 Ambient 模式下使用 Istio mTLS 与 Istio L7 HTTP 策略控制,Istio 管理的工作负载之间的流量将通过 端口 15008 加密并隧道传输进出 Pod。在这种情况下,Cilium 的 NetworkPolicy 仍将适用于进出 Istio 管理的 Pod 的加密隧道 L4 流量,但 Cilium 无法看到该隧道和加密的 L4 流量的实际来源和目的地,或任何 L7 信息。这意味着应使用 Istio 在 L4 或以上级别为 Istio 管理、mTLS 加固的工作负载之间的流量执行策略。流入 Istio 管理工作负载的非 Istio 管理工作负载的流量不会被隧道或加密处理。因此,这部分流量仍然完全受到 Cilium 强制实施的 Kubernetes 网络策略的约束。

  • 当在 Sidecar 模式下使用 Istio 与 自动 Sidecar 注入 结合 Cilium 的 overlay 模式(VXLAN 或 GENEVE)时,istiod Pod 必须运行在 hostNetwork: true 下,以便 API 服务器能够访问。

演示应用程序(使用 Cilium 与 Istio Ambient 模式)

下面的指南展示了在使用 Cilium L7 HTTP 策略控制而不是 Istio L7 HTTP 策略控制的情况下,Istio 的 Ambient mTLS 模式与 Cilium 网络策略的交互,包括在 Istio 配置 部分描述的注意事项。

先决条件

  • Istio 已在本地 Kubernetes 集群上安装。
  • Cilium 已安装,并配置了 socketLB.hostNamespaceOnlycni.exclusive=false 的 Helm 值。
  • Istio 的 istioctl 已在本地主机上安装。

首先,在三个不同的命名空间中部署一组 web 服务器和客户端应用程序:

kubectl create ns red
kubectl label namespace red istio.io/dataplane-mode=ambient
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/httpbin.yaml)
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml)
kubectl create ns blue
kubectl label namespace blue istio.io/dataplane-mode=ambient
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/httpbin.yaml)
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml)
kubectl create ns green
kubectl -n green apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml

默认情况下,Istio 以 PERMISSIVE 模式工作,允许 Istio 管理和未管理的 Pod 之间相互发送和接收未加密的流量。你可以通过输入以下命令来测试前面示例中部署的客户端和服务器应用程序之间的连通性:

kubectl exec -n red deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'red' to server 'red': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'red': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'green' to server 'red': %{http_code}\n"
kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'blue': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'green' to server 'blue': %{http_code}\n"

所有命令应成功完成:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 200

你可以应用 Cilium 强制的 L4 NetworkPolicy 来限制命名空间之间的通信。下面的命令应用了一个 L4 网络策略,该策略限制了 blue 命名空间中的通信,只允许来自 bluered 命名空间的客户端。

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/l4-policy.yaml

重新运行相同的连通性检查,以确认预期结果:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 000
command terminated with exit code 28

然后你可以决定增强相同的网络策略,以执行额外的基于 HTTP 的检查。以下命令应用了一个允许仅与 /ip URL 路径通信的 Cilium L7 网络策略:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/l7-policy.yaml

此时,由于 Cilium 代理(HTTP)干扰了 Istio 的基于 mTLS 的 HTTPS 连接,blue 命名空间的所有通信都中断了:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 000
command terminated with exit code 28
client 'blue' to server 'blue': 000
command terminated with exit code 28
client 'green' to server 'blue': 000
command terminated with exit code 28

为了解决问题并允许 Cilium 管理 L7 策略,你必须通过配置新策略来禁用 Istio 的 mTLS 身份验证:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: DISABLE

你必须将此策略应用于实施基于 HTTP 的网络策略的同一命名空间:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/authn.yaml

重新运行连通性检查,确认 blue 命名空间的通信已恢复。你可以通过访问不同的 URL 路径来验证 Cilium 是否正在执行 L7 网络策略,例如 /deny

$ kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/deny -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
client 'red' to server 'blue': 403

示例应用程序(使用 Cilium 的 Istio Sidecar 模式)

以下指南展示了 Istio 的 Sidecar 模式下的 mTLS 与 Cilium 网络策略的交互情况,以及使用 Cilium L7 HTTP 策略控制而非 Istio L7 HTTP 策略控制时的注意事项,具体描述在 Istio 配置 部分关于禁用 mTLS 的说明。

先决条件

  • Istio 已经在本地 Kubernetes 集群上安装。
  • Cilium 已经使用 socketLB.hostNamespaceOnlycni.exclusive=false 的 Helm 值安装。
  • Istio 的 istioctl 已经在本地主机上安装。

从部署一组 Web 服务器和客户端应用程序开始,跨三个不同的命名空间:

kubectl create ns red
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/httpbin.yaml | istioctl kube-inject -f -)
kubectl -n red apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml | istioctl kube-inject -f -)
kubectl create ns blue
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/httpbin.yaml | istioctl kube-inject -f -)
kubectl -n blue apply -f <(curl -s https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml | istioctl kube-inject -f -)
kubectl create ns green
kubectl -n green apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/netshoot.yaml

默认情况下,Istio 以 PERMISSIVE 模式工作,允许 Istio 管理的和没有 sidecar 的 Pod 之间互相发送和接收未加密的流量。你可以通过输入以下命令测试上述示例中部署的客户端和服务器应用程序之间的连通性:

kubectl exec -n red deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'red' to server 'red': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'red': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.red/ip -s -o /dev/null -m 1 -w "client 'green' to server 'red': %{http_code}\n"
kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
kubectl exec -n blue deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'blue' to server 'blue': %{http_code}\n"
kubectl exec -n green deploy/netshoot -- curl http://httpbin.blue/ip -s -o /dev/null -m 1 -w "client 'green' to server 'blue': %{http_code}\n"

所有命令应成功完成:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 200

你可以实施网络策略,以限制命名空间之间的通信。以下命令应用了一个由 Cilium 管理的 L4 网络策略,该策略限制 blue 命名空间内的通信,仅允许来自 bluered 命名空间的客户端。

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/l4-policy.yaml

重新运行相同的连通性检查,以确认预期结果:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 200
client 'blue' to server 'blue': 200
client 'green' to server 'blue': 000
command terminated with exit code 28

然后,你可以决定增强相同的网络策略,以执行其他由 Cilium 管理的基于 HTTP 的检查。以下命令应用了 Cilium L7 网络策略,只允许与 /ip URL 路径的通信:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/l7-policy.yaml

此时,blue 命名空间的所有通信都中断了,因为 Cilium 代理(HTTP)干扰了 Istio 的基于 mTLS 的 HTTPS 连接:

client 'red' to server 'red': 200
client 'blue' to server 'red': 200
client 'green' to server 'red': 200
client 'red' to server 'blue': 503
client 'blue' to server 'blue': 503
client 'green' to server 'blue': 000
command terminated with exit code 28

为解决问题并允许 Cilium 管理 L7 策略,你必须通过配置新策略来禁用 Istio 的 mTLS 身份验证:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: DISABLE

你必须将此策略应用到实施基于 HTTP 的网络策略的同一命名空间:

kubectl -n blue apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.1/examples/kubernetes-istio/authn.yaml

重新运行连通性检查,确认与 blue 命名空间的通信已恢复。你可以验证 Cilium 正在执行 L7 网络策略,例如通过访问不同的 URL 路径 /deny

$ kubectl exec -n red deploy/netshoot -- curl http://httpbin.blue/deny -s -o /dev/null -m 1 -w "client 'red' to server 'blue': %{http_code}\n"
client 'red' to server 'blue': 403

Cilium 和 Istio 的 L7 流量管理功能可以同时使用吗?

不推荐同时使用 Istio 和 Cilium 的 L7 流量管理功能。因为同时使用这两个系统的 L7 流量管理功能可能会导致“脑裂”问题,即两个系统可能会对同一流量进行不同的处理,导致不一致的行为。

具体来说:

  1. Istio 的 L7 流量管理:Istio 提供了强大的 L7 流量管理功能,通过其 Sidecar 代理或 Ambient 模式对流量进行控制、路由和监控。

  2. Cilium 的 L7 流量管理:Cilium 也提供了 L7 流量管理功能,主要通过 eBPF 实现,能够对网络层和应用层的流量进行深度包检测和策略控制。

为什么不推荐同时使用

  • 如果你同时启用了 Istio 和 Cilium 的 L7 流量管理,可能会出现冲突。比如,Istio 的 mTLS 加密会使得 Cilium 无法解析和管理加密后的 L7 流量,这样会导致 Cilium 的 L7 策略无法生效。
  • 两者的策略可能会相互覆盖或冲突,导致不可预见的行为和网络问题。

推荐的做法

  • 选择使用其中一个工具的 L7 流量管理功能,而让另一个工具在 L3/L4 层或其他方面提供支持。
  • 如果选择使用 Cilium 的 L7 流量管理功能,需要禁用 Istio 的 mTLS 或将相关工作负载从 Istio 的控制中移除。

因此,为避免复杂性和潜在的问题,通常建议在同一套系统中只使用一个工具的 L7 流量管理功能。