由 SuKai June 19, 2022
KubeVirt虚拟机使用固定IP是生产中比较普遍的一个需求,今天我们一起看一下如何通过Kube-OVN为虚拟机提供固定IP。
配置kube-ovn-controller启动参数
Containers:
kube-ovn-controller:
Container ID: containerd://0f8d53403c9821c7b535c64d2c98e1ca130a15e1b2b878270cd9388c36d0e48a
Image: kubeovn/kube-ovn:v1.11.0
Image ID: docker.io/kubeovn/kube-ovn@sha256:fea623e68a2a81ef78102c6cfe95b96c16c054c57f4c8b9d168bd3ff620b6779
Port: <none>
Host Port: <none>
Args:
/kube-ovn/start-controller.sh
--default-cidr=10.244.0.0/16
--default-gateway=10.244.0.1
--default-gateway-check=true
--default-logical-gateway=false
--default-exclude-ips=
--node-switch-cidr=100.64.0.0/16
--service-cluster-ip-range=10.211.0.0/16
--network-type=geneve
--default-interface-name=
--default-vlan-id=100
--pod-nic-type=veth-pair
--enable-lb=true
--enable-np=true
--enable-eip-snat=true
--enable-external-vpc=true
--keep-vm-ip=true
创建虚拟机
spec.template.spec.interfaces.macAddress指定虚拟机网卡MAC,每次删除重建这台虚拟机时使用同一个MAC地址,与系统的网卡配置文件/etc/netplan/50-cloud-init.yaml中MAC地址一致,不需要重新进行配置。
spec.template.metadata.annotations中添加两条记录,ovn.kubernetes.io/ip_address指定kube-ovn使用IP,ovn.kubernetes.io/mac_address告诉kube-ovn网卡的MAC地址。
---
apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
labels:
kubevirt.io/vm: ubuntu-c
name: ubuntu-c
namespace: mail263
spec:
running: true
template:
metadata:
labels:
kubevirt.io/vm: ubuntu-c
annotations:
ovn.kubernetes.io/ip_address: 172.16.3.203
ovn.kubernetes.io/mac_address: 00:00:00:1F:C5:8F
spec:
domain:
cpu:
cores: 4
model: host-passthrough
memory:
guest: 1Gi
devices:
disks:
- name: bootdisk
disk:
bus: virtio
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- name: default
bridge: {}
macAddress: 00:00:00:1f:c5:8f
resources:
overcommitGuestOverhead: true
networks:
- name: default
pod: {}
terminationGracePeriodSeconds: 0
volumes:
- name: bootdisk
dataVolume:
name: ubuntuboot-c
- name: cloudinitdisk
cloudInitNoCloud:
userData: |-
#cloud-config
ssh_pwauth: True
chpasswd:
list: |
ubuntu:ubuntu
expire: False
固定MAC
如果在KubeVirt的VM配置中指定了网卡MAC地址,那么也需要在annotation中指定kube-ovn分配固定的MAC,否则kube-ovn将会生成一个随机的MAC地址,kube-ovn的交换机上MAC地址与虚拟机MAC地址不一致,网络无法通信。
func (subnet *Subnet) GetStaticAddress(podName, nicName string, ip IP, mac string, force bool, checkConflict bool) (IP, string, error) {
subnet.mutex.Lock()
defer func() {
subnet.pushPodNic(podName, nicName)
subnet.mutex.Unlock()
}()
var v4, v6 bool
if net.ParseIP(string(ip)).To4() != nil {
v4 = subnet.V4CIDR != nil
} else {
v6 = subnet.V6CIDR != nil
}
if v4 && !subnet.V4CIDR.Contains(net.ParseIP(string(ip))) {
return ip, mac, ErrOutOfRange
}
if v6 && !subnet.V6CIDR.Contains(net.ParseIP(string(ip))) {
return ip, mac, ErrOutOfRange
}
if mac == "" {
if m, ok := subnet.NicToMac[nicName]; ok {
mac = m
} else {
mac = subnet.GetRandomMac(podName, nicName)
}
} else {
if err := subnet.GetStaticMac(podName, nicName, mac, checkConflict); err != nil {
return ip, mac, err
}
}
if v4 {
if existPod, ok := subnet.V4IPToPod[ip]; ok {
pods := strings.Split(existPod, ",")
if !util.ContainsString(pods, podName) {
if !checkConflict {
subnet.V4NicToIP[nicName] = ip
subnet.V4IPToPod[ip] = fmt.Sprintf("%s,%s", subnet.V4IPToPod[ip], podName)
return ip, mac, nil
}
return ip, mac, ErrConflict
}
if !force {
return ip, mac, nil
}
}
if subnet.V4ReservedIPList.Contains(ip) {
subnet.V4NicToIP[nicName] = ip
subnet.V4IPToPod[ip] = podName
return ip, mac, nil
}
if split, newFreeList := splitIPRangeList(subnet.V4FreeIPList, ip); split {
subnet.V4FreeIPList = newFreeList
subnet.V4NicToIP[nicName] = ip
subnet.V4IPToPod[ip] = podName
return ip, mac, nil
} else {
if split, newReleasedList := splitIPRangeList(subnet.V4ReleasedIPList, ip); split {
subnet.V4ReleasedIPList = newReleasedList
subnet.V4NicToIP[nicName] = ip
subnet.V4IPToPod[ip] = podName
return ip, mac, nil
}
}
} else if v6 {
if existPod, ok := subnet.V6IPToPod[ip]; ok {
pods := strings.Split(existPod, ",")
if !util.ContainsString(pods, podName) {
if !checkConflict {
subnet.V6NicToIP[nicName] = ip
subnet.V6IPToPod[ip] = fmt.Sprintf("%s,%s", subnet.V6IPToPod[ip], podName)
return ip, mac, nil
}
return ip, mac, ErrConflict
}
if !force {
return ip, mac, nil
}
}
if subnet.V6ReservedIPList.Contains(ip) {
subnet.V6NicToIP[nicName] = ip
subnet.V6IPToPod[ip] = podName
return ip, mac, nil
}
if split, newFreeList := splitIPRangeList(subnet.V6FreeIPList, ip); split {
subnet.V6FreeIPList = newFreeList
subnet.V6NicToIP[nicName] = ip
subnet.V6IPToPod[ip] = podName
return ip, mac, nil
} else {
if split, newReleasedList := splitIPRangeList(subnet.V6ReleasedIPList, ip); split {
subnet.V6ReleasedIPList = newReleasedList
subnet.V6NicToIP[nicName] = ip
subnet.V6IPToPod[ip] = podName
return ip, mac, nil
}
}
}
return ip, mac, ErrNoAvailable
}
查看虚拟机系统网卡
ubuntu@ubuntu-c:~$ cat /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
enp1s0:
dhcp4: true
match:
macaddress: 00:00:00:1f:c5:8f
set-name: enp1s0
version: 2
ubuntu@ubuntu-c:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:00:00:1f:c5:8f brd ff:ff:ff:ff:ff:ff
inet 172.16.3.203/24 brd 172.16.3.255 scope global dynamic enp1s0
valid_lft 86266506sec preferred_lft 86266506sec
inet6 fe80::200:ff:fe1f:c58f/64 scope link
valid_lft forever preferred_lft forever
ubuntu@ubuntu-c:~$ ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=115 time=42.8 ms
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 42.762/42.762/42.762/0.000 ms
ubuntu@ubuntu-c:~$
查看OVN交换机
可以看到ubuntu-c.mail263端口上的MAC和IP与虚拟机一致。
ningsuan@ubuntuserver:~/yaml/vms$ kubectl ko nbctl show 0629dbe7-beab-45f1-8d42-0ce2f2a89a79
switch 0629dbe7-beab-45f1-8d42-0ce2f2a89a79 (mail263)
port localnet.mail263
type: localnet
addresses: ["unknown"]
port ubuntu-b.mail263
addresses: ["00:00:00:F1:B6:40 172.16.3.202"]
port mailserver.mail263
addresses: ["00:00:00:68:56:C6 172.16.3.250"]
port ubuntu-a.mail263
addresses: ["00:00:00:D8:95:33 172.16.3.201"]
port ubuntu-c.mail263
addresses: ["00:00:00:1F:C5:8F 172.16.3.203"]
ningsuan@ubuntuserver:~/yaml/vms$