1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【OpenShift Virtualization】仮想マシンにGitOpsを求めるのは間違っているだろうか

Last updated at Posted at 2024-07-11

出落ち

image.png

間違っていない

アリストテレス的三段論法にて示します。

  • KubeVirt / OpenShift Virtualizationでは、仮想マシン(VM)をKubernetesの上で扱うことができる。
  • 故にVMをKubernetesのリソースとしてYAMLファイルで表現できる。
  • よってVMのGitOpsは寧ろ推進されるべき営みである。

各種CustomResourceについて

KubeVirt / OpenShift Virtualizationの中で仮想マシンを管理する上で必要なCustomResourceDefinitionについて以下、軽く説明します。

DataVolumeCRD

仮想マシンのルートボリューム(rootdisk)を定義するCRDです。今回使うYAMLを示します。

vm-datavolume.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: fedora-datavolume
spec:
  source: #OSイメージの在り処を指定します。今回はURL直指定です。
    http:
      url: https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2
  pvc: #永続ボリュームのスペックをPVCの書式に従って記載します
    accessModes:
      - ReadWriteMany
    volumeMode: Block
    storageClassName: ocs-storagecluster-ceph-rbd-virtualization
    resources:
      requests:
        storage: 30Gi

聞き慣れないリソースなので難しいと感じてしまうかもしれませんが、中身を見るととても簡単です。DataVolumeでは主に2つの要素を定義します。

ひとつはsourceです。ゲストマシンのOSイメージの在り処(取得先)を指定します。今回はFedoraプロジェクトがホームページで公開している「KVM仮想環境向けのイメージ(QCOW2形式)」のダウンロードURLを直接指定します。

QCOW2形式についての詳細はこちらを御覧ください

sourceは今回の場合はhttp.urlとしていますが、既にDeploy済みの仮想マシンのDataVolumeから作成されたPersistentVolumeClaimを指定したり、仮想マシンのスナップショットを指定したりもできます。
ちなみに、source部分だけを更にDataSourceというCRDで外だしして記載することも可能ですが、今回はやりません。

次にpvcです。これは仮想マシンの永続ボリューム要求をPersistentVolumeClaimの書式そのままを記載します。storageClassaccessModes(仮想マシンをLive Migrationさせたい場合はReadWriteManyでのProvisioningが必須です)等を指定します。

VirtualMachine CRD

Kubernetes上の仮想マシンインスタンス(VMI)は、CustomResourceDefinitionである、文字通りVirtualMachineによって定義されます。コンテナアプリケーションでいうところのDeploymentに近しい存在かと私個人は理解しており、VirtualMachineからvirt-launcher(VMが起動しているコンテナを内包するPod)等のリソースが作成されます。

今回使うManifestを以下に示します。

vm-example.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-example
  labels:
    app: vm-example
    os.template.kubevirt.io/fedora: 'true'
spec:
  running: true #仮想マシン作成時の挙動を指定します。trueにすると作成後、自動的に起動します。
  template:
    metadata:
      labels:
        app: vm-example #VMに付与するlabelです。Serviceと紐づける為に付与しておきます
        kubevirt.io/domain: vm-example
    spec:
      accessCredentials: #SSH公開鍵との紐づけを設定します
        - sshPublicKey:
            propagationMethod:
              noCloud: {}
            source:
              secret: #public-key.yamlというSecretファイルに公開鍵情報を盛り込んでいます
                secretName: public-key
      domain:
        cpu: #仮想マシンにアロケーションするCPUリソースを定義します
          cores: 1
          sockets: 1
          threads: 1
        devices: #仮想マシンに接続する仮想デバイスを定義します
          disks:
            - disk:
                bus: virtio
              name: rootdisk #rootdiskとしてVirtIOデバイスを指定します
            - disk:
                bus: virtio
              name: cloudinitdisk #仮想マシン起動時の設定(cloud-init)を実行する為のディスクを定義します
          interfaces:
            - name: eth0 #Podに最初から付与されているvNIC(eth0)の名称です。任意のものに変更できます
              masquerade: {} #eth0は必ずmasqueradeに指定してください。
              macAddress: '02:c7:36:00:00:2b' #eth0に指定したいMACアドレスを記載します
              model: virtio
        memory: #仮想マシンにアロケーションするメモリを定義します
          guest: 2Gi
      hostname: vm-example
      networks: #仮想マシンインスタンスのvNICが接続するNWの定義を記載します
        - name: eth0 #eth0という名称のvNICをKubernetesのPod Network(デフォルトのOverlay Network)に参加させます。これは必須の設定です
          pod: {}
      volumes:
        - name: rootdisk #rootdiskとしてDataVolume名を参照しています
          dataVolume:
            name: vm-datavolume
        - name: cloudinitdisk #cloud-init設定内容を実行するディスク
          cloudInitNoCloud: #cloud-initの書式に従って記載された内容を実行します
            secretRef: #cloud-init設定内容をuserdata-secret.yamlに記載しています
              name: userdata-secret

