Skip to content

Experiments in provisioning local libvirt resources with terraform and cloud-init

License

Notifications You must be signed in to change notification settings

mournfully/terraform-experiments

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

terraform.provisioning libvirt based resources

NOTE: I wanted to learn how to quickly and automatically deploy vm's on my proxmox host, but at the same time I really didn't want to have to learn terraform while learning proxmox. So, I figured I'd learn the basics of terraform here, and then go take a crack at proxmox-terraform integration later.

How to use Terraform to create a small-scale Cloud Infrastructure | by Nitesh | ITNEXT https://itnext.io/how-to-use-terraform-to-create-a-small-scale-cloud-infrastructure-abf54fabc9dd#bf8f

I got as far as Chapter "9. Installing Docker and Terraform provider for docker" and stopped right before it. Since, I had learnt all I wanted regarding the basics of terraform provisioning from this guide. Now that I have the basics down and a good grasp of everything cloud-init, cloud-images, and terraform scripting. I think it's time I got to work on my proxmox server w/ ansible & friends...

Click here to jump to the latest log I wrote for this guide

simple way to provision and manage docker containers? : devops https://www.reddit.com/r/devops/comments/p1aeyg/simple_way_to_provision_and_manage_docker/

Ansible is built for configuration management, while technically being able to provision if it has access to the API. The better tool for provisioning is terraform. So in this case you would use both. I didn't try out terraform yet, but ansible is certainly a great piece of software and worth learning. It is also designed to be as simple as possible.

Maybe the answer is organizing containers in docker-compose files. It's not an orchestration tool, is more a way to have your deployments/containers versioned

  • Test support for the appropriate CPU
lscpu | grep Virtualization
	Virtualization:                  VT-x
# In case of linux machine, instruct physical machine's KVM to enable nested virtualisation (only possible with VT-x).
sudo rmmod kvm-intel && sudo modprobe kvm_intel nested=1
# If the output prints ‘Y’ or ‘1’, it is safe to proceed 
cat /sys/module/kvm_intel/parameters/nested
	Y
  • Download Terraform for Linux 64-bit by going to www.terraform.io/ and pressing on AMD64 under LINUX BINARY DOWNLOAD
wget https://releases.hashicorp.com/terraform/1.3.2/terraform_1.3.2_linux_amd64.zip -p ~/Downloads/
cd ~/Downloads 
unzip terraform_1.3.2_linux_amd64.zip
sudo mv terraform /usr/local/bin/terraform
# sudo pacman -S terraform # works - but just download the binary, its easy af
terraform -v

go to https://developer.hashicorp.com/terraform/downloads and look for 'binary download' and under that 'AMD64' and download that

TANGENT - setup simple terraform project & run some tests

mkdir terraform-testbench && cd terraform-testbench/
git init && git add . && git commit -m "v0.1"
terraform init && terraform apply && terraform destroy
  • install kvm packages - if you are wondering where virt-top equivalanet is, it's called virst and comes bundled with libvirt
# sudo apt -y install qemu-kvm libvirt-bin virt-top libguestfs-tools virtinst bridge-utils
sudo pacman -Syyu
sudo pacman -S qemu-base libvirt libguestfs virt-install bridge-utils

---

# https://www.reddit.com/r/voidlinux/comments/ghwvv5/guide_how_to_setup_qemukvm_emulation_on_void_linux/
# https://docs.voidlinux.org/config/containers-and-vms/libvirt.html
xi qemu libvirt bridge-utils # assumes dbus is setup already

ln -s /etc/sv/libvirtd /var/service/
ln -s /etc/sv/virtlockd/ /var/service/
ln -s /etc/sv/virtlogd/ /var/service/

TANGENT - install linux kernel cause vhost_run isn't a module on linux-surface kernel - rip touchscreen - prior experience with compiling kernel on void should help you TODO compile kernel with vhost_run=m :C

tysm past me for the warning - i had this enabled when i building my kernel a few weeks ago :D

TODO oh hey i need help with getting my mwifiex_pcie drivers to support the set_wiphy_netns command as well!!!

