libvirt and Terraform - Finally!

Thursday, June 22, 2017

Some time ago I wrote a post about the unlove that generally befalls libvirt. When I migrated my site over to Hugo I didn’t bring the post along, because it was basically a long winded diatribe about the lack of support in the devops community for libvirt. Although still not officially supported, lots of work has been done to add support to Terraform for using libvirt with the terraform-provider-libvirt project. As of a few weeks ago I got this set up and working, with relative ease I might add, and wanted to share how I got it working.

Before you can do anything, first the plugin needs to be compiled. Once compiled place the binary someplace where it won’t get removed (I personally don’t like keeping the binarys in my go/bin folder). Then create (or append) your .terraformrc in your home directory with the following:

providers {
  libvirt = "/location/of/binary/terraform-provider-libvirt"
}

The next step depends on your infrastructure. If you are running Terraform and having it provision on a remote hypervisor (like I am), then you need to make sure that you have SSH key-based authentication working, and that the user you log in as can access and run either virt-manager or virsh. If not, then Terraform won’t be able to connect to the remote hypervisor and your applies will fail. Once this is setup and working however, you can define your provider.tf as follows:

provider "libvirt" {
  uri = "qemu+ssh://user@ip.add.re.ss/system"
}

You will notice that Terraform is using ssh to connect to the remote instance, which is why SSH key-based authentication is so important. Although I haven’t tried it without key-based authentication, by logging in and unlocking your key it makes for a simple (and secure) authentication mechanism.

The last bit of setup you will need to do before this all works is to manually create a base image for your operating systems. This will be the base image that Terraform uses to build your new VMs, and should be just that, a base image. I generally use CentOS7 on my servers, so I just spun up a CentOS7 VM, walked through the installation, and then deleted the VM while keeping the resulting qcow2 image. Once that base image is ready, and the other above steps are done, it’s time to create the Terraform configuration:

resource "libvirt_volume" "test_disk" {
  name                  = "test.qcow2"
  pool                  = "VMs"
  base_volume_name      = "base_centos7.qcow2"
}

resource "libvirt_domain" "test" {
  name                  = "test"
  vcpu                  = 1
  memory                = 1024
  running               = "true"

  disk {
    volume_id           = "${libvirt_volume.test_disk.id}"
    scsi                = "yes"
  }

  network_interface {
    bridge              = "br0"
  }
}

If you are familiar with Terraform the above will be pretty familiar. First we setup a new volume for the VM, set the name, and tell it the base volume to use. Then we define the libvirt domain with the CPU, Memory, and Volume information. The network setup may vary depending upon your specific needs and requirements. My setup is using a bridged interface on br0 and as such I only define a bridge. There are additional settings for different networking should you need it here.

And that’s pretty much it! I am super happy to see the progress on this plugin, as I still strongly believe in libvirt as an enterprise ready hypervisor. Now with the added ability to use a Infrastructure as Code tool such as Terraform I think it only stregthens this position.

devopsterraformlinuxlibvirt

Infrastructure Change - Enter CircleCI

My Local Kubernetes Cluster