OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (1)

※2023年12月8日追記 記事タイトルに番号を振りました。

OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (1) <= 本記事
OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (2)

こんにちは、Red Hatでソリューションアーキテクトをしている石川です。 今回はOpenShift上でVMを構築し管理するOpenShift Virtualizationについて紹介したいと思います。

OpenShift VirtualizationはOSSのKubevirtをOpenShiftの機能の一つとして提供しているものです。
Kubevirtは2016年にRed Hatがプロジェクトを開始しOSSとして公開され、その後CNCFプロジェクトの一部となりました。現在はCNCFの中でIncubatingプロジェクトの一つとして位置付けられています。

そんなKubevirtですが今年に入り7月にバージョン1.0がリリースされました。
OSSプロジェクトとして安定、成熟してきており、ユーザーとしてもAppleやGoldman Sachs、NVIDIAなどの企業が名前を連ねています。 今年4月にアムステルダムで行われたOpenShift Commons Gatheringの中でもKubevirtについてRed HatとNVIDIAの方が実施したセッションが公開されているため興味がある方はご覧になってみて下さい。
www.youtube.com

またアップストリームの利用例だけでなく、OpenShift Virtualizationとしての利用も昨今増えつつあります。今年開催されたRed Hat Summitの中でもこうしたユーザー事例がいくつか取り上げられていますのでこちらも興味があればご覧下さい。 www.youtube.com

以降では、OpenShift Virtualizationを利用するメリットと、どのような仕組みでVMが起動するのかと、実際の利用方法を紹介していきたいと思います。

OpenShift Virtualizationを利用するメリット

OpenShift VirtualizationやKubevirtについて、そもそもなぜコンテナ環境上でVMを立てるのか、という点に疑問がある方もいるんじゃないかと思います。
ここについて理由は様々考えられますが、例えばシステムの大部分をコンテナ化しているが、一部についてはパッケージソフトウェアなどを利用しておりコンテナ化が難しくVMが残ってしまう、といったケースなどが考えられます。 勿論この時、既存のVM管理の仕組みを継続して使い続けることも考えられますが、ワークロードのほとんどがコンテナということであればKubernetesの仕組みを利用してVMを管理するという選択肢も出てくると考えられます。

OpenShift Virtualizationを利用してOpenShift環境上にVMを立てる場合、コンテナ基盤ならではの様々なメリットを受けることができます。

ネットワークと名前解決

VMで利用するネットワークは、OpenShiftで利用するCNI(デフォルトではOVN-Kubernetes)を通じて提供されます。
作成したVM上でホストされるアプリケーションには、Podと同様に、ServiceやRouteを通じてクラスタ内外からアクセスすることができます。そのため、同じクラスタ上のPodからVM上のアプリにアクセスする際にVMのIPアドレスを意識してアクセスするという必要が無くなります。
またVMへのアクセスを特定のPodからのみに制限したい場合には、NetworkPolicyを利用することができます。

Probe

Podと同様にVMでもReadinessProbeやLivenessProbeを活用したアプリの正常性確認を行うことができます。TCPやHTTPのProbeに加え、ゲストOSにqemu-guest-agentをインストールし有効化しておくことでexecコマンド実行によるProbeも利用することができます。

ストレージ

VMで利用するディスクはCSIを通じてPVとして提供されます。この時PVのアクセスモードとしてReadWriteOnce(RWO)やReadWriteMany(RWX)を選択することができますが、RWXを選択することでクラスタを構成するベアメタルノード間でVMのライブマイグレーションを実行することが可能となります。これにより例えばクラスタのアップグレードを行うような場合でも、その上で動くVMは無停止でアプリを実行することができます。ライブマイグレーションはOpenShift Virtualizationを利用する上で重要な機能となるため、利用するストレージがRXWに対応しているか確認すると良いでしょう。
その他にも利用するストレージの機能として提供されている場合、CSIを通じてVMのスナップショットを作成することもできます。

OpenShiftに統合されたVM管理コンソール

OSSのKubevirtではVMの運用をCLIやyamlファイルを適用することで実施しますが、OpenShift VirtualizationではOpenShiftコンソールの一部としてGUIを利用することができます。 そのため基本的な運用についてはGitOpsと組み合わせ自動化し、アドホックな操作についてはGUIで実施するなど、状況に応じて使い分けることができます。

ここで挙げた以外にも便利なポイントはありますが、それらについては適宜紹介していければと思います。

コンテナ基盤上でVMが動く仕組み

