How to use terraform with proxmox

Terraform and Proxmox

What is terraform?

Terraform is an open-source infrastructure as code software tool created by HashiCorp. It enables users to define and provision a datacenter infrastructure using a high-level configuration language known as Hashicorp Configuration Language, or optionally JSON.

How to install terraform?

You can find installation instructions on official terraform website here.

Terraform providers

Providers are responsible for interacting with various APIs and services. For example, the AWS provider can be used to interact with the many resources supported by AWS. Similarly, the Proxmox provider can be used to interact with the many resources supported by Proxmox.

So, to use terraform with proxmox we need to specify provider in our terraform config file. The initial configuration file will look like this:

terraform { required_version = ">= 0.13.0" # here we specify minimal terraform version required_providers { proxmox = { source = "Telmate/proxmox" # here we specify proxmox provider version = "2.9.14" # and version of proxmox provider } } }

Of course you won't be able to connect to proxmox without credentials, so we need to specify them too. We can do it in multiple ways, first one will be to specify them by running terraform appply, eg.:

terraform appply -var="pr_api_token_id=root@pam" #[...]

Other way is to specify them as ENV variables, with TF_VAR_ prefix, eg.:

export TF_VAR_pr_api_token_id="root@pam" #[...]

Last, and the best way is to specify them in separate file or in the same file as provider.

I've decided to create separate file for variables. First of all we need to create variables.tf file and specify variables there:

variable "pr_api_token_id" { type = string # type of variable, can be string, number, bool, list, map etc. sensitive = true # this will hide variable value in logs } variable "pr_api_token_secret" { type = string sensitive = true } variable "pr_api_url" { type = string }

Then we need to create credentials.auto.tfvars file and specify values for our variables:

pr_api_token_id = "root@pam" pr_api_token_secret = "secret" pr_api_url = "https://proxmox.example.com:8006/api2/json"

Terraform will automatically load variables from credentials.auto.tfvars file and use them.

If you do not have CA certificate for your proxmox server, you can disable certificate verification by adding pm_tls_insecure = true to your provider config. Also remember to add api2/json at the end of your proxmox url, otherwise you won't be able to connect to proxmox API.

After that you can run terraform init command and terraform will download proxmox provider and all required dependencies.

How to create VM with terraform?

Now we can create our first proxmox VM. I will name my VM gitlab-runner, because that's what I need right now. First, let's create vm.tf file and specify our VMs there, I'm going to use previousely created template image, but you can use ISO image too. You can find more information about how to create template image in my previous post Create VM template.

Ok, let's create our VM, this is full vm.tf file:

resource "proxmox_vm_qemu" "github-runner-cloud-init" { # base vm settings vmid = 141 # this is VM ID, you can specify it manually or let proxmox choose it for you name = "github-runner" # this is VM name desc = "Server for running github actions" # optional description target_node = "mk" # proxmox node where VM will be created # I will use template image, but you can use ISO image too clone = "ubuntu-cloud-img" # VM settings cores = 2 memory = 2048 scsihw = "virtio-scsi-pci" # this parameter represents disk controller, if you choose wrong one, # VM won't boot, it will be stuck on boot screen # disk settings, have to be the same as in template image disk { storage = "local-lvm" size = "4300M" type = "scsi" } # here we specify cloud-init settings, this is optional, but very useful, # because we can specify all settings onec and use it for multiple VMs os_type = "cloud-init" # lastly we specify network settings network { model = "virtio" bridge = "vmbr0" } # if you decide to use cloud-init, you can specify ip address here or # use dhcp, for dhcp you need to specify "ip=dhcp" ipconfig0 = "ip=192.168.0.61/24,gw=192.168.0.1" # this defaults to true, but I like to specify it anyway, because sometimes # I want to create VMs without starting them on boot onboot = true }

Above configuration will create VM with all specified settings, but you have to send this configuration to terraform core to apply it. To do that you need to run terraform apply command. Before that though, it is good practice to run terraform plan command, which will show you what terraform will do, without actually doing it, so like a dry run. After running terraform plan you should see something like this:

terraform plan

The output will be large, so let's take a look at the beginning and the end of it:

terraform -chdir=terraform plan proxmox_vm_qemu.github-runner-cloud-init: Refreshing state... [id=mk/qemu/141] # [...] Plan: 1 to add, 0 to change, 0 to destroy. Note: You didn\'t use the -out option to save this plan, so Terraform can\'t guarantee to take exactly these actions if you run "terraform apply" now.

As you can see, terraform will create 1 VM, and it will not change or destroy anything. Notice last line, it says that you didn't use -out option, which means that terraform will not save this plan, so if you run terraform apply now, it will not guarantee that it will take exactly these actions. If you want to save plan, you can use -out option, eg.:

terraform plan -out=plan.out

This will save plan to plan.out file, and you can use it later with terraform apply command, eg.:

terraform apply plan.out

Ok, so after running terraform apply command, terraform will create VM for you, and you can check it in proxmox web UI. You can also check it with terraform show command, eg.:

terraform show

This command will print state of your infrastructure, even fields that you didn't specify in your configuration file. This is because some fields if not specified, will be filled with default values. You can also check state of specific resource, eg.:

terraform show -json | jq '.values.root_module.resources[] | select(.address == "proxmox_vm_qemu.github-runner-cloud-init")'

This command will print state of proxmox_vm_qemu.github-runner-cloud-init resource in json format.

Ok, so that's it, you should have VM created in proxmox. In next post I will try to go deeper into terraform and proxmox, and I will try to create more complex infrastructure.

See you around!