特殊环境 Agent 部署
#1. 特殊的 K8s CNI
在常见 K8s 环境中,DeepFlow Agent 可以采集到全栈观测信号,如下图左上角所示:
- 同一个 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 和 cBPF Pod NIC 两种位置的数据
- 不同的 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall、cBPF Pod NIC 以及 cBPF Node NIC 三种位置的数据
不同 K8s CNI 下的数据采集能力(Pod 与 Pod 通信场景)
但是,在某些 CNI 下,由于流量路径的特殊性,DeepFlow Agent 采集到的数据会有差异:
- 在 Cilium CNI 环境中(上图右上角):
- Cilium 使用 XDP (opens new window) 将网络绕过了 TCP/IP 协议栈,导致名为 lxc-xxx 的 Pod NIC 上只能看到单向流量
- 同一个 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 一种位置的数据
- 不同的 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 和 cBPF Node NIC 两种位置的数据,后者采集自 Node eth0
- 在 MACVlan、华为云 CCE Turbo (opens new window) 等 CNI 环境中(上图左下角):
- 使用 MACVlan 子接口而非 Veth-Pair + Bridge,此时在 Root Netns 中没有对应的 Pod NIC,但是能在 Node eth0 上看到所有 Pod 的所有流量
- 此时,DeepFlow Agent 可参照下文配置
tap_mode = 1 (virtual mirror)
,将 Node NIC 上的流量等同于视为
是在 Pod NIC 上采集到的 - 同一个 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 和 cBPF Pod NIC 两种位置的数据,后者采集自 Node eth0
- 不过,由于 eth0 上只有一份通信流量,因此客户端、服务端共享一份 cBPF Pod NIC 位置的数据
- 不同的 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 和 cBPF Pod NIC 两种位置的数据,后者采集自 Node eth0
- 在 IPVlan CNI 环境中(上图右下角):
- 使用 IPVlan 子接口而非 Veth-Pair + Bridge,此时在 Root Netns 中没有对应的 Pod NIC,且仅能在 Node eth0 上看到 Pod 进出 Node 的流量
- 同一个 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 一种位置的数据
- 不同的 Node 上的两个 Pod 互访时,可采集到 eBPF Syscall 和 cBPF Node NIC 两种位置的数据,后者采集自 Node eth0
另外,eBPF XDP 还可以与 IPVlan 混合使用(例如阿里云的 Terway CNI (opens new window)),此时的流量采集能力等同于 Cilium 或 IPVlan。
一些参考资料:
- Bridge vs Macvlan (opens new window)
- Macvlan vs Ipvlan (opens new window)
- Packet Walk(s) In Kubernetes (opens new window)
#1.1 MACVlan
K8s 使用 macvlan CNI 时,在 rootns 下只能看到所有 POD 共用的一个虚拟网卡,此时需要对 deepflow-agent 进行额外的配置:
创建 agent-group 和 agent-group-config:
deepflow-ctl agent-group create macvlan deepflow-ctl agent-group-config create macvlan
1
2获取 macvlan agent-group ID:
deepflow-ctl agent-group list | grep macvlan
1新建 agent-group-config 配置文件
macvlan-agent-group-config.yaml
:vtap_group_id: g-xxxxxx ## Regular Expression for TAP (Traffic Access Point) ## Length: [0, 65535] ## Default: ## Localhost: lo ## Common NIC: eth.*|en[osipx].* ## QEMU VM NIC: tap.* ## Flannel: veth.* ## Calico: cali.* ## Cilium: lxc.* ## Kube-OVN: [0-9a-f]+_h$ ## Note: Regular expression of NIC name for collecting traffic tap_interface_regex: eth0 ## Traffic Tap Mode ## Default: 0, means local. ## Options: 0, 1 (virtual mirror), 2 (physical mirror, aka. analyzer mode) ## Note: Mirror mode is used when deepflow-agent cannot directly capture the ## traffic from the source. For example: ## - in the K8s macvlan environment, capture the Pod traffic through the Node NIC ## - in the Hyper-V environment, capture the VM traffic through the Hypervisor NIC ## - in the ESXi environment, capture traffic through VDS/VSS local SPAN ## - in the DPDK environment, capture traffic through DPDK ring buffer ## Use Analyzer mode when deepflow-agent captures traffic through physical switch ## mirroring. tap_mode: 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25创建 agent-group-config:
deepflow-ctl agent-group-config create -f macvlan-agent-group-config.yaml
1修改 deepflow-agent 的 agent-group:
kubectl edit cm -n deepflow deepflow-agent
1添加配置:
vtap-group-id-request: g-xxxxx
1停止 deepflow-agent:
kubectl -n deepflow patch daemonset deepflow-agent -p '{"spec": {"template": {"spec": {"nodeSelector": {"non-existing": "true"}}}}}'
1通过 deepflow-ctl 删除 macvlan 的 agent:
deepflow-ctl agent delete <agent name>
1启动 deepflow-agent:
kubectl -n deepflow patch daemonset deepflow-agent --type json -p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/non-existing"}]'
1查看 deepflow agent list, 确保 agent 加入了 macvlan group:
deepflow-ctl agent list
1
#1.2 华为云 CCE Turbo
参考 MACVlan 配置方法即可。
#1.3 IPVlan
唯一需要注意的是,采集器的 tap_interface_regex 只需配置为 Node NIC 列表。
#1.4 Cilium eBPF
唯一需要注意的是,采集器的 tap_interface_regex 只需配置为 Node NIC 列表。
#2. 特殊 K8s 资源或 CRD
这类场景需要进行以下操作:
- Agent 高级配置中打开和关闭对应的资源
- 配置 Kubernetes API 权限
#2.1 OpenShift
该场景需要关闭默认的 Ingress
资源获取,打开 Route
资源获取。
Agent 高级配置如下:
static_config:
kubernetes-resources:
- name: ingresses
disabled: true
- name: routes
2
3
4
5
ClusterRole 配置增加:
rules:
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- get
- list
- watch
2
3
4
5
6
7
8
9
#2.2 OpenKruise
该场景下需要从 API 获取 CloneSet
和 apps.kruise.io/StatefulSet
资源。
Agent 高级配置如下:
static_config:
kubernetes-resources:
- name: clonesets
group: apps.kruise.io
- name: statefulsets
group: apps
- name: statefulsets
group: apps.kruise.io
2
3
4
5
6
7
8
注意这里需要加上 Kubernetes 的 apps/StatefulSet
。
ClusterRole 配置增加:
- apiGroups:
- apps.kruise.io
resources:
- clonesets
- statefulsets
verbs:
- get
- list
- watch
2
3
4
5
6
7
8
9
#2.3 OpenGauss
该场景下需要从 API 获取 OpenGaussCluster
资源。
Agent 高级配置如下:
static_config:
kubernetes-resources:
- name: opengaussclusters
2
3
ClusterRole 配置增加:
- apiGroups:
- opengauss.sig
resources:
- opengaussclusters
verbs:
- get
- list
- watch
2
3
4
5
6
7
8
#3. K8s 运行 Agent 权限受限
#3.1 无 K8s Daemonset 部署权限
当没有在 Kubernetes 集群中运行 Daemonset 的权限、但可在 K8s Node 上直接运行普通进程时,可使用该方法实现 Agent 部署。
- 以 deployment 形态部署一个 deepflow-agent
- 通过设置环境变量
K8S_WATCH_POLICY=watch-only
,该 agent 仅实现对 K8s 资源的 list-watch 及上送控制器的功能 - 这个 agent 的其他所有功能均会自动关闭
- agent 请求 server 时告知自己在 watch-k8s,server 会将此信息更新到 MySQL 数据库中
- 这个仅用做 Watcher 的 Agent 将不会出现在 Agent 列表中
- 通过设置环境变量
- 在这个 K8s 集群中,以 Linux 进程的形态在每个 K8s Node 上运行一个常规功能的 deepflow-agent
- 由于这些 agent 没有
IN_CONTAINER
环境变量,不会 list-watch K8s 资源 - 这些 agent 依然会获取 POD 的 IP 和 MAC 地址并同步到 server
- 这些 agent 将完成所有的观测数据采集功能
- server 向这些 agent 下发的 Agent 类型为 K8s
- 由于这些 agent 没有
#3.1.1 部署 deployment 模式 DeepFlow Agent
cat << EOF > values-custom.yaml
deployComponent:
- "watcher"
clusterNAME: your-cluster-name
EOF
helm install deepflow -n deepflow deepflow/deepflow-agent --create-namespace \
-f values-custom.yaml
2
3
4
5
6
7
8
部署后,将自动创建 Domain(对应此 K8s 集群),通过 deepflow-ctl domain list
中获取 your-cluster-name
cluster 的 kubernetes-cluster-id
,再继续下面的操作。
#3.1.2 部署普通进程形式的 DeepFlow Agent
- 参考传统服务器部署 DeepFlow Agent,但无需创建 Domain
- 修改 agent 配置文件
/etc/deepflow-agent/deepflow-agent.yaml
,kubernetes-cluster-id
填写上一步获取的集群 ID
#3.2 不允许 Daemonset 请求 apiserver
默认情况下 DeepFlow Agent 在 K8s 中以 Daemonset 方式运行。但有些情况下为了保护 apiserver 避免过载,Daemonset 不允许对 apiserver 请求。此时也可使用本文中「无 Daemonset 部署权限」的类似方式进行部署:
- 部署一个 deepflow-agent deployment,仅负责 list-watch apiserver、同步 K8s 资源信息
- 部署一个 deepflow-agent daemonset,任何 Pod 都不会 list-watch apiserver
#3.3 不允许 deepflow-agent 请求 apiserver
deepflow-server 依赖 deepflow-agent 上报的 K8s 资源信息来实现 AutoTagging 能力,当你的环境不允许 deepflow-agent 直接 Watch K8s apiserver 时,你可以自己实现一个专门用于同步 K8s 资源的 pseudo-deepflow-gent。这个 pseudo-deepflow-agent 需要实现的功能包括:
- 周期性的 List-Watch K8s apiserver 以获取最新的 K8s 资源信息
- 调用 deepflow-server 的 gRPC 接口上报 K8s 资源信息
#3.3.1 gRPC 接口
上报 K8s 资源信息的接口为(GitHub 代码链接 (opens new window)):
rpc KubernetesAPISync(KubernetesAPISyncRequest) returns (KubernetesAPISyncResponse) {}
pseudo-deepflow-agent 上报消息的结构体说明(GitHub 代码链接同上):
message KubernetesAPISyncRequest {
// 如无特殊说明,以下字段均必须携带。
// K8s 集群标识。
// 请使用同一个 K8s 集群中 deepflow-agent.yaml 所配置的值。
optional string cluster_id = 1;
// 资源信息的版本号。
// 当 K8s 资源信息发生变化时,请确保此版本号也要进行改变,通常可使用 Linux Epoch。
// 当 K8s 资源信息没有变化时,携带上一次的版本号,此时 entries 无需传输。
// 即使资源信息没有变化,也要周期性请求 deepflow-server,保证两次请求间隔不要超过 24 小时。
optional uint64 version = 2;
// 异常信息。
// 当调用 K8s API 异常,或者发生其他错误时,可通过此字段告知 deepflow-server。
// 当存在 error_msg 时,建议携带上一次请求使用的 version 和 entries 字段。
optional string error_msg = 3;
// Source IP 地址。
// 通常可填写为 pseudo-deepflow-agent 请求 gRPC 时使用的客户端 IP 地址。
// 使用有代表性、区分性的 source_ip 能够方便查阅 deepflow-server 日志,定位请求者。
optional string source_ip = 5;
// 各类 K8s 资源的所有信息。
// 请注意需要包括所有类型的所有资源,未出现的资源将会被 deepflow-server 认为已删除。
repeated common.KubernetesAPIInfo entries = 10;
}
message KubernetesAPIInfo {
// K8s 资源类型,当前支持的资源类型有:
// - *v1.Node
// - *v1.Namespace
// - *v1.Deployment
// - *v1.StatefulSet
// - *v1.DaemonSet
// - *v1.ReplicationController
// - *v1.ReplicaSet
// - *v1.Pod
// - *v1.Service
// - *v1beta1.Ingress
optional string type = 1;
// 该类型的资源列表。
// 注意:请使用 JSON 序列化,之后使用 zlib 进行压缩,传输压缩后的字节流即可。
optional bytes compressed_info = 3;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
deepflow-server 回复消息的结构体说明(GitHub 代码链接同上):
message KubernetesAPISyncResponse {
// deepflow-server 已经接受的资源信息版本号,通常等于最近一次请求中的 version。
optional uint64 version = 1;
}
2
3
4
#3.3.2 KubernetesAPIInfo
注意,deepflow-server 要求某些 K8s 资源类型必须上报包括:
*v1.Node
*v1.Namespace
*v1.Pod
*v1.Deployment
、*v1.StatefulSet
、*v1.DaemonSet
、*v1.ReplicationController
、*v1.ReplicaSet
:根据 Pod 的工作负载类型按需上报即可
除此之外的其他资源可以不上报:
*v1.Service
*v1beta1.Ingress
对于上述资源,pseudo-deepflow-agent 需要上报的信息可参考此处的文档。
#4. 云服务器运行 Agent 权限受限
#4.1 使用非 root 用户运行 deepflow-agent
假设我们希望使用普通用户 deepflow 来运行安装于 /usr/sbin/deepflow-agent 的 Agent,我们必须先通过 root 用户添加 deepflow 所需的权限:
## Use the root user to grant execution permissions to the deepflow-agent
setcap cap_sys_ptrace,cap_net_raw,cap_net_admin,cap_ipc_lock,cap_sys_admin=eip /usr/sbin/deepflow-agent
mkdir /sys/fs/cgroup/cpu/deepflow-agent
mkdir /sys/fs/cgroup/memory/deepflow-agent
chown -R deepflow:deepflow /sys/fs/cgroup/cpu/deepflow-agent
chown -R deepflow:deepflow /sys/fs/cgroup/memory/deepflow-agent
chown -R deepflow:deepflow /usr/sbin/deepflow-agent
2
3
4
5
6
7
使用非 root 用户运行 deepflow-agent,例如:
systemctl start deepflow-agent
若希望卸载 deepflow-agent,注意删除对应的权限:
## Use the root user to revoke execution permissions from the deepflow-agent
setcap -r /usr/sbin/deepflow-agent
rmdir /sys/fs/cgroup/cpu/deepflow-agent
rmdir /sys/fs/cgroup/memory/deepflow-agent
2
3
4