ここからはそもそもどうやってコンテナ基盤上でVMが動いているのかを解説していきたいと思います。 OpenShift Virtualizationでは、これまでRHEL等で実現していたのと同様に、KVMを利用しVMを作成し、管理します。そのため必要なコンポーネント(QEMU、libvirtなど)は変わりませんが、一部はPodとして動作することとなります。

まず以下にKubevirt Operatorがインストールされた状態を示します。

KubevirtのAPIを提供するVirt API Serverと、制御を行うVirt Controller、そしてVMを起動する各Worker Node上にはDaemonsetとしてVirt HandlerというPodが起動します。

VMを作成するため、まずVirtualMachineオブジェクトを作成します。VirtualMachineを作成すると、VMの実際の状態を表すVirtualMachineInstanceというオブジェクトが自動的に作成され、それを元にVirt Launcherと呼ばれるPodがWorker Nodeにスケジュールされ起動します。Virt Launcherは起動するVMと1:1の関係となります。 通常のPodと同様にkube-schedulerによりスケジューリングされるため、NodeSelectorやAffinity、Taint/Tolerentを設定することで、結果としてVMが起動するNodeをコントロールすることができます。

このVirt Launcherの中ではVMの操作に必要なlibvirtdやQEMUが実行されます。(上図では別々のコンテナのように見えますが、実際はVirt launcherコンテナの中でまとめて実行されます。) 各コンポーネントの役割については以下を参照下さい。 access.redhat.com


Virt Launcher Podが起動すると、起動したNodeの情報をVirt ControllerがVMIに対し追記します。ここまで完了すると、以降のVMIの変更はkubeletではなく、DaemonSetとして配置されたVirt Handlerにより監視され、Virt Handlerを経由しVirt Launcherに情報が渡されます。Virt Launcherは定義されたVMIの状態と一致するよう、libvirtのAPIを使用しVMの操作を行います。

ここまででコンテナ基盤上でVMを起動することができました。


VMを削除する場合、作成したVirtualMachineオブジェクトを削除します。するとそれに伴いVMIオブジェクトも削除され、Virt Handlerがその削除を検知し、対象のVirt Launcher Podの削除を行います。

OpenShift Virtualizationのインストールと準備

ここからはOpenShift上でOpenShift Virtualizationをインストールし、VMを起動したいと思います。 OpenShift Virtualizationを利用する場合、ベアメタルノードが必要となります。これまではオンプレミス環境でのベアメタルノードしかサポートの対象となりませんでしたが、最新のバージョンである4.14からはAWSのベアメタルノードも利用可能となりました。 docs.openshift.com

今回はAWS上にIPIでクラスターをインストールし、ノードの一つをベアメタルノード(インスタンスタイプ: c5.metal)とします。ノード間のライブマイグレーションを試したい場合は2つ以上のベアメタルノードを準備しましょう。

クラスターインストール手順は割愛しますが、今回検証を行ったクラスターの各ノードのスペックは以下の通りです。
Master Node: m6i.xlarge * 3
Infra Node: なし
Worker Node: m5.2xlarge * 3 + c5.metal * 1

OpenShift Data Foundationのインストール

AWSではEFSを使うことでRWXなPVを利用することができますが、OpenShift VirtualizationではEBS/EFSの利用はサポートされていません。そのためOpenShift Data Foundationをインストールし、RWXとして利用可能なStorageClassを準備したいと思います。

まずはOperator HubからODFを探しインストールしましょう。

ODFのインストールが完了するとStorageSystemの作成が要求されます。
Deploymentタイプとして"Full deployment"、バッキングストレージとして"gp3-csi"を選択します。

次に容量とノードの選択です。今回は検証用途となるため最小容量であるノードごと0.5TiBを選択し、デプロイ対象のノードを3つ選択します。

残りの設定項目はデフォルトのままStorageSystemを作成します。
しばらくすると必要なリソースが作成されODFで追加されたStorageClassが利用可能となります。

# oc get storageclass
NAME                                         PROVISIONER                             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2-csi                                      ebs.csi.aws.com                         Delete          WaitForFirstConsumer   true                   4h
gp3-csi (default)                            ebs.csi.aws.com                         Delete          WaitForFirstConsumer   true                   4h
ocs-storagecluster-ceph-rbd                  openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   11m
ocs-storagecluster-ceph-rbd-virtualization   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   11m
ocs-storagecluster-cephfs                    openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   11m
openshift-storage.noobaa.io                  openshift-storage.noobaa.io/obc         Delete          Immediate              false                  10m

