VPC 使用¶
Kube-OVN 支持多租户隔离级别的 VPC 网络。不同 VPC 网络相互独立,可以分别配置 Subnet 网段, 路由策略,安全策略,出网网关,EIP 等配置。
VPC 主要用于有多租户网络强隔离的场景,部分 Kubernetes 网络功能在多租户网络下存在冲突。 例如节点和 Pod 互访,NodePort 功能,基于网络访问的健康检查和 DNS 能力在多租户网络场景暂不支持。 为了方便常见 Kubernetes 的使用场景,Kube-OVN 默认 VPC 做了特殊设计,该 VPC 下的 Subnet 可以满足 Kubernetes 规范。用户自定义 VPC 支持本文档介绍的静态路由,EIP 和 NAT 网关等功能。 常见隔离需求可通过默认 VPC 下的网络策略和子网 ACL 实现,在使用自定义 VPC 前请明确是否需要 VPC 级别的隔离,并了解自定义 VPC 下的限制。 在 Underlay 网络下,物理交换机负责数据面转发,VPC 无法对 Underlay 子网进行隔离。

创建自定义 VPC¶
创建两个 VPC:
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
  name: test-vpc-1
spec:
  namespaces:
  - ns1
---
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
  name: test-vpc-2
spec:
  namespaces:
  - ns2
namespaces可以限定只有哪些 Namespace 可以使用当前 VPC,若为空则不限定。
创建两个子网,分属两个不同的 VPC 并有相同的 CIDR:
kind: Subnet
apiVersion: kubeovn.io/v1
metadata:
  name: net1
spec:
  vpc: test-vpc-1
  cidrBlock: 10.0.1.0/24
  protocol: IPv4
  namespaces:
    - ns1
---
kind: Subnet
apiVersion: kubeovn.io/v1
metadata:
  name: net2
spec:
  vpc: test-vpc-2
  cidrBlock: 10.0.1.0/24
  protocol: IPv4
  namespaces:
    - ns2
分别在两个 Namespace 下创建 Pod:
apiVersion: v1
kind: Pod
metadata:
  namespace: ns1
  name: vpc1-pod
spec:
  containers:
    - name: vpc1-pod
      image: docker.io/library/nginx:alpine
---
apiVersion: v1
kind: Pod
metadata:
  namespace: ns2
  name: vpc2-pod
spec:
  containers:
    - name: vpc2-pod
      image: docker.io/library/nginx:alpine
运行成功后可观察两个 Pod 地址属于同一个 CIDR,但由于运行在不同的租户 VPC,两个 Pod 无法相互访问。
创建 VPC 网关¶
自定义 VPC 下的子网不支持默认 VPC 下的分布式网关和集中式网关。
VPC 内容器访问外部网络需要通过 VPC 网关,VPC 网关可以打通物理网络和租户网络,并提供 浮动 IP,SNAT 和 DNAT 功能。
VPC 网关功能依赖 Multus-CNI 的多网卡功能,安装请参考 multus-cni。
配置外部网络¶
apiVersion: kubeovn.io/v1
kind: Subnet
metadata:
  name: ovn-vpc-external-network
spec:
  protocol: IPv4
  provider: ovn-vpc-external-network.kube-system
  cidrBlock: 192.168.0.0/24
  gateway: 192.168.0.1  # IP address of the physical gateway
  excludeIps:
  - 192.168.0.1..192.168.0.10
---
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: ovn-vpc-external-network
  namespace: kube-system
spec:
  config: '{
      "cniVersion": "0.3.0",
      "type": "macvlan",
      "master": "eth1",
      "mode": "bridge",
      "ipam": {
        "type": "kube-ovn",
        "server_socket": "/run/openvswitch/kube-ovn-daemon.sock",
        "provider": "ovn-vpc-external-network.kube-system"
      }
    }'
- 该 Subnet 用来管理可用的外部地址,网段内的地址将会通过 Macvlan 分配给 VPC 网关,请和网络管理员沟通给出可用的物理段 IP。
 - VPC 网关使用 Macvlan 做物理网络配置,