spec.template.spec.volumesで2つのボリューム(仮想ディスク)を指定しています。rootdiskは先程示したDataVolumeそのものになります。cloudinitdiskは仮想マシン起動時の初期設定(cloud-init)をディスクとしてマウントするものです。中にはユーザ/パスワード情報を含むcloud-initで設定可能な情報を記載しますので、センシティブな情報です。VirtualMachineYAML自体に記載することも可能ですが、別にSecretファイルを用意したほうがよさそうです。なお、今回の設定内容は以下のとおりです。

   #cloud-config
   user: cloud-user
   password: cloud-password
   chpasswd:
      expire: false
   ssh_pwauth: true
   runcmd:
     - sudo yum install httpd -y
     - sudo systemctl start httpd.service

Fedora OSのユーザ/パスワード情報を記載しています。また、以下の記事でも触れているのですが、起動時に特定のコマンドを実行しています。今回はApacheをインストールし、Webサーバの起動をしています。

この内容をuserdata-secret.yamlに記載しています。

userdata-secret.yaml
kind: Secret
apiVersion: v1
metadata:
  name: userdata-secret
data:
  userData: I2Nsb3VkLWNvbmZpZw0KdXNlcjogY2xvdWQtdXNlcg0KcGFzc3dvcmQ6IGNsb3VkLXBhc3N3b3JkDQpjaHBhc3N3ZDoNCiAgZXhwaXJlOiBmYWxzZQ0Kc3NoX3B3YXV0aDogdHJ1ZQ0KcnVuY21kOg0KICAtIHN1ZG8geXVtIGluc3RhbGwgaHR0cGQgLXkNCiAgLSBzdWRvIHN5c3RlbWN0bCBzdGFydCBodHRwZC5zZXJ2aWNl
  #以下のcloud-configをBASE64エンコードしたものを`userData`に記載します
    #cloud-config
   #user: cloud-user
   #password: cloud-password
   #chpasswd:
      #expire: false
   #ssh_pwauth: true
   #runcmd:
     #- sudo yum install httpd -y
     #- sudo systemctl start httpd.service

cloud-initについてはこの記事が大変参考になりました!

用意しているYAML一覧

以下の通りの構成としています。

root/
 ├ app-of-apps/
 | └ application.yaml  
 ├ applications/
 | ├ namespace-application.yaml
 | ├ configs-application.yaml
 | ├ datavolume-application.yaml
 | └ virualmachine-application.yaml
 └ manifest/
   ├ namespace/
   | └ vm-namespace.yaml
   ├ configs/
   | ├ public-key
   | ├ userdata-secret.yaml
   | ├ vm-route.yaml
   | └ vm-service.yaml
   ├ datavolume/
   | └ vm-datavolume.yaml
   └ virtualmachine/
     └ vm-example.yaml

複数のManifestを順序を意識してApplyしたい(例:まずはNameSpaceのManifestからApplyしたい、DataVolumeVirtualMachineよりも先にDeployしたい 等)ので、「app of apps pattern」を取り入れています。親Applicationから子Applicationをsync-waveの順序でApplyしていく様に設計しています。これにより、Manifestの適用順序をコントロールします。

以下に全てのファイルの中身を貼ります。
まずは親/子Applicationです。

app-of-apps/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: app-of-apps
  namespace: openshift-gitops
