随着eBPF技术的发展,基于该技术的网络测控工具越来越多,也越来越成熟。作为下一代网络测控技术,eBPF直接内嵌Linux内核,具有高性能、高扩展、安全性等优势,在网络、安全、可观察方面均堪大用。
在容器云为基础的现代系统架构中,eBPF技术尤其具有重要意义,同时也已经出现了Cilium(CNCF云原生项目,用于解决大集群规模下iptables性能问题)、Pixie等优秀的开源项目。
今天我们介绍一个同类的项目Retina(视网膜),这是由微软开源,使用Golang语言开发的K8S网络测控系统
概述Retina是一个与云无关的开源K8S网络可观察性平台,可以用来解决容器云平台中DevSecOps下网络流量的安全管控和合规性等问题。Retina提供了一个用于监控应用程序和网络健康与安全的集中中心,满足集群网络管理员、集群安全管理员和DevOps工程师的需求。
Retina收集可自定义的遥测数据,并且支持将其存储到无服务器架构中自建Prometheus中心,以及公有云存储中(例如Azure Monitor和其他SaaS产品),并以Grafana等多种界面展示和可视化,比如Azure Log Analytics和其他SaaS产品)。
特征网络流量洞察;
基于先进的eBPF技术;
按需且可配置,支持自定义指标和流日志;
支持分布式数据包捕获;
云原生支持,可以适用于任何CNI和任何K8S平台。
支持多种操作系统(如 Linux、Windows、Azure Linux)。
典型用例Retina可以实时高效的测控和捕获平台网络情况,可以最大限度地减少网络相关故障排查痛点和调查时间,典型的应用场景有:
调试网络连接
为什么Pod无法相互连接?传统的排查方法耗时耗力,涉及执行数据包捕获,其中必须识别所涉及的节点,获得对每个节点的访问权限,运行tcpdump命令,并导出每个节点的结果,然后人为分析。
借助Retina,可以用单个CLI命令或CRD/YAM自动执行该过程,实现:
捕获集群中特定Pod的所有节点上网络流量。
将每个节点的结果上传到存储blob。
监控网健康状况
Retina通过Prometheus告警、Grafana仪表板等,可实现:
监视命名空间中丢弃的流量。
针对生产DNS错误激增发出警报。
在测试应用程序的规模时观察API服务器延迟的变化。
针对Pod发送超阈值(低于)的流量,给值守团队发出告警。
基本架构Retina使用两种类型的遥测:指标和捕获。
指标Retina提供了丰富的持续可观察性指标:
上行/下行网络流量;
丢包;
TCP/UDP;
域名系统;
API服务器延迟;
节点/接口统计;
同时提供还支持对这些指标:
基本指标(默认,节点级指标)求和。
高级/Pod级指标 (详见文档)。
捕获Retina捕获记录指定Nodes/Pod的网络流量和元数据。捕获是按需的,并且可以输出到多个目的地。
安装配置安装make helm-install基本模式(支持捕获)
make helm-install-with-operator具有远程上下文的高级模式(支持捕获)
make helm-install-advanced-remote-context具有本地上下文的高级模式(支持捕获)
配置自建Prometheus/Grafana
创建 K8S 集群并安装Retina DaemonSet,安装需要通过Helm Chart 安装Prometheus。
helm repo add prometheus-community prometheus-community.github.io/helm-chartshelm repo update安装Prometheus图表
helm install prometheus -n kube-system -f deploy/prometheus/values.yaml prometheus-community/kube-prometheus-stack或者,如已经安装,请升级认为合适的方式,提供新的作业名称作为附加的抓取配置,例如:
helm upgrade prometheus -n kube-system -f deploy/prometheus/values.yaml prometheus-community/kube-prometheus-stack节点Grafana和 ube-state指标可能会在Windows节点上调度,当前图表与这些组件没有节点关联性。可能需要一些手动干预。
验证Retina Pod是否正在通过端口转发Prometheus服务器进行抓取:
kubectl port-forward --namespace kube-system svc/prometheus-operated 9090浏览器访问localhost:9090/targets查看Retina Pod是否被发现并被抓取
配置Grafana
创建一个Grafana实例,然后按照配置Grafana进行操作,或者上面步骤安装的实例。获取Grafana密码:
kubectl get secret -n kube-system prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo导入新的仪表板18814-kubernetes-networking-clusters。如果导入成功,则指标应该可见:
对于自建Prometheus/Grafana或确保可将服务器端口转发到localhost:9090,或者为其他 HTTP 端点配置服务器。端口转发 svc/prometheus-grafana以从本地浏览器访问。
检查Grafana 以确保托管Prometheus数据源存在:
进入仪表板页面并选择“导入”:
导18814-kubernetes-networking-clusters仪表板
Grafana仪表板现在应该可见。
仪表板的版本将预安装在以下位置:
仪表板 > 托管Prometheus > K8S/网络/集群
仪表板 > 托管Prometheus > K8S / 网络 / DNS
基本用法Retina捕获允许用户按需捕获指定节点/Pod的网络流量/元数据,结果可以输出到主机文件系统、存储blob等。有两种触发 Capture 的方法:CLI命令或CRD/YAML配置。
CLI命令安装Retina CLI后可用,目前仅支持Linux操作系统。典型的一个实例是:
捕获所有Linux节点的网络流量,将输出存储在每个节点上的/mnt/capture文件夹中。
kubectl-retina capture create --host-path /mnt/capture --node-selectors "K8S.io/os=linux"对于每个Capture,都会为每个相关节点创建一个K8S作业(可以选择该节点和/或可以托管选定的 Pod)。作业的工作Pod运行指定的持续时间,捕获网络信息并将其包装到tarball中,并将tarball复制到指定的输出位置。作为一种特殊情况,出于安全考虑,将创建一个包含存储blob SAS的K8S密钥,然后将其挂载到Pod。
为每个Retina Capture分配一个随机散列名称以对其进行唯一标记。
捕获CRD创建Capture并将Capture项目存储到Blob SAS URL指定的存储帐户中。
创建一个Secret来存储blob SAS URL:
apiVersion: v1data:## Data key is required to be "blob-upload-url"blob-upload-url: <based-encode-blob-sas-url>kind: Secretmetadata:name: blob-sas-urlnamespace: defaulttype: Opaque创建一个Capture,指定创建为blobUpload的密钥,该例还将工件存储在节点主机路径上
apiVersion: retina.sh/v1alpha1kind: Capturemetadata:name: capture-testspec:captureConfiguration:captureOption:duration: 30scaptureTarget:nodeSelector:matchLabels:K8S.io/hostname: aks-nodepool1-11396069-vmss000000outputConfiguration:hostPath: "/tmp/retina"blobUpload: blob-sas-url与1类似,为每个相关节点创建一个K8S作业。
Retina CLI捕获详解Retina capture命令允许用户捕获目标的网络流量和元数据,然后将捕获文件发送到输出配置的位置。也可以使用Capture CRD后执行捕获。
创建捕获retina capture create使用底层K8S作业创建捕获。
非等待(--no-wait)
不要等待长时间运行的捕获作业完成。默认情况下为-no-wait=false,Retina capture CLI将在作业完成之前退出。CLI将等待作业完成并清理创建的K8S 资源。
非等待长时间运行的捕获作业完成:
kubectl retina capture create --host-path /mnt/capture --node-selectors "K8S.io/os=linux" --no-wait=true命名空间(--namespace)
托管捕获作业的命名空间和用于网络捕获的其他k8s资源。
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux"捕获目标捕获目标表示将执行网络数据包捕获的目标,用户可以通过节点选择器或节点名称选择节点,也可以通过pod选择器和命名空间选择器对选择Pod。
捕获节点选择器选择的节点上的网络数据包:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux"捕获按节点名称选择的节点上的网络数据包:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-names "aks-nodepool1-41844487-vmss000000,aks-nodepool1-41844487-vmss000001"捕获pod选择器和命名空间选择器对选择的pod上的网络数据包:
kubectl retina capture create --host-path /mnt/capture --namespace capture --pod-selectors="k8s-app=kube-dns" --namespace-selectors="K8S.io/metadata.name=kube-system"停止捕获可以通过以下任一方式停止捕获:在给定的时间内,由duration标志,或者当允许的最大捕获文件达到max-size。当两者都指定时,捕获将在任一条件首次满足时停止。根据需要,在满足指定条件之前删除捕获。网络流量将上传到指定的输出位置。
捕捉持续时间(--duration)
抓包时长(默1m),例2分钟后停止捕捉:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --duration=2m最大捕获尺寸(--max-size)
将捕获文件的大小限制为 MB(默认100MB):当捕获文件大小达到50MB时停止捕获:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --max-size=50数据包大小(--packet-size)
将每个数据包的大小限制为字节,超过PacketSize的数据包将被截断:将每个数据包大小限制为96字节
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --packet-size=96捕获配置captureconfiguration表示网络抓包的具体配置。
数据包捕获过滤器(--include-filter,--exclude-filter)
数据包捕获过滤器表示捕获中要包含/排除的一系列过滤器:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --exclude-filter="10.224.0.26:80,10.224.0.33:8080" --include-filter="10.224.0.42:80,10.224.0.33:8080"TCP转储过滤器(--tcpdump-filter)
原始tcpdump标志仅适用于Linux。可以在TCPDUMP手册页中找到可用的 tcpdump过滤器。注意:这仅包括tcpdump标志,对于表达式部分,请使用数据包包含/排除过滤器。例如:过滤 DNS 查询
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --tcpdump-filter="udp port 53"包括元数据(--include-metadata)
如果为true,则将静态网络元数据收集到捕获文件中(默认 true),禁用收集网络元数据:
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux" --include-metadata=false作业数量限制(--job-num-limit)
每次捕获可以创建最大数量的作业 默认值0表示没有限制。这可以通过每个 CLI 命令的 CLI 标志或 retina-operator 使用的配置映射进行配置。当创建作业需要作业数量超过此限制时,会失败并提示如下 Error: the number of capture jobs 3 exceeds the limit 2。
kubectl retina capture create --job-num-limit=10 --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux"输出配置OutputConfiguration 指示将存储捕获的位置,并且应至少指定一个位置。 Blob上传需要具有存储帐户容器写入权限的Blob共享访问签名,需要配置对应的密钥和证书等。
将捕获文件存储在节点主机路径中/mnt/capture
kubectl retina capture create --host-path /mnt/capture --namespace capture --node-selectors "K8S.io/os=linux"将捕获文件存储到PVC mypvc命名空间中的访问模式为ReadWriteMany capture
kubectl retina capture create --pvc mypvc --namespace capture --node-selectors "K8S.io/os=linux"将捕获文件存储到云存储帐户
kubectl retina capture create --blob-upload <Blob SAS URL with write permission> --node-selectors "K8S.io/os=linux"调试模式在调试模式下,当--debug指定后,可以覆盖官方默认的抓包作业Pod镜像 GHCR一。
使用ghcr.io默认调试模式下的镜像
kubectl retina capture create --host-path /mnt/test --namespace capture --node-selectors "K8S.io/os=linux" --debug使用定制的retina代理镜像
RETINA_AGENT_IMAGE=<YOUR RETINA AGENT IMAGE> kubectl retina capture create --host-path /mnt/test --namespace capture --node-selectors "K8S.io/os=linux" --debug删除捕获retina capture delete删除具有指定Capture名称的K8S作业:
kubectl retina capture delete --name retina-capture-zlx5v捕获列表retina capture list列出命名空间或所有命名空间中的捕获。
列出命名空间下的捕获
kubectl retina capture list --namespace capture列出所有命名空间下捕获
kubectl retina capture list --all-namespaces获取输出从指定位置下载或复制tarball后,通过tarLinux shell或 Windows Powershell 中的命令,例如,
tar -xvf retina-capture-aks-nodepool1-41844487-vmss000000-20230320013600UTC.tar.gztarball 采用这样的名称模式,$(capturename)-$(hostname)-$(date +%Y%m%d%H%M%S%Z).tar.gz,例如, retina-capture-aks-nodepool1-41844487-vmss000000-20230313101436UTC.tar.gz。
总结本文介绍了一个基于下一代网络测控技术eBPF的K8S网络测控系统,可以用于在容器云复杂网络平台下高效、自动的捕获、存储和可视化网络流量等信息。对于复杂平台下排障、安全监控和数据合规管理等都有积极的意义,值得我们大家尝鲜试用。