NetworkAttachmentDefinition的master需为对应物理网络网卡的网卡名。 name外部网络名称。
在 Macvlan 模式下,附属网卡会将数据包直接通过该节点网卡对外发送,L2/L3 层面的转发能力需要依赖底层网络设备。 需要预先在底层网络设备配置对应的网关、Vlan 和安全策略等配置。
- 对于 OpenStack 的 VM 环境,需要将对应网络端口的 
PortSecurity关闭。 - 对于 VMware 的 vSwitch 网络,需要将 
MAC Address Changes,Forged Transmits和Promiscuous Mode Operation设置为allow。 - 对于 Hyper-V 虚拟化,需要开启虚拟机网卡高级功能中的 
MAC Address Spoofing。 - 公有云,例如 AWS、GCE、阿里云等由于不支持用户自定义 Mac 无法支持 Macvlan 模式网络。
 - 由于 Macvlan 本身的限制,Macvlan 子接口无法访问父接口地址,也就意味着无法在 VpcNATGateway Pod 所在的宿主机上通过网络访问该 Pod。
 - 如果物理网卡对应交换机接口为 Trunk 模式,需要在该网卡上创建子接口再提供给 Macvlan 使用。
 
创建 VPC 网关并配置 EIP¶
kind: VpcNatGateway
apiVersion: kubeovn.io/v1
metadata:
  name: gw1
spec:
  vpc: test-vpc-1
  subnet: net1
  lanIp: 10.0.1.254
  selector:
    - "kubernetes.io/hostname: kube-ovn-worker"
    - "kubernetes.io/os: linux"
  externalSubnets:
    - ovn-vpc-external-network
vpc:该 VpcNatGateway 所属的 VPC。subnet:为 VPC 内某个 Subnet 名,VPC 网关 Pod 会在该子网下用lanIp来连接租户网络。lanIp:subnet内某个未被使用的 IP,VPC 网关 Pod 最终会使用该 IP。当 VPC 配置路由需要指向当前 VpcNatGateway 时nextHopIP需要设置为这个lanIp。selector:VpcNatGateway Pod 的节点选择器,格式和 Kubernetes 中的 NodeSelector 格式相同。externalSubnets: VPC 网关使用的外部网络,如果不配置则默认使用ovn-vpc-external-network,当前版本只支持配置一个外部网络。
其他可配参数:
创建 EIP¶
EIP 为外部网络段的某个 IP 分配给 VPC 网关后可进行 DNAT,SNAT 和浮动 IP 操作。
随机分配一个地址给 EIP:
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eip-random
spec:
  natGwDp: gw1
固定 EIP 地址分配:
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eip-static
spec:
  natGwDp: gw1
  v4ip: 192.168.0.100
指定 EIP 所在的外部网络:
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eip-random
spec:
  natGwDp: gw1
  externalSubnet: ovn-vpc-external-network
externalSubnet: EIP 所在外部网络名称,如果不指定则默认为ovn-vpc-external-network,如果指定则必须为所在 VPC 网关的externalSubnets中的一个。
创建 DNAT 规则¶
通过 DNAT 规则,外部可以通过一个 EIP 加端口的方式来访问 VPC 内的一个 IP 和端口。
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eipd01
spec:
  natGwDp: gw1
---
kind: IptablesDnatRule
apiVersion: kubeovn.io/v1
metadata:
  name: dnat01
spec:
  eip: eipd01 
  externalPort: '8888'
  internalIp: 10.0.1.10
  internalPort: '80'
  protocol: tcp
创建 SNAT 规则¶
通过 SNAT 规则配合自定义路由规则,VPC 内的 Pod 访问外部的地址时将会通过对应 EIP 进行 SNAT。
---
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eips01
spec:
  natGwDp: gw1
---
kind: IptablesSnatRule
apiVersion: kubeovn.io/v1
metadata:
  name: snat01
spec:
  eip: eips01
  internalCIDR: 10.0.1.0/24
