大家读完觉得有帮助记得关注和点赞!!!
目录
[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 的云原生网络和安全性,包括:
- 如何使用 CiliumNetworkPolicy 进行 L3/L4 访问控制,包括将安全模型扩展到 BM/VM 实例;
- 我们名为 KVStoreMesh 的新多集群解决方案作为 ClusterMesh 的替代方案,以及我们如何使其与社区兼容以便轻松升级;
- 大规模构建稳定性,例如管理控制平面和多集群中断,以及我们因此对 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 推出时间表
以下是我们推出流程的简单时间表:
- 我们从 2018 年开始研究云原生网络解决方案 [9],当然,Cilium 胜出;
- 我们的第一个纤毛节点于 2019 年投入生产 [10];
- 从那时起,我们的各种业务和基础设施服务开始透明地迁移到 Cilium。
2021 年,随着大多数在线业务已经在 Cilium 中, 我们启动了一个基于 Cilium 网络策略的安全项目 [8]。
我们使用的功能:
- 服务负载均衡 (eBPF/XDP)
- CiliumNetworkPolicy (CNP)
- eBPF 主机路由
- eBPF 带宽管理器
- 哈勃(部分)
- Rsyslog 驱动程序
- 性能提升选项,如 sockops、eBPF 重定向
- ...
2.2 自定义
首先,此处显示了两个 Kubernetes 集群,
我们基于上述拓扑的一些自定义:
- 使用 docker-compose 部署 cilium 以去除 kubernetes 依赖 [1];
- 为每个代理分配一个用于 Kubernetes 身份验证的专用证书,而不是所有代理共享的 seviceaccount;
- 我们已经帮助完善了 Cilium 的 rsyslog 驱动程序,并已将所有代理日志发送到 ClickHouse 进行故障排除;
- 添加了一些补丁来促进业务迁移,但这并不是那么通用,所以我们没有将它们上游化;
- 使用 BIRD 作为 BGP 代理,而不是建议的 kube-router,我们已经为 Cilium 文档贡献了 BGP+Cilium 指南;
- 我们开发了一种新的多集群解决方案,称为 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 的家伙。社区非常好,过去帮了我们很多。