使用Cilium/eBPF实现大规模云原生网络和安全

大家读完觉得有帮助记得关注和点赞!!!

目录

抽象

[1 Trip.com 云基础设施](#1 Trip.com 云基础设施)

[1.1 分层架构](#1.1 分层架构)

[1.2 更多细节](#1.2 更多细节)

[2 纤毛在 Trip.com](#2 纤毛在 Trip.com)

[2.1 推出时间表](#2.1 推出时间表)

[2.2 自定义](#2.2 自定义)

[2.3 优化和调整](#2.3 优化和调整)

[2.3.1 解耦安装](#2.3.1 解耦安装)

[2.3.2 避免重试/重启风暴](#2.3.2 避免重试/重启风暴)

[2.3.3 稳定性优先](#2.3.3 稳定性优先)

[2.3.4 规划规模](#2.3.4 规划规模)

[2.3.5 性能调优](#2.3.5 性能调优)

[2.3.6 可观察性和警报](#2.3.6 可观察性和警报)

[2.3.7 其他选项](#2.3.7 其他选项)

[2.4 多集群解决方案](#2.4 多集群解决方案)

[2.4.1 集群网格](#2.4.1 集群网格)

[2.4.2 KVStoreMesh](#2.4.2 KVStoreMesh)

[3 高级故障排除技巧](#3 高级故障排除技巧)

[3.1 使用delve/dlv](#3.1 使用delve/dlv)

[3.2 使用bpftrace](#3.2 使用bpftrace)

[3.2.1 使用绝对路径](#3.2.1 使用绝对路径)

[2.3.2 带 PID/proc/](#2.3.2 带 PID/proc/)

[3.3 操作 BPF 映射bpftool](#3.3 操作 BPF 映射bpftool)

[3.4 使用 API 操作 kvstore 内容etcdctl](#3.4 使用 API 操作 kvstore 内容etcdctl)

[4 总结](#4 总结)


抽象

Trip.com 年,我们将第一个 Cilium 节点(裸机)投入生产 在 2019 年。从那时起,我们几乎所有的 Kubernetes 集群 - 都是本地的 公共云中的裸机和自我管理的集群 - 已切换到 Cilium。

现在有 ~10K 个节点,~300K Pod 在 Kubernetes 上运行, Cilium 为我们的关键业务服务提供支持,例如酒店 搜索引擎、金融/支付服务、内存数据库、数据存储 服务,其中涵盖了延迟方面的广泛要求, 吞吐量等

根据我们 4 年的经验,观众将学习 Cilium 的云原生网络和安全性,包括:

  1. 如何使用 CiliumNetworkPolicy 进行 L3/L4 访问控制,包括将安全模型扩展到 BM/VM 实例;
  2. 我们名为 KVStoreMesh 的新多集群解决方案作为 ClusterMesh 的替代方案,以及我们如何使其与社区兼容以便轻松升级;
  3. 大规模构建稳定性,例如管理控制平面和多集群中断,以及我们因此对 Cilium 所做的改进。

1 Trip.com 云基础设施

1.1 分层架构

Trip.com 云团队负责公司在全球的基础设施,如下所示:

  • 在底部,我们有数据中心和几个公共云供应商;
  • 底部上方是我们用于 BM、VM 和容器的编排系统;
  • 再上一层是内部开发的持续交付平台 (CI/CD);
  • 顶部是我们的业务服务和相应的中间件;
  • 在垂直方向上,我们在不同级别都有安全和管理工具。

云范围是图中所示的框。

1.2 更多细节

有关我们基础设施的更多具体信息:

  • 我们的大部分工作负载现在都在 Kubernetes 上运行,我们有 3 个大型 集群和几个小型集群,具有总节点和 pod;~10k``~300k
  • 大多数 Kubernetes 节点都是刀片服务器;哪
  • 使用内部维护的 4.19/5.10 内核运行;
  • 对于主机间网络,我们将 BGP 用于本地集群和 ENI 适用于云上的自建集群。

2 纤毛在 Trip.com

2.1 推出时间表

以下是我们推出流程的简单时间表:

  1. 我们从 2018 年开始研究云原生网络解决方案 [9],当然,Cilium 胜出;
  2. 我们的第一个纤毛节点于 2019 年投入生产 [10];
  3. 从那时起,我们的各种业务和基础设施服务开始透明地迁移到 Cilium。

2021 年,随着大多数在线业务已经在 Cilium 中, 我们启动了一个基于 Cilium 网络策略的安全项目 [8]。

我们使用的功能:

  • 服务负载均衡 (eBPF/XDP)
  • CiliumNetworkPolicy (CNP)
  • eBPF 主机路由
  • eBPF 带宽管理器
  • 哈勃(部分)
  • Rsyslog 驱动程序
  • 性能提升选项,如 sockops、eBPF 重定向
  • ...

2.2 自定义

首先,此处显示了两个 Kubernetes 集群,

我们基于上述拓扑的一些自定义:

  1. 使用 docker-compose 部署 cilium 以去除 kubernetes 依赖 [1];
  2. 为每个代理分配一个用于 Kubernetes 身份验证的专用证书,而不是所有代理共享的 seviceaccount;
  3. 我们已经帮助完善了 Cilium 的 rsyslog 驱动程序,并已将所有代理日志发送到 ClickHouse 进行故障排除;
  4. 添加了一些补丁来促进业务迁移,但这并不是那么通用,所以我们没有将它们上游化;
  5. 使用 BIRD 作为 BGP 代理,而不是建议的 kube-router,我们已经为 Cilium 文档贡献了 BGP+Cilium 指南;
  6. 我们开发了一种新的多集群解决方案,称为 KVStoreMesh [4]。更多关于这个 lader 的信息。

2.3 优化和调整

现在是优化和调整部分。

2.3.1 解耦安装

刚才说的,我们做的第一件事就是解耦 Cilium 从 Kubernetes 部署/安装:没有 daemonset,没有 configmap。所有 代理所需的配置位于节点上。

这使得代理受 Kubernetes 中断的影响较小,但更重要的是,每个代理现在在配置和升级方面都是完全独立的

2.3.2 避免重试/重启风暴

第二个考虑因素是避免重试风暴和突发启动, 因为请求将激增两个数量级甚至更高 当发生中断时,这很容易崩溃或卡住中央组件 如 Kubernetes apiserver/etcd 和 kvstore 一样。

我们使用内部开发的重启回退 (jitter+backoff) 机制来避免此类情况。 抖动窗口是根据 Cluster Scale 计算的。 如

  • 对于具有 1000 个节点的集群,抖动窗口可能是 20 分钟,在此期间,每个代理只能启动一次,然后退出。
  • 对于具有 5000 个节点的集群,抖动窗口可能为 60 分钟。
  • 退避机制作为 bash 脚本实现 (所有状态都保存在本地文件中),使用 在 docker-compose 中作为 "pre-start hook" 时,Cilium 代码没有变化

此外,我们还为每个代理分配了一个不同的证书(每个代理都有一个 专用用户名,但属于公共用户组),这将启用 Kubernetes 使用 APF(API 优先级和公平性)对 Cilium 代理执行速率限制。也没有更改 Cilium 代码来实现这一点。

如果您想了解有关 Kubernetes AuthN/AuthZ 模型的更多信息,请参阅我们之前的博客 [2,3]。

2.3.3 稳定性优先

Trip.com 7x24 小时在全球范围内提供在线预订服务,因此随时 在任何一天,业务服务中断都会导致 公司。因此,我们不能冒险让网络等基础服务通过简单的 "快速故障" 规则自行重启,而倾向于必要的人工干预和决策。

当失败出现时,我们希望像 Cilium 这样的服务能更有耐心,只是 在那里等待并保持当前业务不中断,让系统开发人员和 维护者决定做什么;快速失败和自动重试 在这种情况下,让事情变得更糟

一些特定选项(带有示例配置)来调整此行为:

  • --allocator-list-timeout=3h
  • --kvstore-lease-ttl=86400s
  • --k8s-syn-timeout=600s
  • --k8s-heartbeat-timeout=60s

请参阅 Cilium 文档或源代码以找出每个选项的内容 确切的含义,并根据您的需要自定义它们。

2.3.4 规划规模

根据您的集群规模,某些内容需要提前规划。 例如,身份相关标签 () 直接确定 集群中的最大 pod :一组标签映射到 在 Cilium 中只有一个身份,所以在它的设计中,所有具有相同标签的 Pod 都共享相同的身份。 但是,如果你的 Bean 太细粒度(不幸的是,这是默认的 case),这可能会导致每个 Pod 都有不同的身份,在最坏的情况下,你的集群规模为 上限为 64K pod,因为表示身份 替换为整数。有关更多信息,请参阅 [8]。--labels``--labels=<labels>``16bit

此外,还有一些参数需要根据 您的工作负载吞吐量,例如 Identity Allocation Mode、Connection Tracking Table。

选项:

  • --cluster-id/--cluster-name:避免多集群场景中的身份冲突;

  • --labels=<labellist>Identity Relevent 标签

  • --identity-allocation-mode和 kvstore 基准测试(如果使用 kvstore 模式)

    我们使用模式,并在大型集群的专用刀片服务器上运行 kvstore (cilium etcd)。 kvstore

  • --bpf-ct-*

  • --api-rate-limit

  • 用于减少可观测性数据量的 Monitor 聚合选项

2.3.5 性能调优

Cilium 包含许多高性能选项,例如 sockops 和 BPF 主机 routing,当然,所有这些功能都需要特定的内核版本 支持。

  • --socops-enable
  • --bpf-lb-sock-hostns-only
  • ...

此外,禁用一些调试级别选项也是必要的:

  • --disable-cnp-status-updates
  • ...

2.3.6 可观察性和警报

我们要讨论的最后一个方面是可观测性。

  • 度量
  • 伐木
  • 描图

除了来自 Cilium agent/operator 的指标数据 外,我们还 还收集了所有代理/操作员日志(日志记录数据)并发送 到 ClickHouse 进行分析,这样,我们就可以对异常指标进行告警,以及 错误/警告日志、

此外,跟踪也很有帮助,稍后会详细介绍。

2.3.7 其他选项

  • --enable-hubble
  • --keep-config
  • --log-drivers
  • --policy-audit-mode

2.4 多集群解决方案

现在我们来看一下多集群问题。

由于历史原因,我们的业务部署在不同的 数据中心和 Kubernetes 集群。 因此,存在没有 L4/L7 边界网关的集群间通信。 这对访问控制来说是一个问题,因为 Cilium 身份是一个集群范围的对象

2.4.1 集群网格

这个问题的社区解决方案是 ClusterMesh,如下所示,

ClusterMesh 要求每个 agent 连接到所有集群中的每个 kvstore, 有效地产生点对点网格。虽然这个解决方案是直接的 向前,它遇到了稳定性和可扩展性问题,尤其是对于大型 集群。

简而言之,当单个集群宕机时,故障很快就会传播到所有集群 网格中的其他集群, 最终,所有集群可能会同时崩溃,如下所示:

从本质上讲,这是因为 ClusterMesh 中的集群耦合得太紧密了。

2.4.2 KVStoreMesh

我们解决这个问题的概念非常简单: 从所有远程 KVSache 中提取元数据,并在筛选后推送到本地 KVSares。

三集群案例更清楚地显示了这个概念:只涉及 kvstores,

在 ClusterMesh 中,代理从远程 kvstores 获取远程元数据;在 KVStoreMesh 中,它们从本地获取。

感谢 cilium 的良好设计,这只需要对代理和操作符 [4] 进行一些改进和/或错误修复 ,我们已经 他们中的一些人被上游。kvstoremesh-operator 是新引入的,目前在内部维护; 我们也会在下一个版本投入更多精力将其上游化。

此外,我们还开发了一个简单的解决方案,让 Cilium 注意我们的遗留工作负载,例如 OpenStack 中的虚拟机, the-solultion 称为 CiliumExeternalResource。请看我们之前的 博客 [8] 如果你感兴趣的话。

3 高级故障排除技巧

现在让我们回到一些方便的东西。

第一个是调试。

3.1 使用delve/dlv

Delve 是一个好朋友,我们的 docker-compose 方式使调试更加容易。 由于每个代理程序都是独立部署的,因此命令可以 在节点上执行以启动/停止/重新配置代理。

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em># Start cilium-agent agent container with entrypoint `sleep 10d`, then enter the container</em></span>
<span style="color:#000000"><strong>(</strong></span>node<span style="color:#000000"><strong>)</strong></span> <span style="color:#008080">$ </span>docker <span style="color:#0086b3">exec</span> <span style="color:#000080">-it</span> cilium-agent bash

<span style="color:#000000"><strong>(</strong></span>cilium-agent ctn<span style="color:#000000"><strong>)</strong></span> <span style="color:#008080">$ </span>dlv <span style="color:#0086b3">exec</span> /usr/bin/cilium-agent <span style="color:#000080">--</span> <span style="color:#000080">--config-dir</span><span style="color:#000000"><strong>=</strong></span>/tmp/cilium/config-map
Type <span style="color:#dd1144">'help'</span> <span style="color:#000000"><strong>for </strong></span>list of commands.
<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span>

<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span> <span style="color:#0086b3">break </span>github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.regenerateBPF
Breakpoint 3 <span style="color:#0086b3">set </span>at 0x1e84a3b <span style="color:#000000"><strong>for </strong></span>github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.regenerateBPF<span style="color:#000000"><strong>()</strong></span> /go/src/github.com/cilium/cilium/pkg/endpoint/bpf.go:591
<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span> <span style="color:#0086b3">break </span>github.com/cilium/cilium/pkg/endpoint/bpf.go:1387
Breakpoint 4 <span style="color:#0086b3">set </span>at 0x1e8c27b <span style="color:#000000"><strong>for </strong></span>github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.syncPolicyMapWithDump<span style="color:#000000"><strong>()</strong></span> /go/src/github.com/cilium/cilium/pkg/endpoint/bpf.go:1387
<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span> <span style="color:#000000"><strong>continue</strong></span>
...

<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span> clear 1
Breakpoint 1 cleared at 0x1e84a3b <span style="color:#000000"><strong>for </strong></span>github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.regenerateBPF<span style="color:#000000"><strong>()</strong></span> /go/src/github.com/cilium/cilium/pkg/endpoint/bpf.go:591
<span style="color:#000000"><strong>(</strong></span>dlv<span style="color:#000000"><strong>)</strong></span> clear 2
Breakpoint 2 cleared at 0x1e8c27b <span style="color:#000000"><strong>for </strong></span>github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.syncPolicyMapWithDump<span style="color:#000000"><strong>()</strong></span> /go/src/github.com/cilium/cilium/pkg/endpoint/bpf.go:1387
</code></span></span></span>

我们以这种方式跟踪了几个 bug。

3.2 使用bpftrace

另一个有用的工具是用于实时跟踪的 bpftrace。

但请注意,跟踪容器进程存在一些差异。 您需要在节点上找到 cilium-agent 二进制文件的 PID 命名空间或绝对路径。

3.2.1 使用绝对路径

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em># Check cilium-agent container</em></span>
<span style="color:#008080">$ </span>docker ps | <span style="color:#0086b3">grep </span>cilium-agent
0eb2e76384b3        cilium:20220516   <span style="color:#dd1144">"/usr/bin/cilium-agent ..."</span>   4 hours ago    Up 4 hours   cilium-agent

<span style="color:#999988"><em># Find the merged path for cilium-agent container</em></span>
<span style="color:#008080">$ </span>docker inspect <span style="color:#000080">--format</span> <span style="color:#dd1144">"{{.GraphDriver.Data.MergedDir}}"</span> 0eb2e76384b3
/var/lib/docker/overlay2/0a26c6/merged <span style="color:#999988"><em># 0a26c6.. is shortened for better viewing</em></span>
<span style="color:#999988"><em># The object file we are going to trace</em></span>
<span style="color:#008080">$ </span><span style="color:#0086b3">ls</span> <span style="color:#000080">-ahl</span> /var/lib/docker/overlay2/0a26c6/merged/usr/bin/cilium-agent
/var/lib/docker/overlay2/0a26c6/merged/usr/bin/cilium-agent <span style="color:#999988"><em># absolute path</em></span>

<span style="color:#999988"><em># Or you can find it bruteforcelly if there are no performance (e.g. IO spikes) concerns:</em></span>
<span style="color:#008080">$ </span>find /var/lib/docker/overlay2/ <span style="color:#000080">-name</span> cilium-agent
/var/lib/docker/overlay2/0a26c6/merged/usr/bin/cilium-agent <span style="color:#999988"><em># absolute path</em></span>
</code></span></span></span>

无论如何,在找到目标文件并检出其中的符号后,

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>nm /var/lib/docker/overlay2/0a26c6/merged/usr/bin/cilium-agent
0000000001d3e940 T type..hash.github.com/cilium/cilium/pkg/k8s.ServiceID
0000000001f32300 T type..hash.github.com/cilium/cilium/pkg/node/types.Identity
0000000001d05620 T type..hash.github.com/cilium/cilium/pkg/policy/api.FQDNSelector
0000000001d05e80 T type..hash.github.com/cilium/cilium/pkg/policy.PortProto
...
</code></span></span></span>

您可以像下面这样启动用户空间探测,打印您希望看到的内容:

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>bpftrace <span style="color:#000080">-e</span> <span style="color:#dd1144">\</span>
  <span style="color:#dd1144">'uprobe:/var/lib/docker/overlay2/0a26c6/merged/usr/bin/cilium-agent:"github.com/cilium/cilium/pkg/endpoint.(*Endpoint).regenerateBPF" {printf("%s\n", ustack);}'</span>
Attaching 1 probe...

        github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Endpoint<span style="color:#000000"><strong>)</strong></span>.regenerateBPF+0
        github.com/cilium/cilium/pkg/endpoint.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>EndpointRegenerationEvent<span style="color:#000000"><strong>)</strong></span>.Handle+1180
        github.com/cilium/cilium/pkg/eventqueue.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>EventQueue<span style="color:#000000"><strong>)</strong></span>.run.func1+363
        sync.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>Once<span style="color:#000000"><strong>)</strong></span>.doSlow+236
        github.com/cilium/cilium/pkg/eventqueue.<span style="color:#000000"><strong>(</strong></span><span style="color:#000000"><strong>*</strong></span>EventQueue<span style="color:#000000"><strong>)</strong></span>.run+101
        runtime.goexit+1
</code></span></span></span>

2.3.2 带 PID/proc/<PID>

更方便、更简洁的方法是找到 PID 命名空间并将其传递给 ,这将使命令更短:bpftrace

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span><span style="color:#0086b3">sudo </span>docker inspect <span style="color:#000080">-f</span> <span style="color:#dd1144">'{{.State.Pid}}'</span> cilium-agent
109997
<span style="color:#008080">$ </span>bpftrace <span style="color:#000080">-e</span> <span style="color:#dd1144">'uprobe:/proc/109997/root/usr/bin/cilium-agent:"github.com/cilium/cilium/pkg/endpoint.(*Endpoint).regenerate" {printf("%s\n", ustack); }'</span>
</code></span></span></span>

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>bpftrace <span style="color:#000080">-p</span> 109997 <span style="color:#000080">-e</span> <span style="color:#dd1144">'uprobe:/usr/bin/cilium-agent:"github.com/cilium/cilium/pkg/endpoint.(*Endpoint).regenerate" {printf("%s\n", ustack); }'</span>
</code></span></span></span>

3.3 操作 BPF 映射bpftool

现在考虑一个具体问题:**如何确定 CNP 是否真的生效?**有几种方法:

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>kubectl get cnp <span style="color:#000080">-n</span> <ns> <cnp> <span style="color:#000080">-o</span> yaml       <span style="color:#999988"><em># spec & status in k8s</em></span>
<span style="color:#008080">$ </span>cilium endpoint get <ep <span style="color:#0086b3">id</span><span style="color:#000000"><strong>></strong></span>                 <span style="color:#999988"><em># spec & status in cilium userspace</em></span>
<span style="color:#008080">$ </span>cilium bpf policy get <ep <span style="color:#0086b3">id</span><span style="color:#000000"><strong>></strong></span>               <span style="color:#999988"><em># summary of kernel bpf policy status</em></span>
</code></span></span></span>
  • 查询 Kubernetes?不,这太高了;
  • 查看终端节点状态?不,这是一个用户空间状态,仍然太高级别了;
  • 使用 cilium 命令检查 bpf 策略?嗯,这确实是一个总结 的 BPF 策略,但摘要代码本身也可能有 bug;

最底层的策略状态是内核中的 BPF 策略映射,我们可以通过 bpftool 查看它:

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>bpftool map dump pinned cilium_policy_00794 <span style="color:#999988"><em># REAL & ULTIMATE policies in the kernel!</em></span>
</code></span></span></span>

但是要使用此工具,您首先需要熟悉一些 Cilium 数据结构。 比如,IP 地址如何对应一个身份,以及如何组合 身份、端口、协议、流量方向在 BPF 策略映射中形成一个键。

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em># Get the corresponding identity of an (client) IP address</em></span>
<span style="color:#008080">$ </span>cilium bpf ipcache get 10.2.6.113
10.2.6.113 maps to identity 298951 0 0.0.0.0

<span style="color:#999988"><em># Convert a numeric identity to its hex representation</em></span>
<span style="color:#008080">$ </span><span style="color:#0086b3">printf</span> <span style="color:#dd1144">'%08x'</span> 298951
00048fc7

<span style="color:#999988"><em># Search if there exists any policy related to this identity</em></span>
<span style="color:#999988"><em>#</em></span>
<span style="color:#999988"><em># Key format: identity(4B) + port(2B) + proto(1B) + direction(1B)</em></span>
<span style="color:#999988"><em># For endpoint 794's TCP/80 ingress, check if allow traffic from identity 298951</em></span>
<span style="color:#008080">$ </span>bpftool map dump pinned cilium_policy_00794 | <span style="color:#0086b3">grep</span> <span style="color:#dd1144">"c7 8f 04 00"</span> <span style="color:#000080">-B</span> 1 <span style="color:#000080">-A</span> 3
key:
c7 8f 04 00 00 50 06 00 <span style="color:#999988"><em># 4B identity + 2B port(80) + 1B L4Proto(TCP) + direction(ingress)</em></span>
value:
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
</code></span></span></span>

键和值数据结构:

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em>// PolicyKey represents a key in the BPF policy map for an endpoint. It must</em></span>
<span style="color:#999988"><em>// match the layout of policy_key in bpf/lib/common.h.</em></span>
<span style="color:#999988"><em>// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey</em></span>
<span style="color:#000000"><strong>type</strong></span> PolicyKey <span style="color:#000000"><strong>struct</strong></span> {
	Identity         <span style="color:#445588"><strong>uint32</strong></span> <span style="color:#dd1144">`align:"sec_label"`</span>
	DestPort         <span style="color:#445588"><strong>uint16</strong></span> <span style="color:#dd1144">`align:"dport"`</span> <span style="color:#999988"><em>// In network byte-order</em></span>
	Nexthdr          <span style="color:#445588"><strong>uint8</strong></span>  <span style="color:#dd1144">`align:"protocol"`</span>
	TrafficDirection <span style="color:#445588"><strong>uint8</strong></span>  <span style="color:#dd1144">`align:"egress"`</span>
}

<span style="color:#999988"><em>// PolicyEntry represents an entry in the BPF policy map for an endpoint. It must</em></span>
<span style="color:#999988"><em>// match the layout of policy_entry in bpf/lib/common.h.</em></span>
<span style="color:#999988"><em>// +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue</em></span>
<span style="color:#000000"><strong>type</strong></span> PolicyEntry <span style="color:#000000"><strong>struct</strong></span> {
	ProxyPort <span style="color:#445588"><strong>uint16</strong></span> <span style="color:#dd1144">`align:"proxy_port"`</span> <span style="color:#999988"><em>// In network byte-order</em></span>
	Flags     <span style="color:#445588"><strong>uint8</strong></span>  <span style="color:#dd1144">`align:"deny"`</span>
	Pad0      <span style="color:#445588"><strong>uint8</strong></span>  <span style="color:#dd1144">`align:"pad0"`</span>
	Pad1      <span style="color:#445588"><strong>uint16</strong></span> <span style="color:#dd1144">`align:"pad1"`</span>
	Pad2      <span style="color:#445588"><strong>uint16</strong></span> <span style="color:#dd1144">`align:"pad2"`</span>
	Packets   <span style="color:#445588"><strong>uint64</strong></span> <span style="color:#dd1144">`align:"packets"`</span>
	Bytes     <span style="color:#445588"><strong>uint64</strong></span> <span style="color:#dd1144">`align:"bytes"`</span>
}

<span style="color:#999988"><em>// pkg/maps/policymap/policymap.go</em></span>

<span style="color:#999988"><em>// Allow pushes an entry into the PolicyMap to allow traffic in the given</em></span>
<span style="color:#999988"><em>// `trafficDirection` for identity `id` with destination port `dport` over</em></span>
<span style="color:#999988"><em>// protocol `proto`. It is assumed that `dport` and `proxyPort` are in host byte-order.</em></span>
<span style="color:#000000"><strong>func</strong></span> (pm <span style="color:#000000"><strong>*</strong></span>PolicyMap) Allow(id <span style="color:#445588"><strong>uint32</strong></span>, dport <span style="color:#445588"><strong>uint16</strong></span>, proto u8proto<span style="color:#000000"><strong>.</strong></span>U8proto, trafficDirection trafficdirection<span style="color:#000000"><strong>.</strong></span>TrafficDirection, proxyPort <span style="color:#445588"><strong>uint16</strong></span>) <span style="color:#445588"><strong>error</strong></span> {
	key <span style="color:#000000"><strong>:=</strong></span> newKey(id, dport, proto, trafficDirection)
	pef <span style="color:#000000"><strong>:=</strong></span> NewPolicyEntryFlag(<span style="color:#000000"><strong>&</strong></span>PolicyEntryFlagParam{})
	entry <span style="color:#000000"><strong>:=</strong></span> newEntry(proxyPort, pef)
	<span style="color:#000000"><strong>return</strong></span> pm<span style="color:#000000"><strong>.</strong></span>Update(<span style="color:#000000"><strong>&</strong></span>key, <span style="color:#000000"><strong>&</strong></span>entry)
}
</code></span></span></span>

bpftool在紧急情况下也会来救援,例如当 流量被拒绝,但您的 Kubernetes 或 Cilium 代理无法准备就绪, 只需插入一个 allow-any 规则,如下所示:

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#999988"><em># Add an allow-any rule in emergency cases</em></span>
<span style="color:#008080">$ </span>bpftool map update pinned <map> <span style="color:#dd1144">\</span>
  key hex 00 00 00 00 00 00 00 00 <span style="color:#dd1144">\</span>
  value hex 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 noexist
</code></span></span></span>

3.4 使用 API 操作 kvstore 内容etcdctl

我们要分享的最后一个技能是操作 kvstore 内容。

同样,这需要对 Cilium 数据模型有深入的了解。 例如,将以下三个条目插入 kvstore 中,

highlight 复制代码
<span style="color:#333333"><span style="background-color:#f8f8f8"><span style="background-color:#f6f8fa"><code><span style="color:#008080">$ </span>etcdctl put <span style="color:#dd1144">"cilium/state/identities/v1/id/15614229"</span> <span style="color:#dd1144">\</span>
  <span style="color:#dd1144">'k8s:app=app1;k8s:io.cilium.k8s.policy.cluster=cluster1;k8s:io.cilium.k8s.policy.serviceaccount=default;k8s:io.kubernetes.pod.namespace=ns1;'</span>

<span style="color:#008080">$ </span>etcdctl put <span style="color:#dd1144">'k8s:app=app1;k8s:io.cilium.k8s.policy.cluster=cluster1;k8s:io.cilium.k8s.policy.serviceaccount=default;k8s:io.kubernetes.pod.namespace=ns1;/10.3.9.10'</span> <span style="color:#dd1144">\</span>
  15614229

<span style="color:#008080">$ </span>etcdctl put <span style="color:#dd1144">"cilium/state/ip/v1/cluster1/10.3.192.65"</span> <span style="color:#dd1144">\</span>
  <span style="color:#dd1144">'{"IP":"10.3.192.65","Mask":null,"HostIP":"10.3.9.10","ID":15614299,"Key":0,"Metadata":"cilium-global:cluster1:node1:2404","K8sNamespace":"ns1","K8sPodName":"pod1"}'</span>
</code></span></span></span>

所有 cilium-agents 都会收到通知,在 Kubernetes 、 namespace 中创建了一个 pod ,其中包含 PoIP、NodeIP、NodeName、pod 标签和 条目中的身份信息。cluster1``default

从本质上讲,这就是我们在 CER 解决方案中将 VM、BM 和非纤毛 pod 注入 Cilium 世界的方式(有关详细信息,请参阅我们之前的帖子 [8]); 它也是 Cilium 网络策略的基础。

警告:操纵 kvstores 和 BPF 映射是危险的, 因此,我们不建议在生产环境中执行这些操作 环境中,除非您知道自己在做什么。

4 总结

我们从 1.4 开始一直在使用 Cilium,现在已经一路升级到 1.10(2022.11 更新)。 它支持我们的业务和基础设施关键服务。 凭借 4 年的经验,我们相信它不仅为大规模生产做好了准备, 而且在性能、功能、社区等方面也是最佳候选人之一。1.11

最后,我想特别感谢 Andre、Denial、Joe、Martynas、Paul、Quentin、Thomas 以及所有 Cilium 的家伙。社区非常好,过去帮了我们很多。

相关推荐
哈里谢顿7 小时前
Kubernetes Operator核心概念、实现原理和实战开发
云原生
阿里云云原生12 小时前
你的 OpenClaw 真的在受控运行吗?
云原生
用户9623779544812 小时前
DVWA 靶场实验报告 (High Level)
安全
阿里云云原生12 小时前
5 分钟零代码改造,让 Go 应用自动获得全链路可观测能力
云原生·go
Shanyoufusu1213 小时前
RKE2 单节点集群安装 Rancher+ 私有镜像仓库搭建 完整教程
云原生
阿里云云原生13 小时前
Dify 官方上架 Higress 插件,轻松接入 AI 网关访问模型服务
云原生
数据智能老司机15 小时前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机15 小时前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
AI攻城狮15 小时前
OpenClaw Session 管理完全指南:Context 压缩、重置与持久化
人工智能·云原生·aigc
用户9623779544817 小时前
DVWA 靶场实验报告 (Medium Level)
安全