自定义路由规则请参考自定义路由。
创建浮动 IP¶
通过浮动 IP 规则配合自定义路由规则,VPC 内的一个 IP 会和 EIP 进行完全映射,外部可以通过这个 EIP 访问 VPC 内的 IP,VPC 内的这个 IP 访问外部地址时也会 SNAT 成这个 EIP。
---
kind: IptablesEIP
apiVersion: kubeovn.io/v1
metadata:
  name: eipf01
spec:
  natGwDp: gw1
---
kind: IptablesFIPRule
apiVersion: kubeovn.io/v1
metadata:
  name: fip01
spec:
  eip: eipf01
  internalIp: 10.0.1.5
自定义路由规则请参考自定义路由。
更改网关镜像¶
VPC 网关所使用的镜像可以通过 kube-system Namespace 下的 ovn-vpc-nat-config ConfigMap 进行调整:
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: ovn-vpc-nat-config
  namespace: kube-system
data:
  image: 'docker.io/kubeovn/vpc-nat-gateway:v1.12.35'
image: 网关 Pod 所使用的镜像。
自定义路由¶
在自定义 VPC 内,用户可以自定义网络内部的路由规则,结合网关实现更灵活的转发。 Kube-OVN 支持静态路由和更为灵活的策略路由。
静态路由¶
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
  name: test-vpc-1
spec:
  staticRoutes:
    - cidr: 0.0.0.0/0
      nextHopIP: 10.0.1.254
      policy: policyDst
    - cidr: 172.31.0.0/24
      nextHopIP: 10.0.1.253
      policy: policySrc
      routeTable: "rtb1"
policy: 支持目的地址路由policyDst和源地址路由policySrc。- 当路由规则存在重叠时,CIDR 掩码较长的规则优先级更高,若掩码长度相同则目的地址路由优先于源地址路由。
 routeTable: 可指定静态路由所在的路由表,默认在主路由表。子网关联路由表请参考创建子网
策略路由¶
针对静态路由匹配的流量,可通过策略路由进行更细粒度的控制。策略路由提供了更精确的匹配规则,优先级控制 和更多的转发动作。该功能为 OVN 内部逻辑路由器策略功能的一个对外暴露,更多使用信息请参考 Logical Router Policy。
简单示例如下:
kind: Vpc
apiVersion: kubeovn.io/v1
metadata:
  name: test-vpc-1
spec:
  policyRoutes:
    - action: drop
      match: ip4.src==10.0.1.0/24 && ip4.dst==10.0.1.250
      priority: 11
    - action: reroute
      match: ip4.src==10.0.1.0/24
      nextHopIP: 10.0.1.252
      priority: 10