sudo modprobe vhost_net
# modprobe: FATAL: Module vhost_net not found in directory /lib/modules/...
uname -r # find current kernel
find /boot/vmli* # list possible kernels
sudo pacman -S linux linux-headers # install

# cause ~~`GRUB_DEFAULT=saved GRUB_SAVEDEFAULT=true GRUB_DISABLE_SUBMENU=y`~~ can't work cause grub cannot write to a /boot partition that is btrfs 
# **TODO** on future partion maps (this + void exemplar):
	# /dev/nvme0n1p1 (512M) mounted on /boot/efi as vfat
	# /dev/nvme0n1p2 (512M) mounted on /boot as ext4
sudo vim /etc/default/grub
---	GRUB_DEFAULT=0
+++	GRUB_DEFAULT=4

# 0: linux-surface, 1: fallback, 2: linux-lts, 3: fallback, 4: linux, 5: fallback
update-grub
sudo reboot
uname -r

Enable the vhost_net kernel module to allow libvirt to directly call into subsystems instead of using calls from userspace to increase VM performance.

sudo modprobe vhost_net
sudo lsmod | grep vhost
	vhost_net              36864  0
	tun                    61440  1 vhost_net
	vhost                  57344  1 vhost_net <--
	vhost_iotlb            16384  1 vhost
	tap                    28672  1 vhost_net

sudo systemctl enable libvirtd # start a service at boot
sudo systemctl start libvirtd # start service now
sudo systemctl status libvirtd # service status


# **NOT** using `virt-manager` from step 'install kvm' substep '8' - i dont want gui

DEPRECATED - most commands here aren't necesary since provider is autoinstalled by terraform

# ====================================================================
#  START - DEPRECATED 
# ====================================================================

# **DEPRECATED** install go INSTEAD add terraform provider to $PATH
# wget https://dl.google.com/go/go1.19.2.linux-amd64.tar.gz -p ~/Downloads/
# sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.19.2.linux-amd64.tar.gz
vim ~/.bashrc
	# export PATH=$PATH:/usr/local/go/bin # path for golang
	export PATH=$PATH:/usr/lib/go/bin # terraform provider binary
	# export GOPATH=/usr/lib/go # prob for compiling providers
source ~/.bashrc
# echo $GOPATH


# **DEPRECATED** - compile build 
# wait, isn't this installing *-git version, if `build and test` is `faiing` then obviously u can't do compile - **NOTE** try downloading latest release instead
# cd terraform-provider-libvirt
# sudo mkdir -p $GOPATH/src/github.com/dmacvicar/
# cd $GOPATH/src/github.com/dmacvicar/
# sudo git clone https://github.com/dmacvicar/terraform-provider-libvirt.git 
# sudo make install
# cd $GOPATH/bin/
# ./terraform-provider-libvirt -version

# install latest release instead
# wget https://github.com/dmacvicar/terraform-provider-libvirt/releases/download/v0.6.14/terraform-provider-libvirt_0.6.14_linux_amd64.zip
# unzip terraform-provider-libvirt_0.6.14_linux_amd64.zip
# sudo mkdir -p $GOPATH/bin
# sudo mv /tmp/terraform-libvirt/terraform-provider-libvirt_v0.6.14 $GOPATH/bin/terraform-provider-libvirt
# cd $GOPATH/bin && ./terraform-provider-libvirt -version

# add provider as plugin
cd ~/.terraform.d/ && ls
mkdir ~/.terraform.d/plugins
# sudo ln -s /usr/lib/go/bin/terraform-provider-libvirt ~/.terraform.d/plugins/

# ==================================================================
#  END - DEPRECATED SINCE PROVIDER IS AVAILABLE FOR AUTOINSTALLATON 
# ==================================================================
  • add $USER to libvirt and kvm groups. btw local = $USER
sudo usermod -aG libvirt,kvm local
su local
id -nG | grep 'libvirt\|kvm'
  • disable QEMU SELinux but leave SELinux for host enabled (Search with / and change the line ‘security_driver=”selinux”’ to ‘security_driver = “none”’.)
sudo vim /etc/libvirt/qemu.conf
- #security_driver = "selinux" 	
+ security_driver = "none" 

sudo systemctl restart libvirtd

sudo sv restart libvirtd

