Kubernetes(以下、k8s)のSR-IOV設定方法を記載します。
PodとVMI(Virtual Machine Instance)の両方でそれぞれSR-IOVを設定していきます。
1.構成
1-1.環境
1.Master VMWare : VMware(R) Workstation 15 Pro 15.5.1 build-15018445 2.Worker 筐体 : ProLiant DL360p Gen8 System ROM : P71 05/24/2019 NIC : Intel X520-SR2(82599ES), X540-AT2 3.Master&Worker共通 OS : CentOS8.0(1905) Kernel : 4.18.0-80.el8.x86_64 Installed Environment Groups : @^graphical-server-environment @container-management @development @virtualization-client @virtualization-hypervisor @virtualization-tools Kubernetes : 1.17.0 Docker : 19.03.5 flannel : latest KubeVirt : 0.24.0 Multus : latest sriov-cni : latest sriov-network-device-plugin : latest
1-2.全体の構成
2.事前準備
2-1.諸々の準備
SELinuxの無効化 : Master&Worker*2 sed -i -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config FW無効化 : Master&Worker systemctl stop firewalld systemctl disable firewalld パススルー設定 : Master&Worker*3 sed -i -e "s/#options kvm_intel nested=1/options kvm_intel nested=1/g" /etc/modprobe.d/kvm.conf swap無効化 : Master&Worker vi /etc/fstab #/dev/mapper/cl-swap swap swap defaults 0 0 hostsファイル設定 : Master&Worker*4 vi /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 c80g105.md.jp c80g105 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.11.105 c80g105 c80g105.md.jp 192.168.11.106 c80g106 c80g106.md.jp
2-2.HugePageとIOMMUの有効化 : Worker
sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ default_hugepagesz=1G hugepagesz=1G hugepages=16\"/g" /etc/default/grub sed -i -e "/GRUB_CMDLINE_LINUX=/s/\"$/ intel_iommu=on iommu=pt pci=realloc\"/g" /etc/default/grub grub2-mkconfig -o /etc/grub2.cfg vi /etc/fstab 最終行に以下を追記 nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
hugepageの有効化
iommuの有効化
grubに設定反映
マウント
2-3.SR-IOVのVF設定 : Worker
vi /etc/rc.local echo 8 > /sys/class/net/ens1f0/device/sriov_numvfs echo 8 > /sys/class/net/ens1f1/device/sriov_numvfs echo 8 > /sys/class/net/ens2f0/device/sriov_numvfs echo 8 > /sys/class/net/ens2f1/device/sriov_numvfs sleep 1 exit 0 chmod +x /etc/rc.d/rc.local
2枚のNICの各ポートにVFをそれぞれ8つづつ設定
実行権限付与
<補足>
過去記事では、Blacklistに追加していますが、今回は不要です。
2-4.vfio-pciの設定 : Worker
vi /etc/modprobe.d/vfio_pci.conf options vfio_pci ids=8086:10ed echo "vfio-pci" > /etc/modules-load.d/vfio-pci.conf echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modules-load.d/iommu.conf
vfio-pciを有効化するデバイス(NIC)のDeviceID設定
vfio-pciの永続化設定
vfio-pciのiommu利用の永続化
<補足(重要)>
DeviceIDはそれぞれ以下の通りとなります。
8086:10ed | X520 | VMI用 | vfio-pci |
8086:1515 | X540 | Pod用 | ixgbevf |
今回は2枚のNICでそれぞれVMI用とPod用として分けているため、vfio-pciを有効化するのは、X520のみとしています。*5
というのも、以下2点を確認したからです。*6
- VMIでixgbevfを使用すると、kubectl get vmi上ではscheduledのまま固まります。flannelのIPはアサインされますがPingは通りません。*7
- Podでvfio-pciのNICを掴むことができませんでした。ip link showなどで確認しても追加されていません。
ここまでの準備が整ったらMaster&Workerを一旦再起動してください。
3.k8s Cluster & flannelの構築
3-1.Dockerのインストール : Master&Worker
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && \ dnf -y install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm && \ dnf -y install docker-ce && \ systemctl start docker && \ systemctl enable docker
3-2.k8sのリポジトリ設定 : Master&Worker
cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF
3-3.k8sのインストール : Master&Worker
Master dnf -y install kubeadm kubectl Worker dnf -y install kubeadm Master&Worker systemctl start kubelet.service && \ systemctl enable kubelet.service
3-4.Dockerの設定 : Master&Worker
cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF mkdir -p /etc/systemd/system/docker.service.d systemctl daemon-reload && \ systemctl restart docker
3-5.k8sClusterの構築 : Master
kubeadm init --apiserver-advertise-address=192.168.11.105 --pod-network-cidr=10.244.0.0/16
<出力例>
最後に以下の出力が表示されますので、赤文字部分をコピーしておいてください。
WorkerがMasterへJoinする際に使用します。
To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.11.105:6443 --token 0gfh5j.vgu76alcycb2tc2e \ --discovery-token-ca-cert-hash sha256:edcb1a3856838586a6ea7c99200daafa4fbb639e822838f4df81ce09d2faaac3
3-6.k8s Cluster構築後の設定 : Master
コンフィグファイルのコピー mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config コマンド補完設定 echo "source <(kubectl completion bash)" >> ~/.bashrc
3-7.flannelのインストール : Master
mkdir /root/tmp && \ cd /root/tmp/ && \ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml && \ kubectl apply -f kube-flannel.yml kubectl get nodes
<出力例>
以下のようにReadyとなるまで待ってください。
[root@c80g105 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION c80g105.md.jp Ready master 48m v1.17.0
3-8.WorkerのJoin : Worker
kubeadm join 192.168.11.105:6443 --token 0gfh5j.vgu76alcycb2tc2e \ --discovery-token-ca-cert-hash sha256:edcb1a3856838586a6ea7c99200daafa4fbb639e822838f4df81ce09d2faaac3
<出力例>
以下のようにWorkerもReadyとなるまで待ってください。
[root@c80g105 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
c80g105.md.jp Ready master 48m v1.17.0
c80g106.md.jp Ready <none> 19s v1.17.0
ここまでの準備が整ったらMaster&Workerをもう一度再起動してください。
4.KubeVirtの構築
4-1.KubeVirtインストール : Master
export RELEASE=v0.24.0 kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-cr.yaml
<出力例>
Podの状態が以下のようにすべてRunningになるまでには、2分程度掛かります。
kubectl get pods -n kubevirt [root@c80g116 ~]# kubectl -n kubevirt get pods NAME READY STATUS RESTARTS AGE virt-api-64f59f44dd-prkj4 1/1 Running 3 70m virt-api-64f59f44dd-w9984 1/1 Running 3 71m virt-controller-79cc7fb59d-6bz7d 1/1 Running 3 70m virt-controller-79cc7fb59d-wt8g4 1/1 Running 3 70m virt-handler-ljfqg 1/1 Running 5 88m virt-operator-54db765c7d-4xkq5 1/1 Running 3 70m virt-operator-54db765c7d-5bgw4 1/1 Running 3 64m
全てRunningになったら、以下のコマンドを実行
kubectl -n kubevirt wait kv kubevirt --for condition=Available
<出力例>
以下の出力が表示されればOKです。
[root@c80g105 ~]# kubectl -n kubevirt wait kv kubevirt --for condition=Available kubevirt.kubevirt.io/kubevirt condition met
4-2.virtctlのインストール : Master : オプション
必須ではありませんが、vmiを操作する際に便利です。*8
export RELEASE=v0.24.0 curl -L -o virtctl \ https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/virtctl-${RELEASE}-linux-amd64 chmod +x virtctl chown root:root virtctl mv virtctl /usr/bin
4-3.virtctlのインストール : Master : オプション
必須ではありませんが、virtctlはKrewを使ってもインストールできます。*9
export RELEASE=v0.3.3 set -x; cd "$(mktemp -d)" && curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/download/v0.3.3/krew.{tar.gz,yaml}" && tar zxvf krew.tar.gz && KREW=./krew-"$(uname | tr '[:upper:]' '[:lower:]')_amd64" && "$KREW" install --manifest=krew.yaml --archive=krew.tar.gz && "$KREW" update export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" kubectl krew install virt echo 'PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"' >> ~/.bashrc
5.SR-IOV関連のビルド
5-2.SR-IOV CNIのビルド : Master
git clone https://github.com/intel/sriov-cni.git && \ cd sriov-cni && \ make && \ cp build/sriov /opt/cni/bin SRIOV CNIの実行ファイルをWorkerへコピー scp /opt/cni/bin/sriov root@192.168.11.106:/opt/cni/bin/
5-3.SR-IOV Network Deviceのビルド : Master
cd ~/ && \ git clone https://github.com/intel/sriov-network-device-plugin.git && \ cd sriov-network-device-plugin && \ make docker build -t nfvpe/sriov-device-plugin -f ./images/Dockerfile .
<出力例>
docker images [root@c80g105 sriov-network-device-plugin]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nfvpe/sriov-device-plugin latest a45310aae832 13 seconds ago 25.3MB <none> <none> b65d412dee59 19 seconds ago 905MB k8s.gcr.io/kube-proxy v1.17.0 7d54289267dc 6 days ago 116MB k8s.gcr.io/kube-apiserver v1.17.0 0cae8d5cc64c 6 days ago 171MB k8s.gcr.io/kube-controller-manager v1.17.0 5eb3b7486872 6 days ago 161MB k8s.gcr.io/kube-scheduler v1.17.0 78c190f736b1 6 days ago 94.4MB golang alpine 69cf534c966a 8 days ago 359MB k8s.gcr.io/coredns 1.6.5 70f311871ae1 5 weeks ago 41.6MB k8s.gcr.io/etcd 3.4.3-0 303ce5db0e90 7 weeks ago 288MB alpine latest 965ea09ff2eb 7 weeks ago 5.55MB quay.io/coreos/flannel v0.11.0-amd64 ff281650a721 10 months ago 52.6MB k8s.gcr.io/pause 3.1 da86e6ba6ca1 24 months ago 742kB
5-4.SR-IOV Network Deviceのビルド : Worker
cd ~/ && \ git clone https://github.com/intel/sriov-network-device-plugin.git && \ cd sriov-network-device-plugin && \ docker build -t nfvpe/sriov-device-plugin -f ./images/Dockerfile .
<出力例>
docker images [root@c80g106 sriov-network-device-plugin]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nfvpe/sriov-device-plugin latest 8c508ab37c1c 28 seconds ago 25.3MB <none> <none> 571b3587b90d 34 seconds ago 855MB k8s.gcr.io/kube-proxy v1.17.0 7d54289267dc 6 days ago 116MB golang alpine 69cf534c966a 8 days ago 359MB alpine latest 965ea09ff2eb 7 weeks ago 5.55MB quay.io/coreos/flannel v0.11.0-amd64 ff281650a721 10 months ago 52.6MB k8s.gcr.io/pause 3.1 da86e6ba6ca1 24 months ago 742kB kubevirt/virt-api <none> 1a3697b92f09 49 years ago 293MB kubevirt/virt-controller <none> ab9c8cce9c60 49 years ago 291MB kubevirt/virt-handler <none> c5919b95ca31 49 years ago 313MB kubevirt/virt-operator <none> 45c6d543afb1 49 years ago 326MB
<補足>
この後の工程で、sriovdp-daemonset.yaml をデプロイするのですが、元から以下のように書かれているため、WorkerにおいてもDockerイメージをビルドしています。
containers:
- name: kube-sriovdp
image: nfvpe/sriov-device-plugin
imagePullPolicy: Never
6.SR-IOV関連の設定
以下のQuick Startに記載された順番に従い設定を行っていきます。
GitHub - k8snetworkplumbingwg/sriov-network-device-plugin: SRIOV network device plugin for Kubernetes
流れは以下の通りです。*10
- configMapの設定&デプロイ
- sriovdp-daemonsetのデプロイ
- Master:Multusのインストール
- sriov-crdの設定&デプロイ
- リソースの確認
6-1.ConfigMapの設定 : Master
ポイントは
"resourceName": "intel_sriov_netdevice1", "resourceName": "intel_sriov_netdevice2",
として別けて記載している点です。
CRDやVMI&Podのyamlファイルにも一連の流れとして記載していくため、青と緑に別けて書いておきます。
既存ファイルを以下のように書き換えてください。
vi /root/sriov-network-device-plugin/deployments/configMap.yaml [root@c80g105 ~]# vi /root/sriov-network-device-plugin/deployments/configMap.yaml apiVersion: v1 kind: ConfigMap metadata: name: sriovdp-config namespace: kube-system data: config.json: | { "resourceList": [{ apiVersion: v1 kind: ConfigMap metadata: name: sriovdp-config namespace: kube-system data: config.json: | { "resourceList": [ { "resourceName": "intel_sriov_netdevice1", "selectors": { "vendors": ["8086"], "devices": ["154c", "10ed"], "drivers": ["i40evf", "vfio-pci"] } }, { "resourceName": "intel_sriov_netdevice2", "selectors": { "vendors": ["8086"], "devices": ["154c", "1515"], "drivers": ["i40evf", "ixgbevf"] } }, { "resourceName": "intel_sriov_dpdk", "selectors": { "vendors": ["8086"], "devices": ["154c", "10ed"], "drivers": ["vfio-pci"], "pfNames": ["enp0s0f0","enp2s2f1"] } }, { "resourceName": "mlnx_sriov_rdma", "isRdma": true, "selectors": { "vendors": ["15b3"], "devices": ["1018"], "drivers": ["mlx5_ib"] } } ] } kubectl create -f /root/sriov-network-device-plugin/deployments/configMap.yaml
<出力例>
kubectl get configmaps -n kube-system
[root@c80g105 ~]# kubectl get configmaps -n kube-system
NAME DATA AGE
coredns 1 4h32m
extension-apiserver-authentication 6 4h33m
kube-flannel-cfg 2 4h32m
kube-proxy 2 4h32m
kubeadm-config 2 4h32m
kubelet-config-1.17 1 4h32m
multus-cni-config 1 3h16m
sriovdp-config 1 3h16m
<補足>
先ほど記載した表の通りに別けて書いてあることが確認できると思います。
8086:10ed | X520 | VMI用 | vfio-pci |
8086:1515 | X540 | Pod用 | ixgbevf |
6-2.SRIOVDP DaemonSetのデプロイ : Master
特に修正する箇所はありませんので、yamlファイルの中身を確認せず、以下のコマンドを入力しても構いません。
kubectl create -f /root/sriov-network-device-plugin/deployments/k8s-v1.16/sriovdp-daemonset.yaml
vi /root/sriov-network-device-plugin/deployments/k8s-v1.16/sriovdp-daemonset.yaml [root@c80g105 ~]# vi /root/sriov-network-device-plugin/deployments/k8s-v1.16/sriovdp-daemonset.yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: sriov-device-plugin namespace: kube-system --- apiVersion: apps/v1 kind: DaemonSet metadata: name: kube-sriov-device-plugin-amd64 namespace: kube-system labels: tier: node app: sriovdp spec: selector: matchLabels: name: sriov-device-plugin template: metadata: labels: name: sriov-device-plugin tier: node app: sriovdp spec: hostNetwork: true hostPID: true nodeSelector: beta.kubernetes.io/arch: amd64 tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule serviceAccountName: sriov-device-plugin containers: - name: kube-sriovdp image: nfvpe/sriov-device-plugin imagePullPolicy: Never args: - --log-dir=sriovdp - --log-level=10 securityContext: privileged: true volumeMounts: - name: devicesock mountPath: /var/lib/kubelet/ readOnly: false - name: log mountPath: /var/log - name: config-volume mountPath: /etc/pcidp volumes: - name: devicesock hostPath: path: /var/lib/kubelet/ - name: log hostPath: path: /var/log - name: config-volume configMap: name: sriovdp-config items: - key: config.json path: config.json kubectl create -f /root/sriov-network-device-plugin/deployments/k8s-v1.16/sriovdp-daemonset.yaml
<出力例>*11
kubectl get pods -n kube-system [root@c80g105 ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-6955765f44-cn2xp 1/1 Running 1 4h35m coredns-6955765f44-z9dj6 1/1 Running 1 4h35m etcd-c80g105.md.jp 1/1 Running 1 4h35m kube-apiserver-c80g105.md.jp 1/1 Running 1 4h35m kube-controller-manager-c80g105.md.jp 1/1 Running 1 4h35m kube-flannel-ds-amd64-7ltvr 1/1 Running 1 4h35m kube-flannel-ds-amd64-rfr4f 1/1 Running 1 4h35m kube-multus-ds-amd64-475wf 1/1 Running 0 3h19m kube-multus-ds-amd64-9zz5d 1/1 Running 0 3h19m kube-proxy-dmqvr 1/1 Running 1 4h35m kube-proxy-pwmx2 1/1 Running 0 4h35m kube-scheduler-c80g105.md.jp 1/1 Running 1 4h35m kube-sriov-device-plugin-amd64-c2szn 1/1 Running 0 3h19m kube-sriov-device-plugin-amd64-ttwj5 1/1 Running 0 3h19m
6-3.Multusのインストール : Master
ここも特に設定変更などは不要です。
cd /root && \ git clone https://github.com/intel/multus-cni.git && \ cd multus-cni && \ cat ./images/multus-daemonset.yml | kubectl apply -f -
<出力例>
デプロイ後、以下のような出力が表示されればOKです。
kubectl get pods --all-namespaces | grep -i multus [root@c80g105 multus-cni]# kubectl get pods --all-namespaces | grep -i multus kube-system kube-multus-ds-amd64-7kc44 1/1 Running 0 51s kube-system kube-multus-ds-amd64-8ds8r 1/1 Running 0 51s
6-4.SRIOV CRDの設定 : Master
8086:10ed | X520 | VMI用 | vfio-pci |
上記VMI用のCRD(Custom Resource Definitions)の設定を行っていきます。
ポイントはannotationsのresourceNameがconfigMap.yamlと一致している点です。
加えて、この後に設定するVMI用yamlにsriov-net1を記載します。
vi /root/sriov-network-device-plugin/deployments/sriov-crd1.yaml [root@c80g105 ~]# vi /root/sriov-network-device-plugin/deployments/sriov-crd1.yaml apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: sriov-net1 annotations: k8s.v1.cni.cncf.io/resourceName: intel.com/intel_sriov_netdevice1 spec: config: '{ "type": "sriov", "cniVersion": "0.3.1", "name": "sriov300_1", "vlan": 300, "ipam": { "type": "host-local", "subnet": "192.168.30.0/24", "routes": [{ "dst": "0.0.0.0/0" }], "gateway": "192.168.30.254" } }' kubectl create -f /root/sriov-network-device-plugin/deployments/sriov-crd1.yaml
続いて、Pod用のCRD設定を行っていきます。
8086:1515 | X540 | Pod用 | ixgbevf |
vi /root/sriov-network-device-plugin/deployments/sriov-crd2.yaml [root@c80g105 ~]# vi /root/sriov-network-device-plugin/deployments/sriov-crd2.yaml apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: sriov-net2 annotations: k8s.v1.cni.cncf.io/resourceName: intel.com/intel_sriov_netdevice2 spec: config: '{ "type": "sriov", "cniVersion": "0.3.1", "name": "sriov300_2", "vlan": 300, "ipam": { "type": "host-local", "subnet": "192.168.30.0/24", "routes": [{ "dst": "0.0.0.0/0" }], "gateway": "192.168.30.254" } }' kubectl create -f /root/sriov-network-device-plugin/deployments/sriov-crd2.yaml
<出力例>
以下のように表示されればOKです。
[root@c80g105 ~]# kubectl get network-attachment-definitions NAME AGE sriov-net1 3h29m sriov-net2 3h29m
6-5.リソースの確認 : Master
SR-IOVのVFがWorkerのリソースとしてk8sに認識されていることを確認します。
dnf -y install jq kubectl get node c80g106.md.jp -o json | jq '.status.allocatable'
<出力例>
以下のような出力が表示されればOKです。
[root@c80g105 ~]# kubectl get node c80g106.md.jp -o json | jq '.status.allocatable' { "cpu": "40", "devices.kubevirt.io/kvm": "110", "devices.kubevirt.io/tun": "110", "devices.kubevirt.io/vhost-net": "110", "ephemeral-storage": "400024062519", "hugepages-1Gi": "16Gi", "intel.com/intel_sriov_dpdk": "0", "intel.com/intel_sriov_netdevice": "0", "intel.com/intel_sriov_netdevice1": "16", "intel.com/intel_sriov_netdevice2": "16", "intel.com/mlnx_sriov_rdma": "0", "memory": "313085984Ki", "pods": "110" }
7.VMIとPodのデプロイ
VMI用として事前にqcow2イメージファイルを作成しておきます。*12
以下の過去記事などを参照の上、適当な仮想マシンを作成してください。
CentOS7 kickstartによるインストール - Metonymical Deflection
CentOS8 kickstartによるインストール - Metonymical Deflection
ここでは、CentOS7.7をインストールしたqcow2ファイルが、/root直下に既に存在する前提として話を進めます。
7-1.VMI用のイメージ登録 : Worker
イメージファイルのコピー mkdir /root/docker cd /root/docker cp /root/c771.qcow2 ./ ビルド用のDockerfile作成 cat << END > Dockerfile FROM scratch ADD c771.qcow2 /disk/ END イメージのビルド docker build -t vmidisks/centos:7.7 .
<出力例>
[root@c80g106 docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE vmidisks/centos 7.7 f5a39b56e448 21 seconds ago 1.64GB nfvpe/sriov-device-plugin latest 8c508ab37c1c 6 minutes ago 25.3MB <none> <none> 571b3587b90d 7 minutes ago 855MB k8s.gcr.io/kube-proxy v1.17.0 7d54289267dc 6 days ago 116MB golang alpine 69cf534c966a 8 days ago 359MB nfvpe/multus v3.4 7cf8e2d1b733 10 days ago 312MB alpine latest 965ea09ff2eb 7 weeks ago 5.55MB quay.io/coreos/flannel v0.11.0-amd64 ff281650a721 10 months ago 52.6MB k8s.gcr.io/pause 3.1 da86e6ba6ca1 24 months ago 742kB kubevirt/virt-handler <none> c5919b95ca31 49 years ago 313MB kubevirt/virt-controller <none> ab9c8cce9c60 49 years ago 291MB kubevirt/virt-api <none> 1a3697b92f09 49 years ago 293MB kubevirt/virt-operator <none> 45c6d543afb1 49 years ago 326MB
7-2.VMIのデプロイ : Master
vi /root/sriov-network-device-plugin/deployments/c771.yaml [root@c80g105 deployments]# vi /root/sriov-network-device-plugin/deployments/c771.yaml apiVersion: kubevirt.io/v1alpha3 kind: VirtualMachineInstance metadata: name: c771 spec: domain: resources: requests: memory: "2048Mi" cpu: "1" devices: disks: - name: containerdisk disk: bus: virtio interfaces: - name: pod bridge: {} - name: net1 sriov: {} - name: net2 sriov: {} volumes: - name: containerdisk containerDisk: image: vmidisks/centos:7.7 imagePullPolicy: Never networks: - name: pod pod: {} - name: net1 multus: networkName: sriov-net1 - name: net2 multus: networkName: sriov-net1 kubectl create-f /root/sriov-network-device-plugin/deployments/c771.yaml
<出力例>
kubectl get pods kubectl get vmi [root@c80g105 ~]# kubectl get pods kubectl get vmi NAME READY STATUS RESTARTS AGE virt-launcher-c771-5kdr2 2/2 Running 0 3h29m [root@c80g105 ~]# kubectl get vmi NAME AGE PHASE IP NODENAME c771 3h29m Running 10.244.1.14/24 c80g106.md.jp
<補足>
ポイントを5点ほど。
- multus: > networkName: に先ほど作成したCRDの名前sriov-net1を指定している点です。これにより、明示的にX520を使用する設定*13となっています。
- spec: > domain: > resources: には、requests:のみを記載している点です。ここでlimits: を追記すると起動後に高確率でOOM Killerが発動しVMIが瞬殺されます。*14
- kubectl get podsにて、READYが2/2になっています。これはVMIに加えて、virt-launcherが起動しているためです。
- kubectl get vmiにて、IPが10.244.1.14/24*15となっています。IPアドレス自体「10.244.1.14」は、PHASEがRunningになると、すぐに表示されます。しかし、私の環境ではプリフィックス「 /24 」が表示されるまでに90秒程度かかりました。また、プリフィックスが表示されなくてもログインできる場合があります。*16
- SR-IOVにてアサインされたNICが保持するIPアドレスを確認するためには、VMIへのログインが必要なので、virtctl console コマンドやsshなどでVMIにログインしてください。ログイン後、ip add showすると、以下のように見えると思います。eth1とeth2のMACアドレスがWorkerのVFのMACアドレスと一致していることを確認してください。加えて、外部NW機器にPingが通ることを確認できれば構築完了です。
[root@c771 ~]# ip add show 1: lo: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: eth0: mtu 1450 qdisc pfifo_fast state UP group default qlen 1000 link/ether 8e:29:cb:fc:87:4a brd ff:ff:ff:ff:ff:ff inet 10.244.1.14/24 brd 10.244.1.255 scope global noprefixroute dynamic eth0 valid_lft 86312966sec preferred_lft 86312966sec inet6 fe80::f6a2:e021:e183:9852/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: eth1: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 96:e5:96:36:1c:90 brd ff:ff:ff:ff:ff:ff inet 192.168.30.139/24 brd 192.168.30.255 scope global noprefixroute dynamic eth1 valid_lft 2966sec preferred_lft 2966sec inet6 fe80::409f:ff:fe56:8741/64 scope link valid_lft forever preferred_lft forever 4: eth2: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 9e:46:96:a2:4b:4e brd ff:ff:ff:ff:ff:ff inet 192.168.30.138/24 brd 192.168.30.255 scope global noprefixroute dynamic eth2 valid_lft 2966sec preferred_lft 2966sec inet6 fe80::6c:5eff:fee0:56ca/64 scope link valid_lft forever preferred_lft forever
Worker上では以下のように認識されます。
[root@c80g106 ~]# ip link show 一部省略 6: ens1f0:mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 90:e2:ba:0b:37:b8 brd ff:ff:ff:ff:ff:ff vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 1 MAC 96:e5:96:36:1c:90, vlan 300, spoof checking on, link-state auto, trust off, query_rss off vf 2 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 3 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 4 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 5 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 6 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 7 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off 7: ens1f1: mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 90:e2:ba:0b:37:b9 brd ff:ff:ff:ff:ff:ff vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 1 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 2 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 3 MAC 9e:46:96:a2:4b:4e, vlan 300, spoof checking on, link-state auto, trust off, query_rss off vf 4 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 5 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 6 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off vf 7 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off, query_rss off
7-3.Podのデプロイ
vi /root/sriov-network-device-plugin/deployments/pod2.yaml apiVersion: v1 kind: Pod metadata: name: pod2 annotations: k8s.v1.cni.cncf.io/networks: sriov-net2 spec: containers: - name: pod2 image: docker.io/centos/tools:latest command: - /sbin/init resources: requests: intel.com/intel_sriov_netdevice2: '1' limits: intel.com/intel_sriov_netdevice2: '1' kubectl create -f /root/sriov-network-device-plugin/deployments/pod2.yaml
<出力例>
[root@c80g105 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod2 1/1 Running 1 11h 10.244.1.19 c80g106.md.jpvirt-launcher-c771-cp2nk 2/2 Running 0 23m 10.244.1.27 c80g106.md.jp
<補足>
ポイントを3点ほど。
- annotations: > k8s.v1.cni.cncf.io/networks: に先ほど作成したCRDの名前sriov-net2を指定している点です。これにより、明示的にX540を使用する設定*17となっています。
- resources: > requests: に intel.com/intel_sriov_netdevice2を指定している点です。また「'1'」はVFの数を示していますが、2や3と増やしても、VFは1つしかアサインされませんでした。*18
- SR-IOVにてアサインされたNICが保持するIPアドレスは、以下のコマンドで確認できます。net1のMACアドレスがWorkerのVFのMACアドレスと一致していることを確認してください。加えて、外部NW機器にPingが通ることを確認できれば構築完了です。
kubectl exec -it pod2 -- ip addr show [root@c80g105 ~]# kubectl exec -it pod2 -- ip addr show 1: lo: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 3: eth0@if31: mtu 1450 qdisc noqueue state UP group default link/ether 0a:56:43:b8:ad:f5 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.244.1.19/24 scope global eth0 valid_lft forever preferred_lft forever 24: net1: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 2e:f2:70:b7:e9:ca brd ff:ff:ff:ff:ff:ff inet 192.168.30.6/24 brd 192.168.30.255 scope global net1 valid_lft forever preferred_lft forever
Worker上では以下のように認識されます。
[root@c80g106 ~]# ip link show 一部省略 8: ens2f0:mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether a0:36:9f:3e:70:d4 brd ff:ff:ff:ff:ff:ff vf 0 MAC 4e:bc:dc:62:a8:7e, spoof checking on, link-state auto, trust off, query_rss off vf 1 MAC ee:c9:15:96:2d:5d, spoof checking on, link-state auto, trust off, query_rss off vf 2 MAC c2:82:b1:0f:ca:2e, spoof checking on, link-state auto, trust off, query_rss off vf 3 MAC 86:e2:0a:d6:96:ff, spoof checking on, link-state auto, trust off, query_rss off vf 4 MAC 6e:5e:70:e8:da:48, spoof checking on, link-state auto, trust off, query_rss off vf 5 MAC f2:2f:55:d8:b3:40, spoof checking on, link-state auto, trust off, query_rss off vf 6 MAC ae:a8:e8:48:25:2c, spoof checking on, link-state auto, trust off, query_rss off vf 7 MAC da:d8:2a:7d:2f:5b, spoof checking on, link-state auto, trust off, query_rss off 9: ens2f1: mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether a0:36:9f:3e:70:d6 brd ff:ff:ff:ff:ff:ff vf 0 MAC ba:73:6f:81:ea:31, spoof checking on, link-state auto, trust off, query_rss off vf 1 MAC 0a:24:c7:34:26:ec, spoof checking on, link-state auto, trust off, query_rss off vf 2 MAC d6:62:b0:f5:01:fc, spoof checking on, link-state auto, trust off, query_rss off vf 3 MAC a2:05:32:03:eb:d4, spoof checking on, link-state auto, trust off, query_rss off vf 4 MAC b2:46:0e:e4:93:90, spoof checking on, link-state auto, trust off, query_rss off vf 5 MAC 76:d6:8a:9f:1a:84, spoof checking on, link-state auto, trust off, query_rss off vf 6 MAC 2e:f2:70:b7:e9:ca, vlan 300, spoof checking on, link-state auto, trust off, query_rss off vf 7 MAC 8e:c0:94:c2:98:f9, spoof checking on, link-state auto, trust off, query_rss off
7-4.VMIとPodの差異について
以下にまとめます。
8086:10ed | X520 | VMI用 | vfio-pci |
8086:1515 | X540 | Pod用 | ixgbevf |
VMI用vfio-pciについて
- worker上でip add showを打っても、vfio-pci上で動作しているため、blacklist登録時と同様にVFのNICは表示されません。このためip link showでMACアドレスを確認します。
- VMIによってVFが掴まれていないとき、MACアドレスは00:00:00:00:00:00が正常です。
- 今回の構成では、IPアドレスは外部NW機器*19にてDHCPサーバを立ててIPアドレスをアサインしています。
Pod用ixgbevfについて
- ixgbevfにて動作しているため、ip add showにてVFのNICが表示されます。
- PodによってVFが掴まれているか否かに関わらず、任意のMACアドレスがアサインされます。そのMACアドレスはそのままPodが継承します。
- IPアドレスは(恐らく)MultusからDHCPのように自動でアサインされています。
- アドレスレンジを指定する場合は以下のようにCRDに追記してください。
vi /root/sriov-network-device-plugin/deployments/sriov-crd2.yaml [root@c80g105 ~]# vi /root/sriov-network-device-plugin/deployments/sriov-crd2.yaml apiVersion: "k8s.cni.cncf.io/v1" kind: NetworkAttachmentDefinition metadata: name: sriov-net2 annotations: k8s.v1.cni.cncf.io/resourceName: intel.com/intel_sriov_netdevice2 spec: config: '{ "type": "sriov", "cniVersion": "0.3.1", "name": "sriov300_2", "vlan": 300, "ipam": { "type": "host-local", "subnet": "192.168.30.0/24", "rangeStart": "192.168.30.64", "rangeEnd": "192.168.30.127", "routes": [{ "dst": "0.0.0.0/0" }], "gateway": "192.168.30.254" } }'
7-5.VMIとPodのdescribe情報*20
VMIのdescribe
以下のコマンドで確認できます。実際の出力はここにアップしておきます。
kubectl describe pods virt-launcher-c771-cp2nk
Podのdescribe
以下のコマンドで確認できます。実際の出力はここにアップしておきます。
kubectl describe pods pod2
VMIのlog
VMIが正常起動しないときやログインできないときは、以下のログを確認してみてください。
膨大な量のログが出力されるので、ここにアップしておきます。
kubectl logs virt-launcher-c771-cp2nk compute
以上です。
8.最後に
以下のサイトを参考にさせて頂きました。
GitHub - k8snetworkplumbingwg/multus-cni
GitHub - k8snetworkplumbingwg/sriov-cni: DPDK & SR-IOV CNI plugin
GitHub - k8snetworkplumbingwg/sriov-network-device-plugin: SRIOV network device plugin for Kubernetes
https://kubevirt.io/user-guide/docs/latest/creating-virtual-machines/interfaces-and-networks.html
Kubernetes: Multus + SRIOV quickstart – Zenghui Shi
今回はSR-IOVでしたが、次回はOvS-DPDKなどにも挑戦できればと考えています。
Kubernetesのネットワーク構成といった場合、flannelやCalicoの解説サイトがたくさんあったため、とても助かりました。
しかし、SR-IOVに関してVMIとPodの両方を解説しているサイトが皆無に等しかったため今回の記事を書きました。
今のネットワークのトレンドとしては、P4やeBPF+XDP、SRv6といった辺りかなと思っています。
このため、まだまだ私は遅れ気味だなと日々痛感しておりますが、これでようやく足元ぐらいに辿り着けていられればいいなぁ、と思っています。
また、クラウドネイティブといったキーワードが頻出していますが、実際に自分で手を動かしていじってみた結果、クラウドネイティブであることの意味とか意義とか優位性というモノが、理解できたような気がします。
今回、Podに加えて、KubeVirt上のVMIについても記載しましたが、私の個人的な感想として、一定の需要がありそうな気がしました。
というのも、
いきなり一足飛びでコンテナ化できない or コンテナ化するにはハードルが高いといったケースを鑑みるに、libvirtd上で仮想マシンを稼働させながらも、アーキテクチャはk8sに(クラウドネイティブ化したシステムとして)統一したい、といった要件を満たせるかもしれないと思いました。
Migrate for Anthosなどは、まさしくこういった課題を解決するために提供され始めたのかな、という気がします。
Migrate for Anthos | Google Cloud
*1:おさらい程度に読み飛ばしてください。
*2:今回は無効化してしまいますが、本来はあまり良くないです。
*3:Masterは不要ですが念のため
*4:名前解決できるようにしておいてください。
*6:これに気付くまでに2週間程度掛かりました。。。
*7:kubectl get pods上ではrunningになりますが。
*8:virshのようにStart & StopやConsoleログインができます。
*9:私の環境では、tar.gzをDLするとハッシュ値が異なるというエラーで弾かれてしまったためインストールしていません。最近、KubeVirtがv0.24.0にアップデートされた影響かもしれません。
*10:Multusが3番目なのですが、先にインストールしても大丈夫かなと思っています。
*11:Master&Workerにて、それぞれsriov-device-pluginを起動させるため、5-3 & 5-4にて、Docker Imageのビルドをしています。
*12:Cloud Initからイメージファイルを落とした場合、証明書認証が必要となるため、公開鍵を仕込む必要がありますので、私は自前でqcow2ファイルを作っています。
*14:これに気付くのに1週間程度掛かりました。。
*16:これの理由は未だによくわかっていません。。
*17:即ち、ixgbevfを使用する設定
*18:この辺りの仕様が正直よくわかっていません。。
*19:構成図右側のスイッチ