自定义内部负载均衡规则¶
Kubernetes 本身提供的 Service 能力可以完成内部负载均衡的功能,但是受限于 Kubernetes 实现, Service 的 IP 地址是全局分配且不能重复。对于 VPC 的使用场景,用户希望能自定义内部负载均衡的地址 范围,不同 VPC 下的负载均衡地址可能重叠,Kubernetes 内置的 Service 功能无法完全满足。
针对这类场景,Kube-OVN 提供了 SwitchLBRule 资源,用户可以自定义内部负载均衡的地址范围。
一个 `SwitchLBRule`` 例子如下:
apiVersion: kubeovn.io/v1
kind: SwitchLBRule
metadata:
  name:  cjh-slr-nginx
spec:
  vip: 1.1.1.1
  sessionAffinity: ClientIP
  namespace: default
  selector:
    - app:nginx
  ports:
  - name: dns
    port: 8888
    targetPort: 80
    protocol: TCP
vip:自定义内部负载均衡的地址。namespace:负载均衡器后端 Pod 所在的 Namespace。sessionAffinity:和 Service 的sessionAffinity功能相同。selector:和 Service 的selector功能相同。ports:和 Service 的port功能相同。
查看部署的内部负载均衡器规则:
# kubectl get slr
NAME                VIP         PORT(S)                  SERVICE                             AGE
vpc-dns-test-cjh2   10.96.0.3   53/UDP,53/TCP,9153/TCP   kube-system/slr-vpc-dns-test-cjh2   88m
自定义 vpc-dns¶
由于自定义 VPC 和默认 VPC 网络相互隔离,VPC 内 Pod 无法使用默认的 CoreDNS 服务进行域名解析。 如果希望在自定义 VPC 内使用 CoreDNS 解析集群内 Service 域名,可以通过 Kube-OVN 提供的 vpc-dns 资源来实现。
创建附加网卡¶
apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: ovn-nad
  namespace: default
spec:
  config: '{
      "cniVersion": "0.3.0",
      "type": "kube-ovn",
      "server_socket": "/run/openvswitch/kube-ovn-daemon.sock",
      "provider": "ovn-nad.default.ovn"
    }'
修改 ovn-default 逻辑交换机的 provider¶
修改 ovn-default 的 provider,为上面 nad 配置的 provider ovn-nad.default.ovn:
apiVersion: kubeovn.io/v1
kind: Subnet
metadata:
  name: ovn-default
spec:
  cidrBlock: 10.16.0.0/16
  default: true
  disableGatewayCheck: false
  disableInterConnection: false
  enableDHCP: false
  enableIPv6RA: false
  excludeIps:
  - 10.16.0.1
  gateway: 10.16.0.1
  gatewayType: distributed
  logicalGateway: false
  natOutgoing: true
  private: false
  protocol: IPv4
  provider: ovn-nad.default.ovn
  vpc: ovn-cluster
配置 vpc-dns 的 ConfigMap¶
在 kube-system 命名空间下创建 configmap,配置 vpc-dns 使用参数,用于后面启动 vpc-dns 功能:
apiVersion: v1
kind: ConfigMap
metadata:
  name: vpc-dns-config
  namespace: kube-system
data:
  coredns-vip: 10.96.0.3
  enable-vpc-dns: "true"
  nad-name: ovn-nad
  nad-provider: ovn-nad.default.ovn
enable-vpc-dns:(可缺省)true启用功能,false关闭功能。默认true。coredns-image:(可省略):dns 部署镜像。默认为集群 CoreDNS 部署版本。coredns-template:(可省略):dns 部署模板所在的 URL。默认:当前版本仓库里的yamls/coredns-template.yaml。coredns-vip:为 CoreDNS 提供 lb 服务的 vip。nad-name:配置的network-attachment-definitions资源名称。nad-provider:使用的 provider 名称。k8s-service-host:(可缺省) 用于 CoreDNS 访问 k8s apiserver 服务的 ip。k8s-service-port:(可缺省)用于 CoreDNS 访问 k8s apiserver 服务的 port。
部署 vpc-dns 依赖资源¶
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:vpc-dns
rules:
  - apiGroups:
    - ""
    resources:
    - endpoints
    - services
    - pods
    - namespaces
    verbs:
    - list
    - watch
  - apiGroups:
    - discovery.k8s.io
    resources:
    - endpointslices
    verbs:
    - list
    - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: vpc-dns
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:vpc-dns
subjects:
- kind: ServiceAccount
  name: vpc-dns
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vpc-dns
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: vpc-dns-corefile
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
          lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf {
          prefer_udp
        }
        cache 30
        loop
        reload
        loadbalance
    }
部署 vpc-dns¶
kind: VpcDns
apiVersion: kubeovn.io/v1
metadata:
  name: test-cjh1
spec:
  vpc: cjh-vpc-1
  subnet: cjh-subnet-1
vpc: 用于部署 dns 组件的 vpc 名称。subnet:用于部署 dns 组件的子名称。
查看资源信息:
[root@hci-dev-mst-1 kubeovn]# kubectl get vpc-dns
NAME        ACTIVE   VPC         SUBNET   
test-cjh1   false    cjh-vpc-1   cjh-subnet-1   
test-cjh2   true     cjh-vpc-1   cjh-subnet-2 
ACTIVE:true成功部署了自定义 dns 组件,false无部署
限制¶
- 一个 vpc 下只会部署一个自定义 dns 组件;
 - 当一个 vpc 下配置多个 vpc-dns 资源(即同一个 vpc 不同的 subnet),只有一个 vpc-dns 资源状态 
true,其他为false; - 当 
true的 vpc-dns 被删除掉,会获取其他false的 vpc-dns 进行部署。