terraform project stuff - bassically just write some configs, make some directories basically, download some repos, and run a few commands - past work on these configs can be found at GitHub - mournfully/terraform-experiments: me trying to learn the basics of terraform first before automating vm provisioning on proxmox

# normally autocreated, i'll try making just `/libvirt-images` for now
# **NOTE** `/libvirt-images` seemed insignificat - but might be crucial to proper perms for VMs :O

sudo mkdir -p /libvirt-images/testbench-pool 

mkdir -p ~/kvm-testbench/downloads 
cd ~/kvm-testbench/ && touch libvirt.tf # CHECK TESTBENCH FOR TEMPLATES
cd ~/kvm-testbench/ && touch cloud_init.cfg # CHECK TESTBENCH FOR TEMPLATES
	# '#cloud-config' on line 1 
	# call from .tf to cloud_init.cfg
	# cat ~/.ssh/testbench.pub 

	# How To Use Cloud-Config For Your Initial Server Setup | DigitalOcean
	# https://www.digitalocean.com/community/tutorials/
	# how-to-use-cloud-config-for-your-initial-server-setup
	# #troubleshooting

the “How AWS Firecracker works” post mentions “virtio-fs, which allows efficient sharing of files and directories between hosts and guest. This way, a directory containing the guests’ file system can be on the host, much like how Docker works.” the kernel docs on virtio-fs 😳 -https://jvns.ca/blog/2021/01/23/firecracker--start-a-vm-in-less-than-a-second/

  • download debian cloud-image (fast iso) and make ssh key pair

get it from wget https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2

cd ~/kvm-testbench/downloads
# wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
# wget http://cloud.debian.org/images/cloud/bullseye/20220911-1135/debian-11-generic-amd64-20220911-1135.qcow2

ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/testbench -C minuramolligoda.dev@gmail.com
# press `enter` twice for no passphrase
cd ~/.ssh/ && chmod +x testbench.pub && mv testbench testbench.key
ls -al testbench* # check perms for read/write access
	-rw------- 1 local local 419 Oct  6 21:45 testbench.key
	-rwxr-xr-x 1 local local 111 Oct  6 21:45 testbench.pub

TANGENT - manually create bridge network to check commands work and increased familiarity

echo $(virsh net-dumpxml default) > /data/terraform/kvm-testbench/libvirt_network_config.xml
vim /data/terraform/kvm-testbench/libvirt_network_config.xml # see templates
sudo virsh net-define libvirt_network_config.xml
sudo virsh net-start terraform_ne
sudo virsh net-list --all

