KubeVirt 07:VM 网络

将 VM 连接到网络有两个步骤,首先需要在 spec.networks 声明网络,然后在 spec.domain.devices.interfaces 中添加网卡并指定使用的网络。

spec.networks 中声明的网络称为后端(Backend),在 spec.domain.devices.interfaces 中声明的网卡称为前端(Frontend)。

Backend

后端网络配置在 spec.networks,网络必须名称唯一。
每个网络都需要声明类型:

类型描述
pod默认 Kubernetes 网络
multus由 Multus 提供的辅助网络

Frontend

网卡配置在 spec.domain.devices.interfaces ,里面定义的属性将在 VM 中可以看到。
每个网卡都需要声明类型:

类型描述
bridge使用 Linux Bridge 连接
slirp使用 QEMU 用户网络模式连接
sriov透传 SR-IOV PCI 设备通过 vfio
masquerade使用 iptables 规则连接以对流量进行 NAT

访问 VM 中的服务

VM 中的提供的服务通常需要暴露给集群中其它的工作负载访问或被集群外部进行访问。

集群内部访问

使用 fedora-vm1.yaml 部署 VM,VM 使用的 PV 已经事先通过 CDI 导入了 Fedora 镜像:

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  labels:
    kubevirt.io/os: linux
  name: fedora-vm1
spec:
  running: true
  template:
    metadata:
      labels:
        kubevirt.io/domain: fedora-vm1
    spec:
      nodeSelector:
        kubernetes.io/hostname: worker01.example.com
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - disk:
              bus: virtio
            name: disk0
          - cdrom:
              bus: sata
              readonly: true
            name: cloudinitdisk
        machine:
          type: q35
        resources:
          requests:
            memory: 512M
      volumes:
      - name: disk0
        persistentVolumeClaim:
          claimName: fedora
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            hostname: fedora-vm1
            ssh_pwauth: True
            disable_root: false
            ssh_authorized_keys:
            - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqjnw9Xnt4buBYlfuCnZNknm0oKDgVtdzhVTnH/S7Aa0P30D89RrlSSuIcKz0p+6ss3c9sT66R/J4dNUxHuyzYJucRLfmdyEEuVR8mlJ8LLTVR8NOK7r3Ao/mx0cIVJ/YS2y7U8T0uO6YoyoKklvGhlqZHli3fsv4JAVbrCXl05/gdqnQu3u+ang97hDtHg7oSiI3e0Wjm40hwPc+agtaSgypWgmPvdvPNB2YGlmm/QGppTzg0ao0NQduGrTzzYEI54SUx1MFBsM70ykN13IOw2J30fHnnLxlFCCoOwgxy4G9soV/e0vvn7dpqIPsr+Nc+sAuweChclKhUcmBVYa6Pr5mX2y3ZeulE+Nzok165mfF9q5TMC5XziInALDOBVtHIw0St1fgrbnnZPEBiMP6i3q814//TvA0m9xotgq8OrhUbNp2ezjpqyMa+31yPP3gmAVMqji2vIaQB3tluGsH2h/djh0I52YHhDO1S5bDs2OCHCrN2WGuA9qr8NT78ISs= vagrant@master01.example.com
        name: cloudinitdisk

在上述资源定义中,没有定义任何关于网络和网卡的信息。
创建虚拟机后,可以看到默认使用的网络信息:

默认使用的桥接到 Pod 网络,所以在 VM 中的 IP 与 Pod 的 IP 是一致的:

[vagrant@master01 ~]$ kubectl get vmi/fedora-vm1 -n vm-net -o wide
NAME         AGE   PHASE     IP             NODENAME               READY   LIVE-MIGRATABLE   PAUSED
fedora-vm1   10m   Running   10.42.95.178   worker01.example.com   True    False             
[vagrant@master01 ~]$ 
[vagrant@master01 ~]$ virtctl ssh fedora@fedora-vm1.vm-net
Last login: Thu May  9 13:28:11 2024 from 10.42.45.219
[fedora@fedora-vm1 ~]$ ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc fq_codel state UP group default qlen 1000
    link/ether 9e:46:39:51:10:bc brd ff:ff:ff:ff:ff:ff
    altname enp1s0
    inet 10.42.95.178/32 scope global dynamic noprefixroute eth0
       valid_lft 86313127sec preferred_lft 86313127sec
    inet6 fe80::6bf8:8366:c521:5857/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

在 VM 中部署了 Web 服务,可以直接通过 Pod 的 IP 进行访问:

[vagrant@master01 ~]$ curl 10.42.95.178
KubeVirt: hi from fedora-vm1.

但使用 Bridge 模式会带来一个问题:

Message:               cannot migrate VMI which does not use masquerade, bridge with kubevirt.io/allow-pod-bridge-network-live-migration VM annotation or a migratable plugin to connect to the pod network

原因是 Pod 的 IP 是不固定的,当发生迁移的时候,会创建新的 VM,此时 IP 将发生变化,导致 VM 中的网络也随着变化,如果要支持迁移,需要将网络类型修改为 masquerade 类型。

修改为 masquerade

