メモ - RyuSA

技術的なメモ書きとか試してみたこと

Rancher Harvesterを使っておうちHCIを構築する話

HarvesterはRancher社が管理しているKubernetes上でHCIを構築するツールです

github.com

自宅で若干持て余している計算資源を使ってHarvesterをインストールし、Hyper-Converged Infrastructureをおうちに構築してみます

f:id:RyuSA:20210822132354p:plain
Harvesterのダッシュボード、バージョン0.2とはいえ非常にかっこいい

Hyper-Converged Infrastructure

通称HCI、これはサーバーの仮想化技術のひとつで、計算資源やネットワーキング、ストレージなどをソフトウェアベースで管理できるようにした製品のことを指すらしいです。

ja.wikipedia.org

いろいろなアプライアンス製品があるそうですが、残念ながら自分はHCI製品に触れたことがないので細かい解説ができないため詳細はWiki先生を参照ください。 詰まるところ、HCI製品を利用すると簡易なオレオレAWS/GCPが作れるといったところでしょうか?

Harvester

冒頭に話をした通り、HarvesterはRancher社がメンテナンスしているHCI製品です。Kubernetesのエコシステムをフルに活用しながら、Rancher製品をうまく組み合わせてHCIを実現しています。

Harbesterが利用しているツールとしては

  • 計算資源管理: KubeVirt
  • ネットワーク管理: Multus CNI, VLAN Plugin
  • ストレージ管理: Longhorn

が挙げられます。

Harvesterを使ってみる

実際にHarvesterをインストールして仮想マシンを作成してみます。今回の検証環境は下記の通りです。

  • 物理サーバー
    • 第6世代 Intel NUC NUC6i5SYH
  • Harvester
    • 0.2.0

ISOインストール

Harvesterはインストール方法にISOによるフルインストール(直接インストールとPXEインストールが選択可能)と既存のKubernetesにインストールするRun as Appの2種類があります。今回はまず動かしてみるということでISOを直接物理サーバーにインストールしていきます。

ISOダウンロード〜インストール完了

GithubのreleaseからISOをダウンロードしてきます。

github.com

ダウンロードしてきたISOを適当なUSBメモリに焼き込み、物理サーバーにインストールしていきます。インストール中いくつかオプションの指定ができますが、今回はすべてデフォルト値のまま進みます。

f:id:RyuSA:20210822133036p:plain
参照: https://github.com/harvester/harvester/blob/master/docs/assets/iso-install.png

トラブルなくスムーズにインストールが完了するとHarvesterのコンソールが表示されます。

f:id:RyuSA:20210822133624p:plain
Harvesterのコンソール、かっこいい

仮想マシンの起動

さっそく仮想マシンを起動してみます。コンソールに指定されているアドレスにアクセスしてダッシュボードを開きます。

f:id:RyuSA:20210822132354p:plain
Harvesterダッシュボード

仮想マシンを作成するには、事前にインストールするISOファイルとネットワークの設定が必要です。

今回はお試しにUbuntu20.04のISOを用意することに。ISOのURLを指定することになるので、ubuntu.comのURLをそのまま指定します。 ImagesタブのCreateボタンからImageの作成をします。

f:id:RyuSA:20210822143500p:plain
ImageのURLにubuntuのISOのURLを指定する

次に仮想ネットワーク、VLANを作成します。NetworksタブのCreateボタンからNetworkの作成をします。

f:id:RyuSA:20210822143717p:plain
Network作成、VLAN IDは適当に指定

これで仮想サーバーを作成する準備できました。実際に仮想マシンを作成してみます。 Virtual MachinesタブのCreateボタンから仮想マシンを作成します。今回はお試しということで、先ほど登録したUbuntuのISOとVLANを利用することにします。

f:id:RyuSA:20210822144027p:plain
仮想マシン自体の設定、デフォルトのテンプレートを使用してます

f:id:RyuSA:20210822144156p:plain
Multus CNIのおかげでPodに複数のNICが渡ります

Createボタンを押すと実際にサーバーが起動し、HarvesterのWebConsoleからUbuntuのインストール画面へアクセスすることができました。 いやーこれは非常に楽ですね!

f:id:RyuSA:20210822144520p:plain
仮想マシンのPodのNICが増え、ホスト側のネットワークから直接Podへのリーチャビリティが生まれてます

少し覗いてみる

少し動きについてみてみます。とりあえずPodの状態を確認。

~
❯ kubectl get pods                                                                                    
NAME                              READY   STATUS    RESTARTS   AGE
virt-launcher-vlan-sample-4bssz   1/1     Running   0          23h

Podの名前から見て、どうもこのPodが先ほど作成した仮想マシン本体のようです。KubeVirtの文字が輝いてますね。 でこのPodのownerReferenceを見てみると下記の通り

