诸如calico flannel等CNI实现,通过牺牲一些功能让网络复杂度得以大幅度降低是我极其推崇的,在云原生时代应用不再关心基础设施的场景下是一个明智之举,给网络调错带来了极大方便。
openstack与k8s放一起比较意义不大,openstack还是着重与基础设施,所以对上接口还是机器设施,网络设施,存储设施等,着重与资源的抽象。
然鹅k8s不仅需要资源抽象,还需要关心应用的管理,其基于容器的设计理念已经改变了传统三层的云计算架构,而更像一个云内核,对上不再关心基础设施的接口了,反正把用户应用管好了就行。
对比早起的操作系统很发现历史是惊人的相似,早期分层式操作系统到现代的宏内核与微内核操作系统,系统设计更为内聚了。目测云操作系统也会朝着这个路子发展吧(openstack粉太多,亡openstack之心不死不敢直说)
但是!
openstack底层一些技术还是非常值得学习与应用的,如qemu kvm ovs ovn ceph DPDK等。。。
本文重点讲网络这块,ovn ovs怎么与kubernetes擦出火花
CNI原理简述
CNI不是本文的重点,这里仅做一下简单的介绍更多详情
CNI很简单,本质就是你实现一个命令行工具,kubelet初始化网络时会去调用这个工具,传入一些环境变量,然后根据环境变量工具去做网络配置:
配置完成后标准输出一个CNI规定的json格式,告诉k8s你的IP地址啥的
命令包含三个部分
- ADD 创建网络
- DEL 删除网络
- CHECK 检查网络
这里对ADD做一个介绍:
EnvCNIPath = "CNI_PATH"
EnvNetDir = "NETCONFPATH"
EnvCapabilityArgs = "CAP_ARGS"
EnvCNIArgs = "CNI_ARGS"
EnvCNIIfname = "CNI_IFNAME" # 网卡名
DefaultNetDir = "/etc/cni/net.d"
CmdAdd = "add"
CmdCheck = "check"
CmdDel = "del"
入参:
容器ID
网络namespace目录
网络配置 - 定义哪些容器可以join到此网络
容器内网卡名
额外参数
标准输出类似这样一个json:
{
"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>
}
...
那比如想拿到pod的一些元数据怎么办,典型场景是比如pod yaml里定义了属于哪个子网啥的,对不起CNI不传给你,你得拿着podid去apiserver里查,这是一个非常不爽的地方,所以现在ovn的CNI都有一个CNI server的东西去和apiserver交互。
我去实现的话会考虑把信息写到容器的label里,这样CNI工具直接去容器元数据里查找一些信息,少用一个server
OVS与OVN安装与配置
编译安装
(吐槽一下ovn写的shit一般的文档)
推荐用源码安装地址
wget https://www.openvswitch.org/releases/openvswitch-2.11.1.tar.gz
tar zxvf openvswitch-2.11.1.tar.gz
cd openvswitch-2.11.1
./boot.sh && ./configure && make && make install
有个ovn的sandbox 可以这样make : make sandbox SANDBOXFLAGS="--ovn"
太低级咱不玩
如果编译内核模块:
$ make modules_install
$ config_file="/etc/depmod.d/openvswitch.conf"
$ for module in datapath/linux/*.ko; do
modname="$(basename ${module})"
echo "override ${modname%.ko} * extra" >> "$config_file"
echo "override ${modname%.ko} * weak-updates" >> "$config_file"
done
$ depmod -a
$ /sbin/modprobe openvswitch
$ /sbin/lsmod | grep openvswitch
启动ovs
$ export PATH=$PATH:/usr/local/share/openvswitch/scripts
$ ovs-ctl start --system-id="random"
$ ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6640:IP_ADDRESS # 开启远程数据库
IP_ADDRESS 是控制节点管理网地址
验证ovs
$ ovs-vsctl add-br br0
$ ovs-vsctl add-port br0 eth0
$ ovs-vsctl add-port br0 vif1.0
$ ovs-vsctl show
启动ovn
$ /usr/share/openvswitch/scripts/ovn-ctl start_northd # 启动北向数据库
$ /usr/share/openvswitch/scripts/ovn-ctl start_controller # 启动ovn controller
$ ovn-sbctl show # 验证
$ ovn-nbctl show # 验证
配置ovs与ovn相连接
# ovn-nbctl set-connection ptcp:6641:0.0.0.0 -- \
set connection . inactivity_probe=60000
# ovn-sbctl set-connection ptcp:6642:0.0.0.0 -- \
set connection . inactivity_probe=60000
# if using the VTEP functionality:
# ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6640:0.0.0.0
配置ovsdb-server模块,默认ovsdb-server只允许本地访问,ovn服务需要这个权限。
配置ovs
controller节点使用ovs databases
ovs-vsctl set open . external-ids:ovn-remote=tcp:IP_ADDRESS:6642
ovs-vsctl set open . external-ids:ovn-encap-type=geneve,vxlan # 配置封装类型,geneve比较吊
ovs-vsctl set open . external-ids:ovn-encap-ip=IP_ADDRESS # 配置overlay endpoint地址
OVS与容器
ovs单机连通性
创建容器, 设置net=none可以防止docker0默认网桥影响连通性测试
docker run -itd --name con6 --net=none ubuntu:14.04 /bin/bash
docker run -itd --name con7 --net=none ubuntu:14.04 /bin/bash
docker run -itd --name con8 --net=none ubuntu:14.04 /bin/bash
创建网桥
ovs-vsctl add-br ovs0
使用ovs-docker给容器添加网卡,并挂到ovs0网桥上
ovs-docker add-port ovs0 eth0 con6 --ipaddress=192.168.1.2/24
ovs-docker add-port ovs0 eth0 con7 --ipaddress=192.168.1.3/24
ovs-docker add-port ovs0 eth0 con8 --ipaddress=192.168.1.4/24
查看网桥
[root@controller /]# ovs-vsctl show
21e4d4c5-cadd-4dac-b025-c20b8108ad09
Bridge "ovs0"
Port "b167e3dcf8db4_l"
Interface "b167e3dcf8db4_l"
Port "f1c0a9d0994d4_l"
Interface "f1c0a9d0994d4_l"
Port "121c6b2f221c4_l"
Interface "121c6b2f221c4_l"
Port "ovs0"
Interface "ovs0"
type: internal
ovs_version: "2.8.2"
测试连通性
[root@controller /]# docker exec -it con8 sh
# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.886 ms
^C
--- 192.168.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.886/0.886/0.886/0.000 ms
#
# ping