共计 7047 个字符,预计需要花费 18 分钟才能阅读完成。
这篇之前写 Kubernetes 网络学习之 Cilium 与 eBPF 记录的内容,隔了几个月终于想起把笔记实现,作为摸索 Cilium 工作原理的入门,也还是 Cilium 冰山一角,像是高级的网络策略、网络加密、BGP 网络、服务网格等方面并没有深刻。如果浏览过程中有发现任何问题,也烦请纠正。
本文基于 Cilium v1.12 及 Kubernetes v1.25。
试验环境
咱们应用 k8e 创立集群,因为 k8e 应用 Cilium 作为默认的 CNI 实现。在我的 homelab 上做个双节点(ubuntu-test1: 192.168.1.21
、ubuntu-test2: 192.168.1.22
)的集群。
Master 节点
curl -sfL https://getk8e.com/install.sh | API_SERVER_IP=192.168.1.21 K8E_TOKEN=ilovek8e INSTALL_K8E_EXEC="server --cluster-init --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config" sh -
工作节点
curl -sfL https://getk8e.com/install.sh | K8E_TOKEN=ilovek8e K8E_URL=https://192.168.1.21:6443 sh -
部署示例利用,通过批改 nodeName 将两个 pod 别离调度两个节点上。
NODE1=ubuntu-test1
NODE2=ubuntu-test2
kubectl apply -n default -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: curl
name: curl
spec:
containers:
- image: curlimages/curl
name: curl
command: ["sleep", "365d"]
nodeName: $NODE1
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: httpbin
name: httpbin
spec:
containers:
- image: kennethreitz/httpbin
name: httpbin
nodeName: $NODE2
EOF
Cilium 组件
Agent
cilium-agent
运行在集群的各个节点上(上图的 Cilium Daemon)。接管来自 Kubernetes 或者 Cilium API 的形容网络、服务负载平衡、网络策略以及可见性和监控需要的配置。
Agent 监控如 Kubernetes 等编排零碎中容器或者负载的生命周期变动,治理着用来管制进出容器的网络拜访的 eBPF 程序;对外(CNI Plugin、CLI)提供 API 来操作配置、Endpoint、Node、Policy、Service、IP 地址等资源。
API 蕴含如下几个模块:
- daemon
- endpoint
- ipam
- metrics
- policy
- prefilter
- recorder
- service
CLI
Cilium CLI 客户端,与 cilium-agent 一起装置。通过 Cilium REST API 与同节点上的本地 agent 进行交互。通过 CLI 能够查看本地 agent 的状态,也能够间接拜访 eBPF map 的内容以便随时验证状态。
cilium
CLI for interacting with the local Cilium Agent
Usage:
cilium [command]
Available Commands:
bpf Direct access to local BPF maps
cleanup Remove system state installed by Cilium at runtime
completion Output shell completion code
config Cilium configuration options
debuginfo Request available debugging information from agent
encrypt Manage transparent encryption
endpoint Manage endpoints
fqdn Manage fqdn proxy
help Help about any command
identity Manage security identities
ip Manage IP addresses and associated information
kvstore Direct access to the kvstore
lrp Manage local redirect policies
map Access userspace cached content of BPF maps
metrics Access metric status
monitor Display BPF program events
node Manage cluster nodes
policy Manage security policies
prefilter Manage XDP CIDR filters
preflight cilium upgrade helper
recorder Introspect or mangle pcap recorder
service Manage services & loadbalancers
status Display status of daemon
version Print version information
Flags:
--config string config file (default is $HOME/.cilium.yaml)
-D, --debug Enable debug messages
-h, --help help for cilium
-H, --host string URI to server-side API
Use "cilium [command] --help" for more information about a command.
Operator
Cilium Operator 负责管理集群中的职责,逻辑上应该为整个集群解决一次,而不是为集群中的每个节点解决一次。Operator 不参加任何转发或者网络策略的决策。即便 Operator 短暂不可用,集群通常会持续运行,除了某些操作可能会失败。
Operator 容许多实例运行,但由 leader 实例实现特定操作,比方 Node CIDR 的调配。
CNI Plugin
Cilium 的 CNI 实现,当 pod 调度到某个节点后,该节点的容器运行时会调用 Cilium CNI 实现一系列的网络配置。CNI Plugin 会与 Agent 组件通过 REST API 进行交互,比方调用 API 调配 IP 地址、创立 Endpoint 等。
对这部分有趣味的能够看下之前的文章《Kubernetes 网络学习之 Cilium 与 eBPF》。
IPAM
Cilium 管理网络 Endpoint,Endpoint 应用的 IP 地址,由 IPAM 调配和治理。
反对 多种 IPAM 模型,默认应用 Cluster Scope cluster-pool
,通过 cilium-config
中的字段 ipam
来设置。
cluster-scope
IPAM 模型为各个集群 node 调配 PodCIDRs,而后在各个 node 上应用 host-scope 分配器调配 IP 地址。
这个 PodCIDRs 的调配与 Flannel 中的 PodCIDRs 调配 的不同:后者应用 v1.Node
上由 Kubernetes 调配的 podCIDR
,这个与 Cilium 的 Kubernetes Host Scope 相似;而 Cilium 的 cluster-scope
应用的 PodCIDRs 则是由 Cilium operator 来调配和治理的,operator 将调配的 PodCIDR 附加在 v2.CiliumNode
上。
Agent 启动后,从 v2.CiliumNode
上获取 podCIDRs
,而后在 CNI 插件调用时为 pod 调配 IP 地址。
eBPF
eBPF 是一种 Linux 内核字节码解释器,最后用于过滤网络数据包,例如 tcpdump 和套接字过滤器。尔后,它扩大了额定的数据结构,如哈希表和数组,以及反对数据包解决、转发、封装等的其余操作。
Cilium 利用 eBPF 执行外围数据门路过滤、解决、监控和重定向,并须要任何 Linux 内核版本 4.8.0 或更高版本的 eBPF 性能。
Linux 内核始终是实现监控 / 可观测性、网络和平安性能的现实中央。不过很多状况下这并非易事,因为这些工作须要批改内核源码或加载内核模块,最终实现模式是在已有的层层形象之上叠加新的形象。eBPF 是一项革命性技术,它能在内核中运行沙箱程序(sandbox programs),而无需批改内核源码或者加载内核模块。
将 Linux 内核变成可编程之后,就能基于现有的(而非减少新的)形象层来打造更加智能、性能更加丰盛的基础设施软件,而不会减少零碎的复杂度,也不会就义执行效率和安全性。
概念
标签 Label
标签是解决大量资源的通用、灵便且高度可扩大的形式,在 Kubernetes 中与 标签选择器 一起被广泛应用。简略来说,一个标签就是一个 key
和 value
的组合:key=value
(应用时也可不提供 value
)。
在 Cilium 中标签有些许不同:每个标签都有个前缀 :
,这个 source
示意该标签是衍生自哪里。创立 Pod 时,衍生来的标签会带有 k8s:
前缀,如 k8s:io.kubernetes.pod.namespace=default
;而应用 docker run [...] -l foo=bar
运行的容器,则带有标签 container:foo=bar
。
除了方才提到的 k8s:
和 container:
,还有两种 reserved:
和 unspec:
。前者示意是 Cilium 的保留标签,后者则示意没有指定起源。
端点 Endpoint
Cilium 通过为容器调配 IP 地址使其在网络上可用。多个容器能够共享同一个 IP 地址,就像一个 Kubernetes Pod 中能够有多个容器,这些容器之间共享网络命名空间,应用同一个 IP 地址。这些共享同一个地址的容器,Cilium 将其组合起来,成为 Endpoint(端点)。
留神,这个 Endpoint 与 Kubernetes 原生资源 v1.Endpoints
相似但却不同,Cilium 为其提供了 CRD CiliumEndpoint
。本文中提到 Endpoint 除非特地阐明,都是指 CiliumEndpoint
。
kubectl get CiliumEndpoint -n default
NAME ENDPOINT ID IDENTITY ID INGRESS ENFORCEMENT EGRESS ENFORCEMENT VISIBILITY POLICY ENDPOINT STATE IPV4 IPV6
curl 2580 1979 <status disabled> <status disabled> <status disabled> ready 10.42.0.171
httpbin 205 20965 <status disabled> <status disabled> <status disabled> ready 10.42.1.205
能够看到咱们部署的示例利用对应的 Endpoint 信息,进一步查看 Endpoint curl
的详细信息:
apiVersion: cilium.io/v2
kind: CiliumEndpoint
metadata:
creationTimestamp: "2023-05-20T05:15:24Z"
generation: 1
labels:
app: curl
name: curl
namespace: default
ownerReferences:
- apiVersion: v1
kind: Pod
name: curl
uid: d34675ea-8f4d-4bad-a1c4-02d183380846
resourceVersion: "1197"
uid: c4d7cdb5-c3a8-4ff8-bf03-d6623a0ec00a
status:
encryption: {}
external-identifiers:
container-id: 60dbc4edc0e5bf70b5290feea448559693b7fb51f7b1c3cf996b310c6cd8a576
k8s-namespace: default
k8s-pod-name: curl
pod-name: default/curl
id: 2580
identity:
id: 1979
labels:
- k8s:app=curl
- k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
- k8s:io.cilium.k8s.policy.cluster=default
- k8s:io.cilium.k8s.policy.serviceaccount=default
- k8s:io.kubernetes.pod.namespace=default
networking:
addressing:
- ipv4: 10.42.0.171
node: 192.168.1.21
policy:
egress:
enforcing: false
state: <status disabled>
ingress:
enforcing: false
state: <status disabled>
state: ready
visibility-policy-status: <status disabled>
Endpoint 大部分信息都集中在 status
局部。 为了分别 Endpoint,每个 Endpoint 都有一个在 Node 节点范畴上惟一的 ID。 比方应用 Endpoint curl 的 ID 2580,在所在节点的 agent 中执行 cilium endpoint get 2580
同样能够失去与 status
局部雷同的信息。
除此以外每个 Endpoint 还有一个 Identity(身份),身份是用于执行在 Endpoint 之间执行根本连贯的信息,在集群范畴内惟一。身份中蕴含了标签信息,这些标签信息是创立 Endpoint 时从 Pod 或者容器来的。
比方这里咱们创立 Pod curl
,容器运行时将 Pod 相干的信息作为执行 CNI ADD
操作的参数 CNI_ARGS
传递给 CNI 插件(这里是 Cilium CNI,对这部分有趣味的能够看下之前的文章《认识一下容器网络接口 CNI》)。Cilium CNI 将这些信息以及其余内容作为创立 Endpoint 的根据,传递给 cilium-agent 来创立 Endpoint。这些信息最终作为 identity.labels
存在。
节点 Node
Cilium 中节点是集群的成员,每个节点上都必须运行 cilium-agent。与 Endpoint 一样,Cilium 也提供了 CRD CiliumNode
,前面文中提到的节点,如非特指均是 Cilium 的 CiliumNode
。
kubectl get CiliumNode
NAME AGE
ubuntu-test1 14m
ubuntu-test2 13m
工作机制
上面只是简略概括了 Cilium 在几个场景下的工作原理,疏忽了大量的细节。
新节点退出
Cilium Agent 以 DaemonSet 的形式部署,运行在各个 Node 节点上。当有新的节点退出时,Operator 会监测到新的节点退出,为节点调配 Pod CIDR 并创立 CiliumNode
。
新的 Agent 实例调度到该节点上运行,接着为节点上的 CLI、CNI 等操作提供 API 的反对;加载根底 BPF 程序;初始化 BPF Map 等操作。
Pod 创立
当容器运行时通过 CNI 来创立 Pod 的网络命名空间,当执行到 CNI 插件时,CNI 插件会调用 Agent API 来调配 IP 地址、创立 CiliumEndpoint
,并在 Pod 的网络命名空间中加载必要的 BPF 程序。
网络策略
应用 Cilium 的 CiliumNetworkPolicy
能够灵便地定义利用的网络通信策略,例如容许或回绝特定的流量流入和流出利用。以此保障只有通过受权的流量能够拜访应用程序,提供细粒度的访问控制。
以《应用 Cilium 加强 Kubernetes 网络安全》中应用的策略为例。
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "L7 policy to restrict access to specific HTTP call"
endpointSelector:
matchLabels:
org: empire
class: deathstar
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "POST"
path: "/v1/request-landing"
Cilium Agent 中运行着大量的 watcher,其中一个就是 CiliumNetworkPolicy
watcher。当策略创立或者更新时,Agent 会对策略进行转换并将规定存储到 BPF Map 中。在网络通信时,BPF 程序会对网络流量进行查看并决定该当容许或者回绝拜访。
关注 ” 云原生指北 ” 公众号
(转载本站文章请注明作者和出处盛世浮生,请勿用于任何商业用途)