Manage OpenShift virtual machines with GitOps

Learn how to utilize GitOps in OpenShift to manage your virtual machines (VMs).

So far we’ve configured our repository and populated that repo with our virtual machine that we intend to manage with GitOps. We’ve discussed some things to keep in mind while implementing this approach and briefly touched on the contents of the overlays we’ll use. Now let’s discuss the files contained within the dev and prod directories. Then we’ll put everything in motion.

In order to get full benefit from taking this lesson, you need to:

  • Have completed Lessons 1 and 2, or created your own infrastructure based on them.

In this lesson, you will:

  • Create the Argo CD application.
  • Create and start virtual machines in OpenShift Virtualization.

Customize virtual machines using YAML files

Now that everything is in place for our VMs to be created, let’s briefly discuss the files that are in the prod and dev directories. 

For this demonstration, there are three files in each directory: config.yamlkustomization.yaml, and dev-vm-patch.yaml or prod-vm-patch.yaml. Let’s take a look at their contents and functions below.

kustomization.yaml - This file defines what resources are to be used and applies them accordingly. In our environments, it will prefix the names of the virtual machines, pull configuration data from the config.yaml file, and apply the patches listed in the appropriate section from the specified file. Below are the contents of the file:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

namePrefix: dev-

configurations:
  - config.yaml

patches:
  - path: dev-vm-patch.yaml 
    target:
      kind: VirtualMachine

config.yaml  - This file is used to modify the VM files during creation based on the resources defined in the kustomization file and referred to in the base directory. It will change the name of the PVC that is created to match the virtual machine name and change the labels of the machine based on the VM name, plus the environmental prefix of dev- or prod-. See below:

# Change PVC claim name based on vm name
nameReference:
- kind: PersistentVolumeClaim 
  version: v1
  fieldSpecs:
  - kind: VirtualMachine
    path: spec/template/spec/volumes/persistentVolumeClaim/claimName 

# Change labels based on VM name WITH prefix. Note that the escape character is not a typo and must be included.
- kind: VirtualMachine
  version: v1
  fieldSpecs:
    - kind: VirtualMachine
      path: spec/template/metadata/labels/kubevirt.io\/domain
 
- kind: VirtualMachine
  version: v1
  fieldSpecs:
    - kind: VirtualMachine
      path: metadata/labels/app

dev-vm-patch.yaml and prod-vm-patch.yaml - Lastly, these are files where we can modify the specifications of the virtual machines during creation and afterward. It is important to note that although some fields are immutable, typical hardware specs for virtual machines can be modified. For this learning path, we’re patching the base virtual machines in two ways: the prod VM will have 8GB of RAM instead of 4GB like dev, and setting both virtual machines to running: true so they start up when we synchronize them after creating our Argo CD application. The changes shown below are for the prod VM only:

- op: replace
  path: /spec/template/spec/domain/memory/guest
  value: 8192M
- op: replace
  path: /spec/running
  value: true

Create the Argo CD application and synchronize the virtual machines

Everything should now be in place to take our final steps. First, we’ll create a simple YAML file to apply that will create the application in Argo CD. Then we’ll synchronize the application, which will kick off the virtual machine creation. This can be done from either the command line or the Argo CD UI. For the sake of simplicity, we’ll use the CLI with a couple of commands.

The code for our Argo application is pretty straightforward and can be copied from below, but be sure to change the applicable fields to your environment:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cnv-gitops-vms
  namespace: openshift-gitops
spec:
  destination:
    namespace: beehive-virtual-machines 
    server: https://kubernetes.default.svc
  project: default
  source:
    path: overlays
    repoURL: https://your-repository-url.git
    targetRevision: main
  syncPolicy:
    syncOptions:
    - CreateNamespace=true

Now apply the file and create the Argo application:

oc apply -f ~/vm-argo.yaml 
application.argoproj.io/cnv-gitops-vms created

After the creation of the application, we synchronize it, which will kick off the virtual machine creation. The command and its output are below, with some output omitted due to length:

argocd app sync cnv-gitops-vms
Name:               openshift-gitops/cnv-gitops-vms
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          beehive-virtual-machines
URL:                https://openshift-gitops-server-openshift-gitops.apps.beehive.example.org/applications/cnv-gitops-vms
Repo:               https://github.com/baromm14/gitops-virt-ocp-alternate.git
Target:             main
Path:               overlays
SyncWindow:         Sync Allowed
Sync Policy:        <none>
Sync Status:        Synced to main (ce3778c)
Health Status:      Progressing

Operation:          Sync
Sync Revision:      ce3778c8515e7aa88fa429e7729244805579a0fd
Phase:              Succeeded
Start:              2024-08-30 15:31:03 -0400 EDT
Finished:           2024-08-30 15:31:05 -0400 EDT
Duration:           2s
Message:            successfully synced (all tasks run)

As you can see, the application has successfully synchronized. Let’s check on our virtual machines using a simple oc get vm command:

oc get vm -n beehive-virtual-machines
NAME                     AGE     STATUS    READY
dev-base-vm              2m36s   Running   True
prod-base-vm             2m36s   Running   True

Alternatively, the following command will search for a name within the YAML output of our prod VM to show a few more details (some output was omitted for brevity):

oc get vm -n beehive-virtual-machines prod-base-vm -o yaml | grep -i name
name: prod-base-vm
  namespace: beehive-virtual-machines
            name: vm-rootdisk
            name: cloudinitdisk
            name: default
      - name: default
      - name: vm-rootdisk
          claimName: prod-base-vm-disk
        name: cloudinitdisk
    name: vm-rootdisk
    name: cloudinitdisk

Summary

Combining GitOps with Red Hat OpenShift Virtualization offers improved consistency, better collaboration, and a solid foundation for redundant infrastructure. By applying software practices to your infrastructure, the benefits of a version control system can be realized in all of your computing environments, not only in software development. This learning path has showcased some best practices of implementing GitOps and demonstrated how to start down the path toward having an agile infrastructure.

Want to learn more? Try these:

Previous resource
Create and customize virtual machine files within the repository