最近业界使用范围最广的K8S CNI网络方案Calico宣布支持eBPF,而作为第一个通过eBPF实现了kube-proxy所有功能的K8S网络方案——Cilium,它的先见之名是否能转成优势,继而成为CNI新的头牌呢?今天我们一起来入门最Cool Kubernetes网络方案Cilium。

Cilium介绍

以下基于Cilium官网文档翻译整理。

当前趋势

现代数据中心的应用系统已经逐渐转向基于微服务架构的开发体系,一个微服务架构的应用系统是由多个小的独立的服务组成,它们之间通过轻量通信协议如HTTP、gRPC、Kafka等进行通信。微服务架构下的服务天然具有动态变化的特点,结合容器化部署,时常会引起大规模的容器实例启动或重启。要确保这种向高度动态化的微服务应用之间的安全可达,既是挑战,也是机遇。

现有问题

传统的Linux网络访问安全控制机制(如iptables)是基于静态环境的IP地址和端口配置网络转发、过滤等规则,但是IP地址在微服务架构下是不断变化的,非固定的;出于安全目的,协议端口(例如HTTP传输的TCP端口80)也不再固定用来区分应用系统。为了匹配大规模容器实例快速变化的生命周期,传统网络技术需要维护成千上万的负载均衡规则和访问控制规则,并且需要以不断增长的频率更新这些规则,而如果没有准确的可视化功能,要维护这些规则也是十分困难,这些对传统网络技术的可用性和性能都是极大的挑战。比如经常会有人对kube-proxy基于iptables的服务负载均衡功能在大规模容器场景下具有严重的性能瓶颈,同时由于容器的创建和销毁非常频繁,基于IP做身份关联的故障排除和安全审计等也很难实现。

解决方案

Cilium作为一款Kubernetes CNI插件,从一开始就是为大规模和高度动态的容器环境而设计,并且带来了API级别感知的网络安全管理功能,通过使用基于Linux内核特性的新技术——BPF,提供了基于service/pod/container作为标识,而非传统的IP地址,来定义和加强容器和Pod之间网络层、应用层的安全策略。因此,Cilium不仅将安全控制与寻址解耦来简化在高度动态环境中应用安全性策略,而且提供传统网络第3层、4层隔离功能,以及基于http层上隔离控制,来提供更强的安全性隔离。

另外,由于BPF可以动态地插入控制Linux系统的程序,实现了强大的安全可视化功能,而且这些变化是不需要更新应用代码或重启应用服务本身就可以生效,因为BPF是运行在系统内核中的。

以上这些特性,使Cilium能够在大规模容器环境中也具有高度可伸缩性、可视化以及安全性。

部署Cilium

部署Cilium非常简单,可以通过单独的yaml文件部署全部组件(目前我使用了这个方式部署了1.7.1版本),也可以通过helm chart一键完成。重要的是部署环境和时机:

  1. 官方建议所有部署节点都使用Linux最新稳定内核版本,这样所有的功能都能启用,具体部署环境建议可以参照这里
  2. 作为一个Kubernetes网络组件,它应该在部署Kubernetes其他基础组件之后,才进行部署。这里,我自己遇到的问题是,因为还没有CNI插件,coredns组件的状态一直是pending的,直到部署完Cilium后,coredns完成了重置变成running状态。

下图是Cilium的整体部署组件图:

测试安装效果

官方提供了一个connectivity检查工具,以检测部署好的Cilium是否工作正常。如果你的网络环境有些限制,我作了一些简单修改,可以参照这里。部署起来很简单,请确保至少有两个可用的节点,否则有几个deployment会无法成功运行:

> kubectl apply -f connectivity-check.yaml

NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
echo-a                                  1/1     1            1           16d
echo-b                                  1/1     1            1           16d
host-to-b-multi-node-clusterip          1/1     1            1           16d
host-to-b-multi-node-headless           1/1     1            1           16d
pod-to-a                                1/1     1            1           16d
pod-to-a-allowed-cnp                    1/1     1            1           16d
pod-to-a-external-1111                  1/1     1            1           16d
pod-to-a-l3-denied-cnp                  1/1     1            1           16d
pod-to-b-intra-node                     1/1     1            1           16d
pod-to-b-multi-node-clusterip           1/1     1            1           16d
pod-to-b-multi-node-headless            1/1     1            1           16d
pod-to-external-fqdn-allow-google-cnp   1/1     1            1           16d