❯ kubectl get pods -o json virt-launcher-vlan-sample-4bssz  | jq .metadata.ownerReferences 
[
  {
    "apiVersion": "kubevirt.io/v1",
    "blockOwnerDeletion": true,
    "controller": true,
    "kind": "VirtualMachineInstance",
    "name": "vlan-sample",
    "uid": "d3cab107-362b-4dfa-a0e7-122457f719ac"
  }
]

なるほど、この仮想マシンはkubevirt.io/v1のVirtualMachineInstanceで作成されているとのこと。 Harvesterの領域ではなくKubeVirtの領域になりますがもう少し深掘りしてみます。このVirtualMachineInstanceのownerReferenceを覗いてみると下記の通り

❯ kubectl get VirtualMachineInstance -o json vlan-sample | jq .metadata.ownerReferences
[
  {
    "apiVersion": "kubevirt.io/v1",
    "blockOwnerDeletion": true,
    "controller": true,
    "kind": "VirtualMachine",
    "name": "vlan-sample",
    "uid": "b6d42e46-0004-47a3-a86d-78411d878cfc"
  }
]

つまりVirtualMachineを作成することでVirtualMachineInstanceが作成され、そのVirtualMachineInstanceに合わせてPodが起動する感じでしょうか? kubectl explainで覗いてみる限り

という関係性っぽいですね。なるほどー

コードを読んでみると、どうもHarvesterはどんなVirtualMachineオブジェクトでも管理対象とするみたいですね。つまりマニュアルで仮想マシンを作ることができそうかな……?

github.com

ためしに下記のようなマニフェストで作成してみます。(ちょっと長い)

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: manual-vm
spec:
  running: true
  dataVolumeTemplates:
  - apiVersion: cdi.kubevirt.io/v1beta1
    kind: DataVolume
    metadata:
      annotations:
        harvesterhci.io/imageId: default/image-9dk4s
      name: manual-vm-cdrom-disk
    spec:
      pvc:
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 10Gi
        storageClassName: longhorn-image-9dk4s
        volumeMode: Block
      source:
        blank: {}
  - apiVersion: cdi.kubevirt.io/v1beta1
    kind: DataVolume
    metadata:
      name: manual-vm-rootdisk
    spec:
      pvc:
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 10Gi
        storageClassName: longhorn
        volumeMode: Block
      source:
        blank: {}
  template:
    metadata:
      annotations:
        harvesterhci.io/diskNames: '["manual-vm-rootdisk","manual-vm-cdrom-disk"]'
        harvesterhci.io/sshNames: '["github.com"]'
      labels:
        harvesterhci.io/creator: RyuSA
        harvesterhci.io/vmName: manual-vm
    spec:
      domain:
        cpu:
          cores: 1
        devices:
          disks:
          - bootOrder: 2
            cdrom:
              bus: sata
            name: cdrom-disk
          - bootOrder: 1
            disk:
              bus: virtio
            name: rootdisk
          - disk:
              bus: virtio
            name: cloudinitdisk
          interfaces:
          - macAddress: 52:54:00:57:4c:53 #適当
            masquerade: {}
            model: virtio
            name: default
          - bridge: {}
            macAddress: 2e:61:8d:3d:35:4c #適当
            model: virtio
            name: vlan
        machine:
          type: q35
        resources:
          requests:
            memory: 2Gi
      evictionStrategy: LiveMigrate
      hostname: manual-vm
      networks:
      - name: default
        pod: {}
      - multus:
          networkName: example-vlan
        name: vlan
      volumes:
      - dataVolume:
          name: manual-vm-cdrom-disk
        name: cdrom-disk
      - dataVolume:
          name: manual-vm-rootdisk
        name: rootdisk
      - cloudInitNoCloud:
          userData: |
            #cloud-config
            ssh_authorized_keys:
              - >-
                ssh-rsa (snip)
        name: cloudinitdisk

これでkubectl createでオブジェクトを作成してみると

f:id:RyuSA:20210823222659p:plain
Cliでも仮想マシンを作成できた

一部の部分(labelやannotation)のお作法さえ守れば、しっかり動きますね。まぁできたからと言ってなにか良いことがあるわけではないのですが……w

まとめ

Harvesterを利用して、Kubernetesクラスタ上にHCIを構築して仮想マシンKubernetesリソースベースで作成してみました。HarvesterのGUIで指定できる項目がまだ少なかったりしましたが、簡単な用途であれば現在のバージョンでもいい感じに動かせると思います。

本当は既存のKubernetes上にデプロイすることまでやりたかったのですが、手元にあるKuberenetesクラスターはRaspberry Piで構築していたため今回は断念。 というのもKubeVirtのARM64のサポートはまだ完成しておらず、それに引きずられてHarvesterのARM64サポートはこれからの状態です。

github.com

なので、気長に待ちつつ、可能なら貢献して行こうかなと思います。