spec:
  destination:
    namespace: openshift-gitops
    server: 'https://kubernetes.default.svc'
  source:
    path: applications
    repoURL: >-
      https://<your_git_repositry_url>
    targetRevision: main
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
applications/namespace-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: namespace
  namespace: openshift-gitops
  annotations:
    argocd.argoproj.io/sync-wave: "1"
spec:
  destination:
    namespace: vm-example
    server: 'https://kubernetes.default.svc'
  source:
    path: manifest/namespace
    repoURL: >-
      https://<your_git_repositry_url>
    targetRevision: main
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - ApplyOutOfSyncOnly=true
applications/configs-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: configs
  namespace: openshift-gitops
  annotations:
    argocd.argoproj.io/sync-wave: "2"
spec:
  destination:
    namespace: vm-example
    server: 'https://kubernetes.default.svc'
  source:
    path: manifest/configs
    repoURL: >-
      https://<your_git_repositry_url>
    targetRevision: main
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - ApplyOutOfSyncOnly=true
applications/datavolume-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: datavolume
  namespace: openshift-gitops
  annotations:
    argocd.argoproj.io/sync-wave: "3"
spec:
  destination:
    namespace: vm-example
    server: 'https://kubernetes.default.svc'
  source:
    path: manifest/datavolume
    repoURL: >-
      https://<your_git_repositry_url>
    targetRevision: main
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - ApplyOutOfSyncOnly=true
applications/virualmachine-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: virtualmachine
  namespace: openshift-gitops
  annotations:
    argocd.argoproj.io/sync-wave: "4"
spec:
  destination:
    namespace: vm-example
    server: 'https://kubernetes.default.svc'
  source:
    path: manifest/virtualmachine
    repoURL: >-
      https://gitlab.com/masaki-oomura/openshift-virt-argocd.git
    targetRevision: main
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - ApplyOutOfSyncOnly=true

次に各Manifestです。これらはステートレスなリソースを生成します。

manifest/namespace/vm-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: vm-example
  labels:
    argocd.argoproj.io/managed-by: openshift-gitops #Argo CDインスタンス(openshift-gitops)から管理できる為に必要なlabelです
manifest/configs/public-key.yaml
kind: Secret
apiVersion: v1
metadata:
  name: public-key
data:
  key: <公開鍵(id_rsa.pub)の中身をBASE64エンコードしたもの>
type: Opaque
manifest/configs/userdata-secret.yaml
kind: Secret
apiVersion: v1
metadata:
  name: userdata-secret
data:
  userData: I2Nsb3VkLWNvbmZpZw0KdXNlcjogY2xvdWQtdXNlcg0KcGFzc3dvcmQ6IGNsb3VkLXBhc3N3b3JkDQpjaHBhc3N3ZDoNCiAgZXhwaXJlOiBmYWxzZQ0Kc3NoX3B3YXV0aDogdHJ1ZQ0KcnVuY21kOg0KICAtIHN1ZG8geXVtIGluc3RhbGwgaHR0cGQgLXkNCiAgLSBzdWRvIHN5c3RlbWN0bCBzdGFydCBodHRwZC5zZXJ2aWNl
  #以下のcloud-configをBASE64エンコードしたものを`userData`に記載します
    #cloud-config
   #user: cloud-user
   #password: cloud-password
   #chpasswd:
      #expire: false
   #ssh_pwauth: true
   #runcmd:
     #- sudo yum install httpd -y
     #- sudo systemctl start httpd.service
manifest/configs/vm-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: vm-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  selector: 
    app: vm-example
  clusterIP: None
manifest/configs/vm-route.yaml
kind: Route
apiVersion: route.openshift.io/v1
metadata:
  name: vm-route
spec:
  to:
    kind: Service
    name: vm-service
  port:
    targetPort: 80

Fedora VMにApacheをインストールしてWebサーバとしてインターネット公開するためには、ServiceRouteが必要ですので、それも一緒にApplyしてしまいます。

最後にDataVolumeVirtualMachineです。こちらは上述の再掲。