如果所有的deployment都能成功运行起来,说明Cilium已经成功部署并工作正常。

网络可视化神器Hubble

上文提到了Cilium强大之处就是提供了简单高效的网络可视化功能,它是通过Hubble组件完成的。Cilium在1.7版本后推出并开源了Hubble,它是专门为网络可视化设计,能够利用Cilium提供的eBPF数据路径,获得对Kubernetes应用和服务的网络流量的深度可见性。这些网络流量信息可以对接Hubble CLI、UI工具,可以通过交互式的方式快速诊断如与DNS相关的问题。除了Hubble自身的监控工具,还可以对接主流的云原生监控体系——Prometheus和Grafana,实现可扩展的监控策略。

部署Hubble 和 Hubble UI

官方提供了基于Helm Chart部署方式,这样可以灵活控制部署变量,实现不同监控策略。出于想要试用hubble UI和对接Grafana,我是这样的部署的:

> helm template hubble \
    --namespace kube-system \
    --set metrics.enabled="{dns:query;ignoreAAAA;destinationContext=pod-short,drop:sourceContext=pod;destinationContext=pod,tcp,flow,port-distribution,icmp,http}" \
    --set ui.enabled=true \
    > hubble.yaml
> kubectl apply -f hubble.yaml
# 包含两个组件
# - daemonset hubble
# - deployment hubble UI
> kubectl get pod -n kube-system |grep hubble
hubble-67ldp                       1/1     Running   0          21h
hubble-f287p                       1/1     Running   0          21h
hubble-fxzms                       1/1     Running   0          21h
hubble-tlq64                       1/1     Running   1          21h
hubble-ui-5f9fc85849-hkzkr         1/1     Running   0          15h
hubble-vpxcb                       1/1     Running   0          21h 

运行效果

由于默认的Hubble UI只提供了ClusterIP类似的service,无法通过外部访问。因此需要创建一个NodePort类型的service,如下所示:

# hubble-ui-nodeport-svc.yaml
kind: Service
apiVersion: v1
metadata:
  namespace: kube-system
  name: hubble-ui-np
spec:
  selector:
    k8s-app: hubble-ui
  ports:
    - name: http
      port: 12000
      nodePort: 32321
  type: NodePort

执行kubectl apply -f hubble-ui-nodeport-svc.yaml,就可以通过任意集群节点IP地址加上32321端口访问Hubble UI的web服务了。打开效果如下所示:

  • 页面上半部分是之前部署的一整套conectivity-check组件的数据流向图,官方叫做Service Map,默认情况下可以自动发现基于网络3层和4层的访问依赖路径,看上去非常cool,也有点分布式链路追踪图的感觉。点击某个服务,还能看到更为详细的关系图:
  • 下图是kube-system命名空间下的数据流图,能看到Hubble-UI组件和Hubble组件是通过gRPC进行通信的,非常有趣。但令人感到的好奇的是,为何没有显示Kubernetes核心组件之间的调用关系图:

页面的下半部分默认显示的是对于每条数据流路径的详细描述,包括发起请求的pod名称、发起请求的service名称、请求目标的pod名称、请求目标的service名称、目标IP、目标端口、目标7层信息、请求状态、最后一次查看时间等,如下图所示:

点击任意一条flow,可以查看到更多详细信息:

页面的下半部分可以通过点击切换成显示network policy模式,列出了当前命名空间下所有的网络策略:

如果想开启网络7层的可视化观察,就需要对目标pod进行annotations ,感兴趣可以看这里,就不在入门篇详述了。

这样的网络可视化是不是你梦寐以求的,绝对能在排查请求调用问题的时候帮上大忙。

对接Grafana+ Prometheus

如果你跟一样是Grafana+ Prometheus的忠实粉丝,那么使Hubble对接它们就是必然操作了。仔细的同学已经发现之前helm template的玄机了:

--set metrics.enabled="{dns:query;ignoreAAAA;destinationContext=pod-short,drop:sourceContext=pod;destinationContext=pod,tcp,flow,port-distribution,icmp,http}"
# 上面的设置,表示开启了hubble的metrics输出模式,并输出以上这些信息。
# 默认情况下,Hubble daemonset会自动暴露metrics API给Prometheus。

你可以对接现有的Grafana+Prometheus服务,也可以部署一个简单的:

