diff --git a/src/content/homelab/images/i-have-homelab.webp b/src/content/homelab/images/i-have-homelab.webp new file mode 100644 index 0000000..7db6e83 Binary files /dev/null and b/src/content/homelab/images/i-have-homelab.webp differ diff --git a/src/content/homelab/terraform.md b/src/content/homelab/terraform.md new file mode 100644 index 0000000..ab9ce0a --- /dev/null +++ b/src/content/homelab/terraform.md @@ -0,0 +1,138 @@ +--- +title: Terraform + Proxmox = <3 +description: Using Terraform to deploy Virtual Machines +pubDate: 08.03.2024 +--- + +## I am tired of UIs + +Up until now, every time i wanted to deploy a VM in my homelab i did it with the Proxmox GUI. Don't get me wrong, the GUI is nice, but i would like to not have to repeat the same mundane task every time i want a new VM. +There is an argument to be made that i probably shouldn't run that many VMs, and that for the number of VMs i need, this isn't worth it. However, being able to deploy a VM by just changing a few variables in a file and running `terraform apply` just tickles something in my nerd brain. + +I also really like the repeatability of this, as i use these VM definitions to deploy K3S hosts, docker hosts and others where i want a "default" setup. + +## Initial requirements + +To use Terraform with Proxmox we use a privoder created by [Telmate](https://github.com/Telmate/terraform-provider-proxmox). We create the initial `provider.tf` file as so: +```json +terraform { + required_providers { + proxmox = { + source = "telmate/proxmox" + version = "3.0.1-rc3" + } + } +} + +variable "proxmox_api_url" { + type = string +} + +variable "proxmox_user" { + type = string + sensitive = true +} + +variable "proxmox_password" { + type = string + sensitive = true +} + +variable "ssh_public_key" { + type = string +} + +provider "proxmox"{ + pm_api_url = var.proxmox_api_url + pm_user = var.proxmox_user + pm_password = var.proxmox_password + pm_tls_insecure = true + pm_otp = "" +} +``` + +I have stored all secrets to access the proxmox API in custom variables located in a `.auto.tfvars` file that i do not track in git. Those variables are defined in the provider such that if they are not present Terraform will complain. + +In this step i had some trouble, as you can see i use a release candidate version. There seems to be a bug in version `2.9.3`, and instead of trying to track it down i just switched to release candidate. + +## Defining the virtual machine + +Now as i mentioned previously, i already have templates created in my proxmox cluster (i made these with Ansible). Therefore i can use these as a base for the provisioning of a new VM. + +Here is an example definition of a VM + +```terraform +resource "proxmox_vm_qemu" "havneboks" { + name = "havneboks" + desc = "Docker master" + target_node = "poseidon" + + agent = 1 + onboot = true + + clone = "VM 9001" + cores = 4 + sockets = 1 + cpu = "host" + memory = 3096 + + # Setup the disk + disks { + ide { + ide2 { + cloudinit { + storage = "basseng" + } + } + } + scsi { + scsi0 { + disk { + size = "10G" + storage = "basseng" + } + } + } + } + + + network { + bridge = "vmbr0" + model = "virtio" + } + scsihw = "virtio-scsi-pci" + os_type = "cloud-init" + ipconfig0 = "ip=192.168.1.51/24,gw=192.168.1.1" + nameserver = "192.168.1.69" + ciuser = "ansible" + sshkeys = var.ssh_public_key +} +``` + +A VM is defined using the resource type of `proxmox_vm_qemu` with a name. I really like to use the names of the service just translated to norwegian, so in this case, this VM is called `havneboks` (meaning docker box). + +- name: The name of the VM (hostname) +- desc: A description of the VM +- target_node: Which node in the cluster should the VM be provisioned to, in this case i provision it to the node `poseidon`(hostname) +- agent: Just select 1 +- onboot: Set the VM to start when the host boots +- clone: Which template to clone the VM from +- cores: How much horsepowa u want? +- sockets: I only got 1 cpu in each of my boxes +- memory: How much RAM u want? + +Now, a really important part of this is the disk setup, as you have to mimic the setup of the template (sizes can be chosen freely). So in my case, i have the cloud-init disk on `ide2` and the OS disk on `scsi0` in the template. Therefore we create the same exact setup for this resource. + +- network: Just mimic the cloud-init +- scsihw: Which hardware do you want the host system to use to provide scsi? +- os_type: I use cloud-init, so we select cloud-init +- ipconfig: Now this is quite interesting, you should set a static IP and gateway such that the VM starts with a proper IP adress (you can also use DHCP here) +- namesever: I use a custom dns on adress `.69`(nice) so i set that, but if this is not set it will use "same as host" +- ciuser: A user to be created by cloud-init for this VM +- sshkeys: Initial SSH public keys to allow access. This is stored in a variable in my case. + +## Just run? + +Bing bang bom. You can now deploy your VM fully automatically and about 43 seconds later access it via SSH. Now all i did was configure it with ansible, and i have a fully reproducible homelab setup. + +![](./images/i-have-homelab.webp) \ No newline at end of file