# to force a vm to use the new virtual network:
resource "libvirt_domain" "test-domain" {
    network_interface {
        # set network_name here to force vm into v-net
	network_name = "terraform_net"
    }

terraform init
terraform apply
sudo virsh net-dhcp-leases terraform_net
# test network by trying to ssh into vm and by requesting a response from picalc server

terraform destroy
virsh net-undefine picalc_net
virsh net-destroy picalc_net

/data/terraform/kvm-testbench/modules/network now let terraform handle the lifecycle of your virtual bridge network

mkdir -p /data/terraform/kvm-testbench/modules/network/
mv /data/terraform/kvm-testbench/libvirt_network_config.xml /data/terraform/kvm-testbench/modules/network/config.xml
touch /data/terraform/kvm-testbench/modules/network/picalc_net # see template

cd /data/terraform/kvm-testbench/modules/network/
terraform init
sudo terraform apply
virsh net-list --all
# test network by trying to ssh into vm and by requesting a response from picalc server
sudo terraform destroy

set static ip addresses via mac address for vms

9. Installing Docker and Terraform provider for docker

^b9c02a

most of the work to get up to here was writing code, I've only documented some of the commands I had to use and tangents I went on here.

the poor mans dashboard

# ================================
#  IMPORTANT COMMANDS CHEATSHEAT
# ================================

# terraform commands 
terraform init
# if you get a resource not found, even though you can see it on virsh - try and check if you're using sudo >.<
sudo terraform apply -auto-approve
sudo terraform destroy -auto-approve

terraform state list
sudo terraform apply -target=
sudo terraform destroy -target=

# example
sudo virsh net-dhcp-leases default 
curl 192.168.122.:8080/PiCalc/100
ssh -i ~/.ssh/testbench.key local@192.168.122.

# diagnosing vms
# see kernel boot log (if run immediatley after vm was made)
sudo virsh list --all 
sudo virsh console $id

# virsh - help + list vm
virsh help | grep network
man virsh | grep network
sudo virsh list --all

# pool stack
sudo virsh pool-list --all
# if showing same, everything is gucci
	sudo virsh vol-list $name
	sudo ls /libvirt-images/$name/

# network stack
sudo virsh net-list --all
sudo virsh net-dhcp-leases default # 192.168.122.36/24
# ping 192.168.122.36 # 0% packet loss OWO
ssh -i ~/.ssh/testbench.key local@192.168.122.126

# How to destroy one specific resource with TF file? · Issue #12917 · hashicorp/terraform
# https://github.com/hashicorp/terraform/issues/12917

# I would like to run terraform only for a specific resource - Stack Overflow
# https://stackoverflow.com/questions/46762047/i-would-like-to-run-terraform-only-for-a-specific-resource

finding virsh commands

nice I also have a network defined but it doesn't appear in the list (i want to know the name I have to undefine). How could I list it ? edit : nvm it's net-list –ChiseledAbs

virsh net-list --all. virsh help gives a list of all the commands, so things like virsh help | grep network produces a list of network related commands; virsh net-list was one of them, and (just as with virsh list) you need --all to show inactive networks as well. –Stephen Harris

virtual machine - How to list domains in virsh? - Unix & Linux Stack Exchange https://unix.stackexchange.com/questions/300113/how-to-list-domains-in-virsh


debugging cloud-init

# on master
sudo pacman -S cloud-init cloud_init.cfg

# debugging `cloud_init.cfg` for valid yaml syntax
cloud-init schema --config-file /data/terraform/kvm-testbench/cloud_init.cfg

# btw there doesn't seem to be a `cloud-init` pakcage in void linux and copying the .cfg to a debian vm and trying to validate it their got me a 'invalid choice: schema' 
	/usr/bin/cloud-init: error: argument subcommand: invalid choice: 'schema' (choose from 'init', 'modules', 'single', 'query', 'dhclient-hook', 'features', 'analyze', 'devel', 'collect-logs', 'clean', 'status')
# on slave
# update + upgrade + install = 140s
# update + install = 65s
# install = 
# sudo apt-get install cloud-init

# sort and print events based on highest time cost
cloud-init analyze blame -i /var/log/cloud-init.log

# organize events into stages and substages and print time cost next to each event
cloud-init analyze show -i /var/log/cloud-init.log

# read through vm init logs - pretty easy to read actually
# Instead of /var/log/cloud-init.log consider searcing for keywords like "Failed", "ERROR" "WARNING" or "/var/lib/cloud/instance/scripts/" inside /var/log/cloud-init-output.log - which in most cases, contains very clear error messages.
sudo vim /var/log/cloud-init-output.log

Debugging cloud-init — cloud-init 22.3 documentation https://cloudinit.readthedocs.io/en/latest/topics/debugging.html

sudo vim /var/log/cloud-init-output.log
/var/lib/cloud/instances/scripts/runcmd: 4: restart: not found
2022-12-02 17:02:32,072 - cc_scripts_user.py[WARNING]: Failed to run module scripts-user (scripts in /var/lib/cloud/instance/scripts)

# i was really confused by this at first but it immediatley makes sense once you see what's inside /var/lib/cloud/instances/scripts/runcmd
sudo ./runcmd
	restart not found

restart ssh
	-bash: restart: command not found

sudo vim /var/lib/cloud/instances/scripts/runcmd
	sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
	sed -i -e '$aAllowUsers terraform' /etc/ssh/sshd_config
	restart ssh

# it's a copy of runcmd: from /home/local/projects/terraform-experiments/cloud_init_test.cfg
# the error here was that I was trying to restart my ssh daemon with a command that didn't exist, so all i had to do was
vim /home/local/projects/terraform-experiments/cloud_init_test.cfg
  runcmd:
    - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
    - sed -i -e '$aAllowUsers terraform' /etc/ssh/sshd_config
-   - restart ssh
+   - sudo systemctl restart ssh

You can usually find some good information about what happened by using grep to search these files.

  • /var/log/cloud-init.log - cloud-init process logs
  • /var/log/cloud-init-output.log - vm initialization process logs

If cannot log into the server you created because of some configuration problems - destroy the server and start again with a temporarily set up root password

#cloud-config
chpasswd:
  list: |
    root:yourpassword
  expire: False

How To Use Cloud-Config For Your Initial Server Setup | DigitalOcean https://www.digitalocean.com/community/tutorials/how-to-use-cloud-config-for-your-initial-server-setup

TANGENTS debugging - mostly useless but makes similar problems go by super fast with a reference

Error error while starting the creation of CloudInit's ISO image: exec: "mkisofs": executable file not found in $PATH

# fixed by installing mkisofs package: `apk add cdrkit`
# search on `https://archlinux.org/packages/` for `cdrkit` gave `cdrtools`
sudo pacman -S cdrtools

Error: storage pool 'debian-pool' already exists - but virsh pool-list didn't show anything but then I looked at the docs at https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/virtualization_administration_guide/delete-lvm-storage-pool-virsh and realised that their commands have # indicating root/sudo 🤦

sudo virsh pool-list
 Name          State    Autostart
-----------------------------------
 debian-pool   active   yes
	 
sudo virsh pool-destroy debian-pool
Pool debian-pool destroyed

# sudo virsh pool-delete debian-pool

ERROR: failed to remove pool '/opt/libvirt-images/debian-pool': Directory not empty might be because /opt/ requiring sudo - try /

sudo rm -rf /opt/libvirt-images/debian-pool/

sudo virsh pool-undefine debian-pool
Pool debian-pool has been undefined
sudo virsh pool-list
 Name   State   Autostart
---------------------------

Error: error creating libvirt domain: Requested operation is not valid: network 'default' is not active read the error a couple times, looked through code around line indicated, didnt see anything wrong - searched it up: https://www.xmodulo.com/network-default-is-not-active.html - learnt i could try starting it

sudo virsh net-list --all
 Name      State      Autostart   Persistent
----------------------------------------------
 default   inactive   no          yes

sudo virsh net-start default

# https://libvirt.org/sources/virshcmdref/html/sect-net-autostart.html
# sudo virsh net-autostart --network default --enable
# error: command 'net-autostart' doesn't support option --enable
# man virsh | grep net-autostart
sudo virsh net-autostart default # enable autostart
# sudo virsh net-autostart default --disable # disable autostart

Error: error defining libvirt domain: operation failed: domain 'testbench-vm' already exists with uuid 1855f3b7-6707-4e0c-b050-e9c5ac83c2ea

# https://unix.stackexchange.com/questions/300113/how-to-list-domains-in-virsh
# https://www.cyberciti.biz/faq/howto-linux-delete-a-running-vm-guest-on-kvm/
sudo virsh list --all
sudo virsh -c qemu:///system list --all
Id   Name             State
---------------------------------
 -    test-vm-debian   shut off
 -    testbench-vm     shut off

# if "running" 
	# sudo virsh shutdown VM_NAME`
	# sudo virsh destroy VM_NAME
# if "shut off"
	sudo virsh undefine VM_NAME

How to use Terraform to create a small-scale Cloud Infrastructure | by Nitesh | ITNEXT https://itnext.io/how-to-use-terraform-to-create-a-small-scale-cloud-infrastructure-abf54fabc9dd#e6ed

GitHub - dmacvicar/terraform-provider-libvirt: Terraform provider to provision infrastructure with Linux's KVM using libvirt https://github.com/dmacvicar/terraform-provider-libvirt/

linux_file_hierarchy

Linux file system hierarchy v1.0 - blackMORE Ops https://www.blackmoreops.com/2015/02/14/linux-file-system-hierarchy/

Cleaning up a Terraform state file — the right way! | by Karl Cardenas | FAUN Publication https://faun.pub/cleaning-up-a-terraform-state-file-the-right-way-ab509f6e47f3

TODO looks important - try to understand properly

About

Experiments in provisioning local libvirt resources with terraform and cloud-init

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages