共计 6284 个字符,预计需要花费 16 分钟才能阅读完成。
今天丸趣 TV 小编给大家分享一下 kubernetes 的 CNI 怎么安装的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
环境介绍
我们安装 kubernetes 时先不安装 CNI. 如果使用了 sealyun 离线包 那么修改下 kube/conf/master.sh
只留如下内容即可:
[root@helix105 shell]# cat master.sh
kubeadm init --config ../conf/kubeadm.yaml
mkdir ~/.kube
cp /etc/kubernetes/admin.conf ~/.kube/config
kubectl taint nodes --all node-role.kubernetes.io/master-
清空 CNI 相关目录:
rm -rf /opt/cni/bin/*
rm -rf /etc/cni/net.d/*
启动 kubernetes, 如果已经装过那么 kubeadm reset 一下:
cd kube/shell sh init.sh sh master.sh
此时你的节点是 notready 的,你的 coredns 也没有办法分配到地址:
[root@helix105 shell]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-5c98db65d4-5fh7c 0/1 Pending 0 54s none none none none
coredns-5c98db65d4-dbwmq 0/1 Pending 0 54s none none none none
kube-controller-manager-helix105.hfa.chenqian 1/1 Running 0 19s 172.16.60.105 helix105.hfa.chenqian none none
kube-proxy-k74ld 1/1 Running 0 54s 172.16.60.105 helix105.hfa.chenqian none none
kube-scheduler-helix105.hfa.chenqian 1/1 Running 0 14s 172.16.60.105 helix105.hfa.chenqian none none
[root@helix105 shell]# kubectl get node
NAME STATUS ROLES AGE VERSION
helix105.hfa.chenqian NotReady master 86s v1.15.0
安装 CNI
创建 CNI 配置文件
$ mkdir -p /etc/cni/net.d
$ cat /etc/cni/net.d/10-mynet.conf EOF
cniVersion : 0.2.0 ,
name : mynet ,
type : bridge ,
bridge : cni0 ,
isGateway : true,
ipMasq : true,
ipam : {
type : host-local ,
subnet : 10.22.0.0/16 ,
routes : [{ dst : 0.0.0.0/0 }
$ cat /etc/cni/net.d/99-loopback.conf EOF
cniVersion : 0.2.0 ,
name : lo ,
type : loopback
EOF
这里两个配置一个是给容器塞一个网卡挂在网桥上的,另外一个配置负责撸 (本地回环)。。
配置完后会发现节点 ready:
[root@helix105 shell]# kubectl get node
NAME STATUS ROLES AGE VERSION
helix105.hfa.chenqian Ready master 15m v1.15.0
但是 coredns 会一直处于 ContainerCreating 状态, 是因为 bin 文件还没有:
failed to find plugin bridge in path [/opt/cni/bin]
plugins 里实现了很多的 CNI, 如我们上面配置的 bridge.
$ cd $GOPATH/src/github.com/containernetworking/plugins
$ ./build_linux.sh
$ cp bin/* /opt/cni/bin
$ ls bin/
bandwidth dhcp flannel host-local loopback portmap sbr tuning
bridge firewall host-device ipvlan macvlan ptp static vlan
这里有很多二进制,我们学习的话不需要关注所有的,就看 ptp(就简单的创建了设备对) 或者 bridge
再看 coredns 已经能分配到地址了:
[root@helix105 plugins]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-5c98db65d4-5fh7c 1/1 Running 0 3h20m 10.22.0.8 helix105.hfa.chenqian none none
coredns-5c98db65d4-dbwmq 1/1 Running 0 3h20m 10.22.0.9
看一下网桥,cni0 上挂了两个设备, 与我们上面的 cni 配置里配置的一样,type 字段指定用哪个 bin 文件,bridge 字段指定网桥名:
[root@helix105 plugins]# brctl show
bridge name bridge id STP enabled interfaces
cni0 8000.8ef6ac49c2f7 no veth2b28b06f
veth2c093940
原理
为了更好理解 kubelet 干嘛了,我们可以找一个脚本来解释 script 这个脚本也可以用来测试你的 CNI:
为了易读,我删除一些不重要的东西, 原版脚本可以在连接中去拿
# 先创建一个容器,这里只为了拿到一个 net namespace
contid=$(docker run -d --net=none golang:1.12.7 /bin/sleep 10000000)
pid=$(docker inspect -f {{ .State.Pid }} $contid)
netnspath=/proc/$pid/ns/net # 这个我们需要
kubelet 启动 pod 时也是创建好容器就有了 pod 的 network namespaces,再去把 ns 传给 cni 让 cni 去配置
./exec-plugins.sh add $contid $netnspath # 传入两个参数给下一个脚本,containerid 和 net namespace 路径
docker run --net=container:$contid $@
NETCONFPATH=${NETCONFPATH-/etc/cni/net.d}
# 获取容器 id 和网络 ns
contid=$2
netns=$3
# 这里设置了几个环境变量,CNI 命令行工具就可以获取到这些参数
export CNI_COMMAND=$(echo $1 | tr [:lower:] [:upper:] )
export PATH=$CNI_PATH:$PATH # 这个指定 CNI bin 文件的路径
export CNI_CONTAINERID=$contid
export CNI_NETNS=$netns
for netconf in $(echo $NETCONFPATH/10-mynet.conf | sort); do
name=$(jq -r .name $netconf)
plugin=$(jq -r .type $netconf) # CNI 配置文件的 type 字段对应二进制程序名
export CNI_IFNAME=$(printf eth%d $i) # 容器内网卡名
# 这里执行了命令行工具
res=$($plugin $netconf) # 这里把 CNI 的配置文件通过标准输入也传给 CNI 命令行工具
if [ $? -ne 0 ]; then
# 把结果输出到标准输出,这样 kubelet 就可以拿到容器地址等一些信息
errmsg=$(echo $res | jq -r .msg)
if [ -z $errmsg ]; then
errmsg=$res
fi
echo ${name} : error executing $CNI_COMMAND: $errmsg
exit 1
let i=i+1
done
总结一下:
CNI 配置文件
容器 ID
网络 ns
kubelet -------------- CNI command
^ |
| |
+------------------------+
结果标准输出
bridge CNI 实现
既然这么简单,那么就可以去看看实现了:
bridge CNI 代码
//cmdAdd 负责创建网络
func cmdAdd(args *skel.CmdArgs) error
// 入参数都已经写到这里面了,前面的参数从环境变量读取的,CNI 配置从 stdin 读取的
type CmdArgs struct {
ContainerID string
Netns string
IfName string
Args string
Path string
StdinData []byte}
所以 CNI 配置文件除了 name type 这些特定字段,你自己也可以加自己的一些字段. 然后自己去解析
然后啥事都得靠自己了
// 这里创建了设备对,并挂载到 cni0 王桥上
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan)
具体怎么挂的就是调用了 netlink 这个库,sealos 在做内核负载时同样用了该库。
err := netns.Do(func(hostNS ns.NetNS) error { // 创建设备对
hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
...
// 配置容器内的网卡名 mac 地址等
contIface.Name = containerVeth.Name
contIface.Mac = containerVeth.HardwareAddr.String()
contIface.Sandbox = netns.Path()
hostIface.Name = hostVeth.Name
return nil
// 根据 index 找到宿主机设备对名
hostVeth, err := netlink.LinkByName(hostIface.Name)
hostIface.Mac = hostVeth.Attrs().HardwareAddr.String()
// 把宿主机端设备对挂给网桥
if err := netlink.LinkSetMaster(hostVeth, br); err != nil {}
// 设置 hairpin mode
if err = netlink.LinkSetHairpin(hostVeth, hairpinMode); err != nil {
// 设置 vlanid
if vlanID != 0 {err = netlink.BridgeVlanAdd(hostVeth, uint16(vlanID), true, true, false, true)
return hostIface, contIface, nil
最后把结果返回:
type Result struct {
CNIVersion string `json: cniVersion,omitempty `
Interfaces []*Interface `json: interfaces,omitempty `
IPs []*IPConfig `json: ips,omitempty `
Routes []*types.Route `json: routes,omitempty `
DNS types.DNS `json: dns,omitempty `
// 这样 kubelet 就收到返回信息了
func (r *Result) PrintTo(writer io.Writer) error {data, err := json.MarshalIndent(r, , )
if err != nil {
return err
_, err = writer.Write(data)
return err
}
如:
{
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)
}
}
以上就是“kubernetes 的 CNI 怎么安装”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,丸趣 TV 小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注丸趣 TV 行业资讯频道。