This is a follow-up post of my previous post about Windows VM installation. This one, surprise surprise, is about installing Linux VM.
I hate tedious and manual work, but sometimes it also doesn't make sense to spend time modifying an Ansible playbook that I probably will only use a few times. I find virt-install and cloud-init meet most of my needs when it comes to quickly spinning VMs up for testing. They offer simplicity with great flexibility. Within minutes I can create VMs for testing; if I want to go crazy, I can tell it to run Ansible during the first boot. Probably other automation tools as well.
For more serious stuff (like a production server), I will stick to Ansible for deployment and config management.
I will use Ubuntu as example for this tutorial. Debian/Fedora/CentOS Stream all have cloud editions. Download cloud image .img
file
In a directory, create files meta-data
and user-data
(optionally vendor-data
)
meta-data
:
instance-id: <Your-ID> # not important; will not be in virtual machine's XML file
local-hostname: ubuntu.local.lan # this will be the FQDN
users:
- name: user1
gecos: A super admin user on Ubuntu with nopassword sudo;
groups: [sudo, adm, audio, cdrom, dialout, floppy, video, plugdev, dip, netdev]
# other than sudo, the rest are ubuntu defaults
shell: /bin/bash
sudo: 'ALL=(ALL) NOPASSWD:ALL'
lock_passwd: true # by default; disables password login
chpasswd:
expire: True
ssh_authorized_keys:
- <Your SSH pub key>
# Another example
- name: user2
gecos: A generic admin user with sudo privilege but requires password
groups: users,admin,wheel
shell: /bin/bash
sudo: 'ALL=(ALL) ALL'
passwd: <hash of password> # mkpasswd --method=SHA-512 --rounds=4096 ## to get the hash
ssh_authorized_keys:
- ' <Your SSH pub key>'
package_update: true
package_upgrade: true # default command on Ubuntu is 'apt dist-upgrade'
# installing additional packages
packages:
- ansible
# cloud-init is able to chain Ansible pull mode, if further configuration is needed
ansible:
pull:
url: "https://git.../xxx.git"
playbook_name: xxx.yml
# run some commands on first boot
bootcmd: # very similar to runcmd, but commands run very early in the boot process, only slightly after a 'boothook' would run.
- some commands...
runcmd:
- systemctl daemon-reload
#swap: # by default, there is no swap
# filename: /swap
# size: "auto" # or size in bytes
# maxsize: 2147484000 # size in bytes (2 Gibibyte)
# after system comes up first time; find IP in the output text
final_message: "The system is finally up, after $UPTIME seconds"
Finally, install the VM with cloud-init scripts and the cloud image we downloaded earlier. We are going to use user session qemu:///session
and store the qcow2 image to ~/.local/share/libvirt/images/xxx.qcow2
virt-install \
--connect qemu:///session \
--name ubuntu \
--vcpus 2 \ # --cpu MODEL[,+feature][,-feature][,match=MATCH][,vendor=VENDOR],...
--memory 2048 \
#--memballoon driver.iommu=on \
--osinfo ubuntu22.04 \
--network bridge=virbr0,model=virtio,driver.iommu=on \
--graphics none \ # server install
--disk ~/.local/share/libvirt/images/xxx.qcow2,size=30,backing_store=$PWD"/jammy-server-cloudimg-amd64.img",target.bus=virtio \
--cloud-init user-data=$PWD"/user-data",meta-data=${PWD}"/meta-data"
# to get the list of accepted OS variant `virt-install --osinfo list` debian11/fedora37/win10;
As usual, tweak any flags as you see fit.