Kubernetes网络方案Cilium

Cilium是第一个通过eBPF实现了kube-proxy所有功能的Kubernetes网络方案,让我们一起来实践下吧~

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 能够在大规模容器环境中也具有高度可伸缩性、可视化以及安全性。

环境要求


  • CentOS >= 7.0 or RedHat Enterprise Linux >= 8.0
  • Linux Kernel >= 4.9.17
  • Create a Kubernetes cluster without install cni
  • Mounted eBPF filesystem mounted on all worker nodes
  • Kubernetes must be configured to use CNI
  • Helm3

升级Linux Kernel


http://elrepo.org/tiki/tiki-index.php

Cilium使用了一种名为eBPF的新Linux内核技术,它支持在各种集成点(例如网络IO、应用Sockets)将eBPF字节码动态插入Linux内核,以实现安全性、网络和可见性逻辑。此技术需在新版本内核中才支持,因此我们需要先升级所有节点的内核到官方建议版本(Linux Kernel >= 4.9.17),可执行uname -r查看当前系统内核版本是否满足条件。

安装ELRepo

1
2
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm -y

列出可以使用的kernel版本。lt是longterm的缩写,指长期维护版;ml是mainline的缩写,指最新稳定版

1
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available

安装需要的Kernel,建议选择长期维护版

1
yum --enablerepo=elrepo-kernel install kernel-lt -y

设置以新版本内核启动

1
2
3
4
5
6
7
8
# 查看新版本内核的menuentry名称
cat /boot/grub2/grub.cfg |grep menuentry

# 设置以新版本内核启动,引号中的内容替换为上一步查看到的新版本内核的menuentry名称
grub2-set-default "CentOS Linux (5.4.142-1.el7.elrepo.x86_64) 7 (Core)"

# 验证配置生效
grub2-editenv list

重启机器,若机器上已运行有Kubernetes集群建议逐台重启

1
reboot

挂载BPF文件系统


在所有节点挂载BPF文件系统

1
2
mount bpffs /sys/fs/bpf -t bpf
echo "bpffs /sys/fs/bpf bpf defaults 0 0" >> /etc/fstab

验证是否挂载成功

1
2
# mount |grep bpf
none on /sys/fs/bpf type bpf (rw,relatime)

使用Helm3安装Cilium


说明
请使用Helm3,Helm2不再支持

添加Cilium Helm仓库

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

拉取Cilium Helm Chart

1
2
3
4
5
6
7
# 查询可安装的Cilium版本
helm search repo -l cilium

# Cilium社区为最后三个主要Cilium版本维护了次要的稳定版本。在此之前的主要版本中较旧的Cilium稳定版本被视为EOL。
# 本文安装v1.10.x版本
# 拉取v1.10.x版本Cilium Helm Chart
helm fetch cilium/cilium --version 1.10.3 --untar

修改cilium/values.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
k8sServiceHost: 10.211.55.10 # 指定API Server的IP,在禁用kube-proxy的情况下需显式指定
k8sServicePort: 8443 # 指定API Server的端口,在禁用kube-proxy的情况下需显式指定
...
# -- IPv4 CIDR range to delegate to individual nodes for IPAM.
clusterPoolIPv4PodCIDR: "10.244.0.0/16" # 与kube-controller-manager配置文件中的--cluster-cidr参数配置保持一致
# -- IPv4 CIDR mask size to delegate to individual nodes for IPAM.
clusterPoolIPv4MaskSize: 24
...
# -- Configure the kube-proxy replacement in Cilium BPF datapath
# Valid options are "disabled", "probe", "partial", "strict".
# ref: https://docs.cilium.io/en/stable/gettingstarted/kubeproxy-free/
# 设置Cilium和kube-proxy的混合工作模式
# global.kubeProxyReplacement=strict: 该选项期望使用无kube-proxy的Kubernetes设置,其中Cilium有望完全替代所有kube-proxy功能。 Cilium代理启动并运行后,将负责处理类型为ClusterIP,NodePort,ExternalIP和LoadBalancer的Kubernetes服务。如果不满足基本内核版本要求(请参阅不带kube-proxy注释的Kubernetes),则Cilium代理将在启动时退出并显示一条错误消息。
# global.kubeProxyReplacement=probe : 此选项适用于混合设置,即kube-proxy在Kubernetes集群中运行,其中Cilium部分替换并优化了kube-proxy功能。一旦Cilium代理启动并运行,它就会在基础内核中探查所需BPF内核功能的可用性,如果不存在,则依靠kube-proxy补充其余的Kubernetes服务处理,从而禁用BPF中的部分功能。在这种情况下,Cilium代理将向其日志中发送一条信息消息。例如,如果内核不支持Host-Reachable Services,则节点的主机名空间的ClusterIP转换是通过kube-proxy的iptables规则完成的。
# global.kubeProxyReplacement=partial: 与探针类似,此选项用于混合设置,即kube-proxy在Kubernetes集群中运行,其中Cilium部分替换并优化了kube-proxy功能。与探查基础内核中可用的BPF功能并在缺少内核支持时自动禁用负责BPF kube-proxy替换的组件的探针相反,该部分选项要求用户手动指定应替换BPF kube-proxy的组件。与严格模式类似,如果不满足基本内核要求,则Cilium代理将在启动时通过错误消息进行援助。对于细粒度的配置,可以将global.hostServices.enabled,global.nodePort.enabled和global.externalIPs.enabled设置为true。默认情况下,所有三个选项均设置为false。
kubeProxyReplacement: "probe"
...