# 下面的命令会在命名空间cilium-monitoring下部署一个Grafana服务和Prometheus服务
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/v1.6/examples/kubernetes/addons/prometheus/monitoring-example.yaml

# 创建对应NodePort Service,方便外部访问web服务
kubectl expose deployment/grafana --type=NodePort --port=3000 --name=gnp -n cilium-monitoring 

kubectl expose deployment/prometheus --type=NodePort --port=9090 --name=pnp -n cilium-monitoring

完成部署后,打开Grafana网页,导入官方制作的dashboard,可以快速创建基于Hubble的metrics监控。等待一段时间,就能在Grafana上看到数据了:

Cilium配合Hubble,的确非常好用!

取代kube-proxy组件

Cilium另外一个很大的宣传点是宣称已经全面实现kube-proxy的功能,包括ClusterIP, NodePort, ExternalIPsLoadBalancer,可以完全取代它的位置,同时提供更好的性能、可靠性以及可调试性。当然,这些都要归功于eBPF的能力。

官方文档中提到,如果你是在先有kube-proxy后部署的Cilium,那么他们是一个“共存”状态,Cilium会根据节点操作系统的内核版本来决定是否还需要依赖kube-proxy实现某些功能,可以通过以下手段验证是否能停止kube-proxy组件:

# 检查Cilium对于取代kube-proxy的状态
> kubectl exec -it -n kube-system [Cilium-agent-pod] -- cilium status | grep KubeProxyReplacement

# 默认是Probe状态
# 当Cilium agent启动并运行,它将探测节点内核版本,判断BPF内核特性的可用性,
# 如果不满足,则通过依赖kube-proxy来补充剩余的Kubernetess,
# 并禁用BPF中的一部分功能
KubeProxyReplacement:   Probe   [NodePort (SNAT, 30000-32767), ExternalIPs, HostReachableServices (TCP, UDP)]

# 查看Cilium保存的应用服务访问列表
# 有了这些信息,就不需要kube-proxy进行中转了
> kubectl exec -it -n kube-system [Cilium-agent-pod] -- cilium service list
ID   Frontend              Service Type   Backend
1    10.96.0.10:53         ClusterIP      1 => 100.64.0.98:53
                                          2 => 100.64.3.65:53
2    10.96.0.10:9153       ClusterIP      1 => 100.64.0.98:9153
                                          2 => 100.64.3.65:9153
3    10.96.143.131:9090    ClusterIP      1 => 100.64.4.100:9090
4    10.96.90.39:9090      ClusterIP      1 => 100.64.4.100:9090
5    0.0.0.0:32447         NodePort       1 => 100.64.4.100:9090
6    10.1.1.179:32447      NodePort       1 => 100.64.4.100:9090
7    100.64.0.74:32447     NodePort       1 => 100.64.4.100:9090
8    10.96.190.1:80        ClusterIP
9    10.96.201.51:80       ClusterIP
10   10.96.0.1:443         ClusterIP      1 => 10.1.1.171:6443
                                          2 => 10.1.1.179:6443
                                          3 => 10.1.1.188:6443
11   10.96.129.193:12000   ClusterIP      1 => 100.64.4.221:12000
12   0.0.0.0:32321         NodePort       1 => 100.64.4.221:12000
13   10.1.1.179:32321      NodePort       1 => 100.64.4.221:12000
14   100.64.0.74:32321     NodePort       1 => 100.64.4.221:12000
15   10.96.0.30:3000       ClusterIP
16   10.96.156.253:3000    ClusterIP
17   100.64.0.74:31332     NodePort
18   0.0.0.0:31332         NodePort
19   10.1.1.179:31332      NodePort
20   10.96.131.215:12000   ClusterIP      1 => 100.64.4.221:12000

# 查看iptables是否有kube-proxy维护的规则
> iptables-save | grep KUBE-SVC
<Empty> # 说明kube-proxy没有维护任何应用服务跳转,即可以停止它了。



小结

Cilium作为当下最Cool的Kubernetes CNI网络插件,还有很多特性,如高阶network policy、7层流量控制等,这款基于BPF/eBPF打造出的简单、高效、易用的网络管理体验,有机会大家都来试用吧。

1 对 “最Cool Kubernetes网络方案Cilium入门教程”的想法;

发表评论

电子邮件地址不会被公开。 必填项已用*标注