この時デフォルトのStorageClassが"gp3-csi"のままとなっているため、annotationを変更し"ocs-storagecluster-ceph-rbd-virtualization"をデフォルトのStorageClassとします。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: ocs-storagecluster-ceph-rbd-virtualization
  --- (略) ---
  annotations:
    description: Provides RWO and RWX Block volumes suitable for Virtual Machine disks
    storageclass.kubevirt.io/is-default-virt-class: 'true'
    storageclass.kubernetes.io/is-default-class: 'true' # 追加
  --- (略) ---

"gp3-csi"の方のannotationも忘れずに変更しておきましょう。

OpenShift VirtualizationのインストールとVMの作成

続いてOpenShift VirtualizationをOperator Hubからインストールしましょう。

インストールが完了するとHyperConvergedというリソースの作成を求められます。 OpenShift VirtualizationではKubevirt Operatorだけでなく、VM管理に必要な複数のOperatorをインストールします。それらをまとめて設定し、管理するためのリソースがHyperConvergedです。

ここではデフォルトの設定のまま作成を行います。

HyperConvergedを作成し必要なリソースがデプロイされるとOpenShiftのコンソールからVirtualizationのタブを開くことができるようになります。

この時Overview画面の右上からVMの操作やSSHに使用する"virtctl"CLIのダウンロードをすることができるので、自身の環境に合うものをダウンロードし設定しておきましょう。

# curl -L -O https://hyperconverged-cluster-cli-download-openshift-cnv.apps.{クラスター名}.{ベースドメイン}/amd64/linux/virtctl.tar.gz

# tar xvf virtctl.tar.gz -C /usr/local/bin

VMの起動はこのvirtctlを使用するか、yamlを書いてデプロイするか、GUIを使うかから選択できます。 今回は手軽に実行するためにGUIからVMを起動したいと思います。画面左のタブから、Virtualization => Catalog を選択するとデフォルトで利用可能なVMのテンプレートが表示されるので、RHEL9のテンプレートを選択します。


Customize VirtualMachineを選択しVMのカスタマイズを行います。
ここで起動するVMの様々なパラメーターを設定することが可能です。LinuxについてはCloud-initスクリプトを使い起動時の設定を行うことができます。

今回はパスワードでSSHするためcloud-initに以下の設定を追加しました。検証以外の用途で使う場合は必ずSSHの公開鍵を登録するようにしましょう。

userData: |-
  #cloud-config
  user: cloud-user
  password: akabo-blog
  chpasswd: { expire: False }
  ssh_pwauth: true #追加

設定が完了したので"Create VirtualMachine"を押しVMを作成します。しばらく待つとVMが起動します。

それではこのVMに対しSSHしましょう。 以下のコマンドを実行します。"oc login"した状態で"virtctl ssh"を使用するとポートフォワードにより対象のVMへSSHできます。

# virtctl ssh --namespace test-kvirt2 --username cloud-user rhel9-akabo
The authenticity of host 'vmi/rhel9-akabo.test-kvirt2 (<no hostip for proxy command>)' can't be established.
ED25519 key fingerprint is SHA256:VRcNfaQ39FemkRzpzWACaAXgp1ROzwuYBwNFbxCQ4Xw.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'vmi/rhel9-akabo.test-kvirt2' (ED25519) to the list of known hosts.
cloud-user@vmi/rhel9-akabo.test-kvirt2's password: 
Register this system with Red Hat Insights: insights-client --register
Create an account or view all your systems at https://red.ht/insights-dashboard
[cloud-user@rhel9-akabo ~]$ 

無事SSHすることができました。 今回はこのVM上でnginxを起動し、Routeからアクセスしてみたいと思います。

VMにSSHした状態で以下を実行します。

## rootユーザーになりsubscription-managerに登録
# sudo su- 
# subscription-manager register

## nginxのインストールと起動
# yum install -y nginx
# systemctl enable --now nginx

## 確認
# systemctl status nginx

ここまでできたらSSHを抜け、Service、Routeを作成します。 Serviceは"virtctl expose"で簡単に作成できます。

# virtctl expose vmi rhel9-akabo --name vm-svc --port 27017 --target-port 80
Service vm-svc successfully exposed for vmi rhel9-akabo

# oc get svc
NAME     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
vm-svc   ClusterIP   172.30.11.182   <none>        27017/TCP   25s

# oc expose svc/vm-svc
route.route.openshift.io/vm-svc exposed

公開されたRouteにアクセスすると無事VM上でホストされるnginxにアクセスできました。

まとめ

今回はOpenShift Virtualizationについて紹介しました。ベアメタルサーバーの準備など、試すのには若干のハードルがありますが、機能としては非常に面白いんじゃないかと思います。 またより詳しい機能の紹介などしていければと思います。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。