安装Cilium

1
helm install cilium -f values.yaml . --namespace kube-system

以下是Cilium的整体部署组件列表

验证安装


https://github.com/cilium/cilium-cli/releases下载对应版本和架构的Cilium CLI。Cilium CLI可用于安装Cilium、检查Cilium安装状态以及启用/禁用各种功能(例如clustermesh、Hubble)。

1
tar zxf cilium-linux-amd64.tar.gz -C /usr/local/bin/

验证Cilium是否已正确安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Hubble: disabled
\__/¯¯\__/ ClusterMesh: disabled
\__/

DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2
Containers: cilium-operator Running: 2
cilium Running: 3
Image versions cilium quay.io/cilium/cilium:v1.10.3@sha256:8419531c5d3677158802882bdfe2297915c43f2ebe3649551aaac22de9f6d565: 3
cilium-operator quay.io/cilium/operator-generic:v1.10.3@sha256:337ebf27eae4fbad51cc4baf9110b3ec6753320dd33075bc136e2a1865be5eb5: 2

查看当前Cilium的kube-proxy替换模式

1
kubectl exec -it -n kube-system cilium-xxxxx -- cilium status | grep KubeProxyReplacement

官方提供了一个connectivity检查工具,以检测部署好的Cilium是否工作正常。可到此页面查询Cilium对应版本的检查工具配置清单(connectivity-check.yaml),并确保至少有两个可用的Node节点;若仅有一个Node节点,可在此页面查询Cilium对应版本的单节点检查工具配置清单(connectivity-check-single-node.yaml)。

1
2
3
4
5
6
# 为检测工具创建单独的命名空间
kubectl create ns cilium-test

# 部署检测工具
wget https://raw.githubusercontent.com/cilium/cilium/v1.10.3/examples/kubernetes/connectivity-check/connectivity-check.yaml -O /root/connectivity-check.yaml
kubectl apply -n cilium-test -f /root/connectivity-check.yaml

connectivity会部署一系列的Deployment并且会使用各种连接路径相互连接。包括有无经过Service负载均衡和各种网络策略组合。通过Pod名称可以方便的看出对应的测试场景,并通过就绪探针和存活探针来表示测试成功还是失败。

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

开启网络可视化Hubbel


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

上面已经通过Helm安装了Cilium,则直接使用以下命令开启Hubble和UI

1
2
3
4
5
helm upgrade cilium cilium/cilium --version 1.10.3 \
--namespace kube-system \
--reuse-values \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true

默认Hubble通过ClusterIP类型的Service进行暴露,为了方便从外部访问Hubble UI,将Service修改为NodePort类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# kubectl edit svc hubble-ui -n kube-system
...
spec:
clusterIP: 10.0.0.81
clusterIPs:
- 10.0.0.81
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8081
nodePort: 32000 # 定义暴露端口,可自定义
selector:
k8s-app: hubble-ui
sessionAffinity: None
type: NodePort # 改为NodePort类型
...

验证Hubble是否开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看hubble的pod是否Running
# kubectl get pod -n kube-system | grep hubble
hubble-relay-7967f4665-q7k9x 1/1 Running 0 9m19s
hubble-ui-95d74d44c-9t9qx 3/3 Running 0 9m19s

# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Hubble: OK
\__/¯¯\__/ ClusterMesh: disabled
\__/

DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium-operator Running: 2
cilium Running: 3
hubble-relay Running: 1
Image versions cilium quay.io/cilium/cilium:v1.10.3@sha256:8419531c5d3677158802882bdfe2297915c43f2ebe3649551aaac22de9f6d565: 3
cilium-operator quay.io/cilium/operator-generic:v1.10.3@sha256:337ebf27eae4fbad51cc4baf9110b3ec6753320dd33075bc136e2a1865be5eb5: 2
hubble-relay quay.io/cilium/hubble-relay:v1.10.3@sha256:af8ff09fe374c307356a85b0e0c158359a2e7299f93280151301b7f2fac27339: 1

浏览器访问http://<NodeIP>:<nodeport>即可打开Hubble UI。

在左上角选择或者直接单击首页上的命名空间名称即可切换到对应命名空间下。以cilium-test命名空间为例,页面上半部分就是之前部署的一整套connectivity-check组件的数据流量图,官方叫做Service Map,默认情况下可以自动发现基于网络3层和4层的访问依赖路径,看上去十分酷炫,有点类似分布式链路追踪图。
页面下半部分显示的是每条数据流路径的详细信息,包括发起请求的pod名称、发起请求的IP、发起请求的service名称、请求的目标pod名称、请求的目标IP、请求的目标service名称、请求的目标端口、执行动作(转发或丢弃)、TCP flags、最后一次查看时间等.(单击”Columns”可自定义显示的字段)

单击某个服务还能看到更为详细的关系图,单击任意一条flow,也可以查看到更多详细信息。

删除Cilium


1
helm delete cilium --namespace kube-system

参考文档