> 扩展 kubernetes 分为三种模式 webhook,binary 二进制,controller
a group of entities that are uniquely addressable that can communicate amongst each other
, Containers 可以加到一个或者多个 network 里CNI 项目包括两个部分
AddNetworkList
, runtime 调用这个方法后,会按顺序执行对应 plugin 的 add 命令.AddNetworkList
,触发执行 cni pluginsnetwork name, CNI_CONTAINERID, CNI_IFNAME
)Container ID
, Network namespace path
, Network configuration
, Extra arguments
, Name of the interface inside the container
, 返回 Interfaces list
, IP configuration assigned to each interface
, DNS information
输出参数示例
{
"cniVersion": "0.4.0",
"interfaces": [ (this key omitted by IPAM plugins)
{
"name": "<name>",
"mac": "<MAC address>", (required if L2 addresses are meaningful)
"sandbox": "<netns path or hypervisor identifier>" (required for container/hypervisor interfaces, empty/omitted for host interfaces)
}
],
"ips": [
{
"version": "<4-or-6>",
"address": "<ip-and-prefix-in-CIDR>",
"gateway": "<ip-address-of-the-gateway>", (optional)
"interface": <numeric index into 'interfaces' list>
},
...
],
"routes": [ (optional)
{
"dst": "<ip-and-prefix-in-cidr>",
"gw": "<ip-of-next-hop>" (optional)
},
...
],
"dns": { (optional)
"nameservers": <list-of-nameservers> (optional)
"domain": <name-of-local-domain> (optional)
"search": <list-of-additional-search-domains> (optional)
"options": <list-of-options> (optional)
}
}
Network Configuration 是 CNI 输入参数中最重要当部分, 可以存储在磁盘上
Network Configuration 示例
// ------------------------------------
{
"cniVersion": "0.4.0",
"name": "dbnet",
"type": "bridge",
// type (plugin) specific
"bridge": "cni0",
"ipam": {
"type": "host-local",
// ipam specific
"subnet": "10.1.0.0/16",
"gateway": "10.1.0.1"
},
"dns": {
"nameservers": [ "10.1.0.1" ]
}
}
// ------------------------------------
{
"cniVersion": "0.4.0",
"name": "pci",
"type": "ovs",
// type (plugin) specific
"bridge": "ovs0",
"vxlanID": 42,
"ipam": {
"type": "dhcp",
"routes": [ { "dst": "10.3.0.0/16" }, { "dst": "10.4.0.0/16" } ]
},
// args may be ignored by plugins
"args": {
"labels" : {
"appVersion" : "1.0"
}
}
}
main
plugin{
"cniVersion": "0.4.0",
"ips": [
{
"version": "<4-or-6>",
"address": "<ip-and-prefix-in-CIDR>",
"gateway": "<ip-address-of-the-gateway>" (optional)
},
...
],
"routes": [ (optional)
{
"dst": "<ip-and-prefix-in-cidr>",
"gw": "<ip-of-next-hop>" (optional)
},
...
]
"dns": { (optional)
"nameservers": <list-of-nameservers> (optional)
"domain": <name-of-local-domain> (optional)
"search": <list-of-search-domains> (optional)
"options": <list-of-options> (optional)
}
}
plugins 项目中有几个 cni team 维护的常用 plugin, 并且进行了分类 (尽管 main plugin 可能会调用其他 plugin, 但是对于实现来讲,几种 plugin 的对外接口并无区别):
root@VM-4-10-ubuntu:/etc/cni/net.d/multus# cat bridge.conf
{
"cniVersion": "0.1.0",
"name": "bridge",
"type": "bridge",
"bridge": "cbr0",
"mtu": 1500,
"addIf": "eth0",
"isGateway": true,
"forceAddress": true,
"ipMasq": false,
"hairpinMode": false,
"promiscMode": true,
"ipam": {
"type": "host-local",
"subnet": "10.4.10.0/24",
"gateway": "10.4.10.1",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
node_ipam_controller
中完成, 原始分配的范围来自 ControllerManager
的配置; 即 常见的 IP 分配流程如下图:graph TD
ControllerManager配置subnet --> NodeSpec中生成子subnet
NodeSpec中生成子subnet --> CNIAgent在各个node上生成配置文件,写入子subnet
CNIAgent在各个node上生成配置文件,写入子subnet --> CNIplugin在子subnet中分配Ip
brige模式,即网桥模式。在node上创建一个linux bridge,并通过 vethpair 的方式在容器中设置网卡和 IP。只要为容器配置一个二层可达的网关:比如给网桥配置IP,并设置为容器ip的网关。容器的网络就能建立起来。
ADD 流程:
MTU
, PromiscMode
, Vlan
相比前面两种cni main组件,host-device显得十分简单因为他就只会做两件事情:
在bridge和ptp组件中,就已经有“将vethpair的一端移入到容器的网络namespace”的操作。那这个host-device不是多此一举吗?
并不是。host-device组件有其特定的使用场景。假设集群中的每个node上有多个网卡,其中一个网卡配置了node的IP。而其他网卡都是属于一个网络的,可以用来做容器的网络,我们只需要使用host-device,将其他网卡中的某一个丢到容器里面就行。
host-device模式的使用场景并不多。它的好处是:bridge、ptp 等方案中,node上所有容器的网络报文都是通过node上的一块网卡出入的,host-device方案中每个容器独占一个网卡,网络流量不会经过node的网络协议栈,隔离性更强。缺点是:在node上配置数十个网卡,可能并不好管理;另外由于不经过node上的协议栈,所以kube-proxy直接废掉。k8s集群内的负载均衡只能另寻他法了。
meta组件通常进行一些额外的网络配置(tuning),或者二次调用(flannel)
portmap 的主要作用是修改防火墙 iptables 规则, 配置 SNAT,DNAT 和端口转发
brctl addbr cni0;ip link set cni0 up; ip addr add <bridge-ip>/24 dev cni0
#!/bin/bash -e
if [[ ${DEBUG} -gt 0 ]]; then set -x; fi
exec 3>&1 # make stdout available as fd 3 for the result
exec &>> /var/log/bash-cni-plugin.log
IP_STORE=/tmp/reserved_ips # all reserved ips will be stored there
echo "CNI command: $CNI_COMMAND"
stdin=`cat /dev/stdin`
echo "stdin: $stdin"
# 分配 ip,从所有 ip 中选择没有 reserved 的, 同时更新到 store 的reserved ip 列表
allocate_ip(){
for ip in "${all_ips[@]}"
do
reserved=false
for reserved_ip in "${reserved_ips[@]}"
do
if [ "$ip" = "$reserved_ip" ]; then
reserved=true
break
fi
done
if [ "$reserved" = false ] ; then
echo "$ip" >> $IP_STORE
echo "$ip"
return
fi
done
}
# 实现 cni plugin 的4个命令
case $CNI_COMMAND in
ADD)
network=$(echo "$stdin" | jq -r ".network") # network 配置
subnet=$(echo "$stdin" | jq -r ".subnet") # 子网配置
subnet_mask_size=$(echo $subnet | awk -F "/" '{print $2}')
all_ips=$(nmap -sL $subnet | grep "Nmap scan report" | awk '{print $NF}') # 所有ip
all_ips=(${all_ips[@]})
skip_ip=${all_ips[0]}
gw_ip=${all_ips[1]}
reserved_ips=$(cat $IP_STORE 2> /dev/null || printf "$skip_ip\n$gw_ip\n") # reserving 10.244.0.0 and 10.244.0.1 预留 ip
reserved_ips=(${reserved_ips[@]})
printf '%s\n' "${reserved_ips[@]}" > $IP_STORE # 预留 ip 存储到文件
container_ip=$(allocate_ip)
# ---- 以上是 ip 分配流程
mkdir -p /var/run/netns/
ln -sfT $CNI_NETNS /var/run/netns/$CNI_CONTAINERID
rand=$(tr -dc 'A-F0-9' < /dev/urandom | head -c4)
host_if_name="veth$rand"
ip link add $CNI_IFNAME type veth peer name $host_if_name
ip link set $host_if_name up
ip link set $host_if_name master cni0
ip link set $CNI_IFNAME netns $CNI_CONTAINERID
ip netns exec $CNI_CONTAINERID ip link set $CNI_IFNAME up
ip netns exec $CNI_CONTAINERID ip addr add $container_ip/$subnet_mask_size dev $CNI_IFNAME
ip netns exec $CNI_CONTAINERID ip route add default via $gw_ip dev $CNI_IFNAME
# ------ 以上是创建 veth, 绑定到 网桥,设置 容器端的 ip, route 的过程
mac=$(ip netns exec $CNI_CONTAINERID ip link show eth0 | awk '/ether/ {print $2}')
echo "{
\"cniVersion\": \"0.3.1\",
\"interfaces\": [
{
\"name\": \"eth0\",
\"mac\": \"$mac\",
\"sandbox\": \"$CNI_NETNS\"
}
],
\"ips\": [
{
\"version\": \"4\",
\"address\": \"$container_ip/$subnet_mask_size\",
\"gateway\": \"$gw_ip\",
\"interface\": 0
}
]
}" >&3
;;
DEL)
ip=$(ip netns exec $CNI_CONTAINERID ip addr show eth0 | awk '/inet / {print $2}' | sed s%/.*%% || echo "")
if [ ! -z "$ip" ]
then
sed -i "/$ip/d" $IP_STORE
fi
;;
GET)
echo "GET not supported"
exit 1
;;
VERSION)
echo '{
"cniVersion": "0.3.1",
"supportedVersions": [ "0.3.0", "0.3.1", "0.4.0" ]
}' >&3
;;
*)
echo "Unknown cni commandn: $CNI_COMMAND"
exit 1
;;
esac
$ ip netns add testing
$ CNI_PATH=/opt/cni/bin/ CNI_IFNAME=test CNI_CONTAINERID=testing cnitool add mynet /var/run/netns/testing
{
"cniVersion": "0.3.1",
"interfaces": [
{
"name": "eth0",
"sandbox": "/var/run/netns/testing"
}
],
"ips": [
{
"version": "4",
"interface": 0,
"address": "10.244.149.16/24",
"gateway": "10.244.149.1"
}
],
"dns": {}
}
$ kubectl apply -f https://raw.githubusercontent.com/s-matyukevich/bash-cni-plugin/master/01_gcp/test-deployment.yml
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有