OpenStackもいらなくなる?kubevirt がどんなものか触って見た。
kubevirt を利用すると kubernetes で仮想マシンを管理することが可能になります。 Kubernetes で管理できるということでスケジューリングやセルフヒーリング、ロードバンランサなどのサービスが利用できるなど期待が高まります。
CNCF Cloud Native Interactive Landscape では Application Definition & Image Build のカテゴリに分類されていました。
はじめに
OpenStack もいらなくなる?と書いたのは、冒頭に書いた Kubernetes で得られる一般的なメリットを利用できる点に期待したからです。 OpenStack を作ることが自体がとても大変で、最近だとドキュメント通りでうまく起動はできるとは思うのですが、やはり手間であることには変わりないと思います。 OpenStack をインストールして使える形にすること自体が本質ではないからだと思います。EC2、Route53、EBS、ELB 相当の必要なコンポーネントを作り上げるだけで一苦労です。
VM を提供するために OpenStack 新しく作るとしたら何で作るのが楽かなと考えた時に、Kubernetes 上にコンテナで作る?とかも考えたのですが、 結局、OpenStack を ansible で積み立てるのが dockerfile と yaml になったくらいで労力は変わらないんですよね。。
ということで、kubevirt に OpenStack もいらなくなる?という淡い期待を抱いたわけです。 Kubernetes という一枚抽象レイヤーを挟むことで、仮想マシンを立ち上げるためのサービスの可搬性があがります。
(もちろん、OpenStack は単なる VM を提供するだけのものではないのですが)
kubevirt のコンポーネント
ここからは kubevirt がどんなものか理解するために、実際に動作させて見るわけですが、まずはコンポーネントを軽く見てみます。 代表的なものを紹介しておきます。
- virt-controller
- VM を起動させるための pod を作成します。pod が特定のノードでスケジュールされた場合に、virt-handler と連携します。
- virt-hnadller
- virt-launcher
kubevirt をインストール
minikube インストール
今回、構築した環境をまとめておきます。
$ cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core)
まずはホスト側で kvm の nested を on にしておきます。パフォーマンス気にしないようであれば必須ではないです。 kvm を使わずに、qemu だけで起動もできます。
$ cat /sys/module/kvm_intel/parameters/nested N $ modprobe -r kvm_intel $ modprobe kvm_intel nested=1 $ vi /etc/modprobe.d/kvm.conf $ sudo vi /etc/modprobe.d/kvm.conf $ cat /sys/module/kvm_intel/parameters/nested Y
必要なパッケージをインストール
$ sudo yum -y install libguestfs libvirt libvirt-client python-virtinst qemu-kvm virt-manager virt-top virt-viewer virt-who virt-install bridge-utils
インストールは以下を参考にします。 github.com{:target="_blank"}
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \ > && chmod +x minikube $ ls minikube $ sudo install minikube /usr/local/bin $ minikube
こちら{:target="_blank"} を参考に以下も実施しておきましょう
curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \ && sudo install docker-machine-driver-kvm2 /usr/local/bin/
以下の通り kubevirt というプロファイル名であげておきます。
$ minikube config -p kubevirt set memory 4096 $ minikube config -p kubevirt set vm-driver kvm2 $ minikube start -p kubevirt
kubectl をインストールします。minikube 入れたときに ~/.kube/config を設定しておいてくれます。
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl $ chmod +x ./kubectl $ sudo mv ./kubectl /usr/local/bin/kubectl
一応確認してみます。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION minikube Ready master 5m52s v1.15.0
以下も対応しておきましょう。
$ systemctl stop firewalld $ systemctl disable firewalld $ sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: そのようなファイルやディレクトリはありません こんな感じで not found になったら以下を試して見てください。br_netfilter モジュールに含まれるようになっているはずです。
$ sudo modprobe br_netfilter
kubevirt の環境セットアップ
まずは virt-operator を作ります。 Kubevirt の core components を作成してくれます。crd と必要な role や deployment などができます。
$ export KUBEVIRT_VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases|grep tag_name|sort -V | tail -1 | awk -F':' '{print $2}' | sed 's/,//' | xargs) $ echo $KUBEVIRT_VERSION v0.19.0-rc.0 $ kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml namespace/kubevirt created customresourcedefinition.apiextensions.k8s.io/kubevirts.kubevirt.io created clusterrole.rbac.authorization.k8s.io/kubevirt.io:operator created serviceaccount/kubevirt-operator created clusterrole.rbac.authorization.k8s.io/kubevirt-operator created clusterrolebinding.rbac.authorization.k8s.io/kubevirt-operator created deployment.apps/virt-operator created
kubevirt の crd ができてますね。
$ kubectl get crds NAME CREATED AT kubevirts.kubevirt.io 2019-07-21T04:21:34Z
kubevirt の namespace を確認してみます。
$ kubectl get deployment -n kubevirt NAME READY UP-TO-DATE AVAILABLE AGE virt-operator 2/2 2 2 27m $ kubectl get pod -n kubevirt NAME READY STATUS RESTARTS AGE virt-operator-76d85fb55b-2b9l6 1/1 Running 0 27m virt-operator-76d85fb55b-d494d 1/1 Running 0 27m
virt-api , controller を作ります。 node ごとに handler も立ち上がります。
$ kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml
$ kubectl get deployment -n kubevirt NAME READY UP-TO-DATE AVAILABLE AGE virt-api 2/2 2 2 3m16s virt-controller 2/2 2 2 2m49s virt-operator 2/2 2 2 32m
以下のように pod が立ち上がります。
$ kubectl get pod -n kubevirt NAME READY STATUS RESTARTS AGE virt-api-65f4879dc7-ltmb8 1/1 Running 0 106m virt-api-65f4879dc7-nwmzf 1/1 Running 0 106m virt-controller-5ccf9d47-bwkcw 1/1 Running 0 106m virt-controller-5ccf9d47-jcg5q 1/1 Running 0 106m virt-handler-jddl7 1/1 Running 0 106m virt-operator-76d85fb55b-2b9l6 1/1 Running 0 136m virt-operator-76d85fb55b-d494d 1/1 Running 0 136m
test vm を立ち上げてみる
$ kubectl apply -f https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/vm.yaml virtualmachine.kubevirt.io/testvm created
先ほど入れた virtctl を使ってみましょう。つい型は以下の通りです。
$ virtctl help virtctl controls virtual machine related operations on your kubernetes cluster. Available Commands: console Connect to a console of a virtual machine instance. expose Expose a virtual machine instance, virtual machine, or virtual machine instance replica set as a new service. help Help about any command image-upload Upload a VM image to a PersistentVolumeClaim. restart Restart a virtual machine. start Start a virtual machine. stop Stop a virtual machine. version Print the client and server version information. vnc Open a vnc connection to a virtual machine instance. Use "virtctl <command> --help" for more information about a given command. Use "virtctl options" for a list of global command-line options (applies to all commands).
$ virtctl start testvm
$ kubectl get vms NAME AGE RUNNING VOLUME testvm 114s true $ kubectl get vmis NAME AGE PHASE IP NODENAME testvm 28s Scheduling
ちょっと待つと vm が起動します。
$ kubectl get vmis NAME AGE PHASE IP NODENAME testvm 67s Running 172.17.0.11 minikube
起動しない場合は virt-launcher がちゃんとできているか kubectl get pod / kubectl describe pod virt-launcher-
ちなみにホストのインタフェースを見ると以下のように docker bridge が同じサブネットにいました。
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:dc:39:98:2b brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:dcff:fe39:982b/64 scope link valid_lft forever preferred_lft forever
コンソールを叩いています。
$ virtctl console testvm Successfully connected to testvm console. The escape sequence is ^] login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root. testvm login: root Password: Login incorrect testvm login: cirros Password: $ $ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1 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: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 02:42:ac:11:00:0b brd ff:ff:ff:ff:ff:ff inet 172.17.0.11/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:b/64 scope link valid_lft forever preferred_lft forever $ ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: seq=0 ttl=50 time=2.187 ms 64 bytes from 8.8.8.8: seq=1 ttl=50 time=1.833 ms 64 bytes from 8.8.8.8: seq=2 ttl=50 time=1.852 ms
kubevirt で persistent volume を使った vm を立ち上げてみる
VM 用の PV を作成する
やっぱり永続的ボリューム使わないと困りますよね。 pod 立ち上げるたびにデータが消える VM は使いたくないですよね
$ kubectl create -f https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/storage-setup.yml $ kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/v1.9.0/cdi-controller.yaml
storage-setup.yml の中で storageclass を作成していますが、 storageclass.kubernetes.io/is-default-class: "true"
が入っているので、以下のように default が複数になってしまう点注意してください。また今回は minikube で 1 Node になるので persistent volume の type は hostpath が利用されています。以下、マニュアルの記載です。
HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
$ kubectl get sc NAME PROVISIONER AGE hostpath (default) hostpath 11s standard (default) k8s.io/minikube-hostpath 4h56m
cdi (containerized-data-importer) の pod ができていることが確認できます。
$ kubectl get pods -n cdi NAME READY STATUS RESTARTS AGE cdi-apiserver-775cdcc9b7-2qthb 1/1 Running 0 47s cdi-deployment-75f8755479-5zgd2 1/1 Running 0 47s cdi-uploadproxy-7d9c96fb4f-2g2w8 1/1 Running 0 47s
ここで PersistentVolumeClaim を作成します。イメージは qcow2 です。 以下の通り失敗したら先ほどのストレージタイプのデフォルトを確認してください。
$ kubectl create -f https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/pvc_fedora.yml Error from server (Forbidden): error when creating "https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/pvc_fedora.yml": persistentvolumeclaims "fedora" is forbidden: Internal error occurred: 2 default StorageClasses were found
一応、デフォルトが二つある場合の対処法を書いておきます
$ kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}' storageclass.storage.k8s.io/standard patched $ kubectl get storageclass standard NAME PROVISIONER AGE standard k8s.io/minikube-hostpath 5h2m $ $ kubectl get storageclass NAME PROVISIONER AGE hostpath (default) hostpath 112m standard k8s.io/minikube-hostpath 6h48m```
問題なく作成されていれば以下のようになるはずです。
$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE fedora Bound pvc-a5633c44-7b33-460d-8a51-4c4706528979 10Gi RWO hostpath 91s
importer pod が立ち上がって、指定したイメージを kubevirt で立ち上げられるように pv に書き込んでくれます。
This will create the PVC with a proper annotation so that CDI controller detects it and launches an importer pod to gather the image specified in the cdi.kubevirt.io/storage.import.endpoint annotation.
$ kubectl get pod NAME READY STATUS RESTARTS AGE importer-fedora-zshdd 1/1 Running 1 118s
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-a5633c44-7b33-460d-8a51-4c4706528979 10Gi RWO Delete Bound default/fedora hostpath 90s
importer が起動中に log を見ると以下のように処理が見えます。
I0722 09:27:38.023484 1 importer.go:58] Starting importer I0722 09:27:38.024785 1 importer.go:100] begin import process I0722 09:27:38.358624 1 data-processor.go:237] Calculating available size I0722 09:27:38.362428 1 data-processor.go:245] Checking out file system volume size. I0722 09:27:38.362459 1 data-processor.go:249] Request image size not empty. I0722 09:27:38.362474 1 data-processor.go:254] Target size 10Gi. I0722 09:27:38.362567 1 data-processor.go:167] New phase: Convert I0722 09:27:38.362774 1 data-processor.go:173] Validating image I0722 09:27:39.772281 1 qemu.go:205] 0.00 I0722 09:27:44.024407 1 qemu.go:205] 1.00
この pod は処理が終わると削除されます。
I0722 09:35:49.844195 1 data-processor.go:167] New phase: Resize I0722 09:35:49.863375 1 data-processor.go:230] Expanding image size to: 10Gi I0722 09:35:49.997196 1 data-processor.go:167] New phase: Complete I0722 09:35:49.997274 1 importer.go:132] import complete $ $ kubectl get pod No resources found.
PV にデータが入ったのでここで VM を立ち上げます。 ちなみに CDI の機能として、upload 用の PV を作ったり、 golden image から clone したりして PV を作成することも可能です。参考になるドキュメントはこちら{:target="_blank"} 。
PV を使って VM を作成する
以下のマニュフェストを使います。kind: VirtualMachine になっています。以下のマニュフェストでは label がついていないので、何かつけておいてください。
$ wget https://raw.githubusercontent.com/kubevirt/kubevirt.github.io/master/labs/manifests/vm1_pvc.yml $ ssh-keygen $ PUBKEY=`cat ~/.ssh/id_rsa.pub` $ sed -i "s%ssh-rsa.*%$PUBKEY%" vm1_pvc.yml $ kubectl create -f vm1_pvc.yml
testvm の時と同様 pod / vm / vmi を確認して問題ないことを確認します。 今回は、ssh のアクセスをしてみます。virtctl で node port を作成します。 ここでは virtctl を使っていますが、テストではない場合、結局は vm の label をみて service を作っているだけなのでマニュフェストファイルを作って作成しましょう。
$ virtctl expose vmi vm1 --name vm1s --type NodePort --port 27017 --target-port 22 Service vm1s successfully exposed for vmi vm1 $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.10.0.1 <none> 443/TCP 9h vm1s NodePort 10.111.13.242 <none> 27017:31677/TCP 5s
ポートを確認できましたので、ssh してみます。
$ ssh 192.168.122.214 -p 31677 -l root Last login: Sun Jul 21 12:18:02 2019 from 172.21.0.110 [root@vm1 ~]# [root@vm1 ~]# cat /etc/redhat-release Fedora release 30 (Thirty)
無事に ssh もできました。
missing label information for vm: vm1 が出てしまった人は vm (pod) に lable がついてないことが原因です。 Kubernetes の service は label をみて対象を決めているので lable がないと転送できません。
virtclt 側のコード{:target="_blank"} をみると以下の通りの記載があって virtctl 側でエラーを出すようになっています。
serviceSelector = vmi.ObjectMeta.Labels if len(serviceSelector) == 0 { return fmt.Errorf("missing label information for %s: %s", vmType, vmName) }
動作確認
launcher にログインしてみます。
$ kubectl exec -it virt-launcher-vm3-729lq /bin/bash [root@vm3 /]# [root@vm3 /]# [root@vm3 /]# [root@vm3 /]# ls augconf boot etc lib libvirtd.sh media opt root sbin sys usr bin dev home lib64 lost+found mnt proc run srv tmp var
ここで libvirtd や qemu が動いています。 ps aux | grep libvirtd など叩いてみましょう。
念のため、PV の確認もしましょう。適当なファイルを配置します。
[root@vm1 ~]# touch test [root@vm1 ~]# echo "test dayo" > test [root@vm1 ~]# [root@vm1 ~]# [root@vm1 ~]# cat test test dayo
vm1 を削除してみます。 virtctl 側に delete がないのかなと思ったら bugzilla{:target="_blank"} に記載がありました。
$ kubectl delete vm vm1 virtualmachine.kubevirt.io "vm1" deleted $ kubectl get vm No resources found.
virt-launcher-vm1 も消えています。 もう一度起動してみて確認します。
# ssh 192.168.122.214 -p 31677 -l root Last login: Mon Jul 21 12:53:57 2019 from 172.21.0.110 [root@vm1 ~]# ls test [root@vm1 ~]# cat test test dayo
無事に確認できました。Kubernetes の基本機能部分なので当たり前っちゃ当たり前なのですが。 一応、コンテナを強制停止や minikube を再起動してみたところ、Terminating->ContainerCreating > Running になりました。
実態として Kubernetes の pod として存在しているので、当然これらの Kubernetes の恩恵を享受できるのですが、それが嬉しいですね。 そうなると、 vm を作成するときの VirtualMachine リソースでどんなことが記述できるのかが気になるところですね。先ほどつけた label は pod (launcher) にも反映されているはずです。
explain してみれば楽かなと思いますが、 FIEDS がなかったです。残念。
$ kubectl explain VirtualMachine KIND: VirtualMachine VERSION: kubevirt.io/v1alpha3 DESCRIPTION: <empty>
その他
VirtualMachine ですが、nodeSelector
、 Affinity や Anti-Affinity
が pod と同様に利用できます。Taints と Tolerations
も利用できますので VM の配置は Kubernetes の pod と同様の考え方
で配置の制御ができます。
SR-IOV
とか VirtualMachineInstanceReplicaSet
リソースを試してみたいです。VirtualMachineInstanceReplicaSet がちゃんと動けば update がしやすいですし、HPA と合わせると AutoScale も容易
に実現できますね。Kubernetes ありがたやです。
feature-gates を有効すれば、Live-migration もできるようです。Node 1台なので試せていないのですが、VM だとやりたくなりますよね。
まとめ
冒頭に OpenStackもいらなくなる?と書いたのですが、 kubevirt を使えば 割といい線
いってるのかなと思いました。
ただ、現時点では プロダクション向けにバリバリ使うという印象ではない
です。
実際、検証していて起動時に VM が DHCP から IP 取得できないケースに何回か遭遇したりしました。
そもそも、従来の VM を Kubernetes のようなコンテナを扱うオーケストレータに乗せて共存させることで移行を加速するものと理解した方が良さそうです。
とはいえ、GCP や AWS には相応のコンピュートサービスがあると思いますが、オンプレでそういったサービスをどう提供する?と考えた時の 選択肢の一つに近い将来なりうるのかな
という印象です。
Kubernetes の機能が使えるので、この手の開発物は Kubernetes さえあれば準備するものが少なく済む
のは嬉しいですね。Kubevirt の GUI があると嬉しいかな・・・と思います。
結論としては、 今は厳しいが将来に期待
ってところでしょうか。今回で理解が深まりました。
とはいえ、将来はマイクロサービス化がもっと進んでそう。
Kubernetes完全ガイド (impress top gear)
- 作者: 青山真也
- 出版社/メーカー: インプレス
- 発売日: 2018/09/21
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Kubernetes実践ガイド クラウドネイティブアプリケーションを支える技術 (impress top gear)
- 作者: 北山晋吾,早川博
- 出版社/メーカー: インプレス
- 発売日: 2019/07/12
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
シェアして頂けると嬉しいです。
参考になったという方がいれば是非お願いしますm(_ _ )m
モチベーション維持の観点で非常に励みになります。