需要更改 vm 资源,修改后,还需将 vmi 删除,重新根据 vm 创建 vmi

[vagrant@master01 ~]$ kubectl edit vm/fedora-vm1 -n vm-net
virtualmachine.kubevirt.io/fedora-vm1 edited
[vagrant@master01 ~]$ kubectl delete vmi fedora-vm1 -n vm-net
virtualmachineinstance.kubevirt.io "fedora-vm1" deleted

然后可以看到在 VM 中 eth0 网卡的网络是一个内部网络:

[vagrant@master01 ~]$ kubectl get vmi/fedora-vm1 -o wide -n vm-net
NAME         AGE    PHASE     IP             NODENAME               READY   LIVE-MIGRATABLE   PAUSED
fedora-vm1   106m   Running   10.42.95.189   worker01.example.com   True    True              
[vagrant@master01 ~]$ virtctl ssh fedora@fedora-vm1.vm-net
Last login: Fri May 10 02:03:56 2024 from 10.42.45.232
[fedora@fedora-vm1 ~]$ ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc fq_codel state UP group default qlen 1000
    link/ether 36:e6:18:9a:fb:04 brd ff:ff:ff:ff:ff:ff
    altname enp1s0
    inet 10.0.2.2/24 brd 10.0.2.255 scope global dynamic noprefixroute eth0
       valid_lft 86307426sec preferred_lft 86307426sec
    inet6 fe80::2224:443b:537b:8b64/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

此时访问 Pod 的 IP,依旧可以访问到 VM 中的服务:

[vagrant@master01 ~]$ curl 10.42.95.189
KubeVirt: hi from fedora-vm1.

Pod IP 不固定,需要使用 Service 资源使用固定的 IP 和集群内部的名称解析来访问 VM 中的服务。
创建 Service:

apiVersion: v1
kind: Service
metadata:
  name: fedoravm1-svc
  namespace: vm-net
spec:
  ports:
    - port: 80
      targetPort: 80
  selector:
    kubevirt.io/domain: fedora-vm1

应用并检查:

[vagrant@master01 ~]$ kubectl apply -f fedora-vm1-svc.yaml 
service/fedoravm1-svc created

[vagrant@master01 ~]$ kubectl describe svc fedoravm1-svc
Error from server (NotFound): services "fedoravm1-svc" not found
[vagrant@master01 ~]$ kubectl describe svc fedoravm1-svc -n vm-net
Name:              fedoravm1-svc
Namespace:         vm-net
Labels:            <none>
Annotations:       <none>
Selector:          kubevirt.io/domain=fedora-vm1
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.43.5.191
IPs:               10.43.5.191
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.42.95.189:80
Session Affinity:  None
Events:            <none>
[vagrant@master01 ~]$ cat fedora-vm1-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: fedoravm1-svc
  namespace: vm-net
spec:
  ports:
    - port: 80
      targetPort: 80
  selector:
    kubevirt.io/domain: fedora-vm1


[vagrant@master01 ~]$ curl 10.43.5.191
KubeVirt: hi from fedora-vm1.

集群外部访问

对外提供 VM 的访问可以通过 Service NodePort 这是最简单的方式,还可以通过 Multus 辅助网络,如果是 HTTP 协议的服务,还可以使用 Ingress 资源。

使用 Service NodePort

修改 Service:

apiVersion: v1
kind: Service
metadata:
  name: fedoravm1-svc
  namespace: vm-net
spec:
  ports:
    - port: 80
      targetPort: 80
  selector:
    kubevirt.io/domain: fedora-vm1
  type: NodePort

应用并检查:

[vagrant@master01 ~]$ kubectl apply -f fedora-vm1-svc.yaml
service/fedoravm1-svc configured
[vagrant@master01 ~]$ kubectl get svc/fedoravm1-svc -n vm-net
NAME            TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
fedoravm1-svc   NodePort   10.43.5.191   <none>        80:30491/TCP   7m33s

#访问 master 节点上的 30491 端口
[vagrant@master01 ~]$ curl localhost:30491
KubeVirt: hi from fedora-vm1.

使用 Ingress

因为 vm 中提供的是 Web 服务,所以可以使用 Ingress,如果是非 HTTP/HTTPS 协议的服务则不行。

webserver ingress 资源定义:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webserver
  namespace: vm-net
spec:
  defaultBackend:
    service:
      name: fedoravm1-svc
      port:
        number: 80
  rules:
  - host: webserver.example.com
    http:
      paths:
      - backend:
          service:
            name: fedoravm1-svc
            port:
              number: 80
        path: /
        pathType: Prefix

创建 ingress 资源并验证:

[vagrant@master01 ~]$ kubectl apply -f ingress-webserver.yaml 
ingress.networking.k8s.io/webserver created
[vagrant@master01 ~]$ kubectl get ingress -n vm-net
NAME        CLASS    HOSTS                   ADDRESS                                          PORTS   AGE
webserver   <none>   webserver.example.com   192.168.121.109,192.168.121.110,192.168.121.27   80      6s
[vagrant@master01 ~]$ curl webserver.example.com
KubeVirt: hi from fedora-vm1

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部