manifest/datavolume/vm-datavolume.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: fedora-datavolume
spec:
  source: #OSイメージの在り処を指定します。今回はURL直指定です。
    http:
      url: https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2
  pvc: #永続ボリュームのスペックをPVCの書式に従って記載します
    accessModes:
      - ReadWriteMany
    volumeMode: Block
    storageClassName: ocs-storagecluster-ceph-rbd-virtualization
    resources:
      requests:
        storage: 30Gi
manifest/virtualmachine/vm-example.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-example
  labels:
    app: vm-example
    os.template.kubevirt.io/fedora: 'true'
spec:
  running: true #仮想マシン作成時の挙動を指定します。trueにすると作成後、自動的に起動します。
  template:
    metadata:
      labels:
        app: vm-example #VMに付与するlabelです。Serviceと紐づける為に付与しておきます
        kubevirt.io/domain: vm-example
    spec:
      accessCredentials: #SSH公開鍵との紐づけを設定します
        - sshPublicKey:
            propagationMethod:
              noCloud: {}
            source:
              secret: #public-key.yamlというSecretファイルに公開鍵情報を盛り込んでいます
                secretName: public-key
      domain:
        cpu: #仮想マシンにアロケーションするCPUリソースを定義します
          cores: 1
          sockets: 1
          threads: 1
        devices: #仮想マシンに接続する仮想デバイスを定義します
          disks:
            - disk:
                bus: virtio
              name: rootdisk #rootdiskとしてVirtIOデバイスを指定します
            - disk:
                bus: virtio
              name: cloudinitdisk #仮想マシン起動時の設定(cloud-init)を実行する為のディスクを定義します
          interfaces:
            - name: eth0 #Podに最初から付与されているvNIC(eth0)の名称です。任意のものに変更できます
              masquerade: {} #eth0は必ずmasqueradeに指定してください。
              macAddress: '02:c7:36:00:00:2b' #eth0に指定したいMACアドレスを記載します
              model: virtio
        memory: #仮想マシンにアロケーションするメモリを定義します
          guest: 2Gi
      hostname: vm-example
      networks: #仮想マシンインスタンスのvNICが接続するNWの定義を記載します
        - name: eth0 #eth0という名称のvNICをKubernetesのPod Network(デフォルトのOverlay Network)に参加させます。これは必須の設定です
          pod: {}
      volumes:
        - name: rootdisk #rootdiskとしてDataVolume名を参照しています
          dataVolume:
            name: vm-datavolume
        - name: cloudinitdisk #cloud-init設定内容を実行するディスク
          cloudInitNoCloud: #cloud-initの書式に従って記載された内容を実行します
            secretRef: #cloud-init設定内容をuserdata-secret.yamlに記載しています
              name: userdata-secret

では早速、以下の要件を満たすOpenShiftクラスタにて、application.yamlを適用してみます。

  • OpenShift Virtualizationが利用できる
  • OpenShift Data Foundationが利用できる
  • OpenShift GitOpsが利用できる

Red Hatのサポート対象外ではありますが、こちらの記事のROSA(Red Hat OpenShift Service on AWS)で上記が実現可能です。

image.png

app of appsの親Applicationを貼っつけて「CREATE」をクリック。
しばらく待つと全てのApplicationのステータスがHealthyになります。

image.png

OpenShiftのコンソール画面でDeployされた仮想マシンを確認してみます。
image.png

無事にDeployできました。「リソース」タブからRouteのURLにアクセスしてみます。
image.png

期待通り、Feroda VMがWebサーバとして公開されています。最後にVMにSSHしてみます。

 ~ % virtctl -n vm-example ssh cloud-user@vm-example --identity-file=~/.ssh/id_rsa
[cloud-user@vm-example ~]$ 

SSHで接続できました。

仮想マシンへのSSHについてはこちらを参照ください

おわりに

この様に、仮想マシンのDeployがGitOpsで実現できるようになりました。今回はNameSpace内に単一のVMアプリケーションのみをDeployしましたが、GitOpsを活用できるということは、コンテナアプリケーションも混在してDeployすることが可能になります。KubeVirt / OpenShift Virtualizationによって、アプリケーションがコンテナで作られていても、VMであっても、一体的にリソース管理・Deployし、Immutable Infrastructureを推進できます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?