Skip to content

Instantly share code, notes, and snippets.

@metalcated
Forked from aheadley/README.md
Created February 10, 2020 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metalcated/0871083fde2b5adf2067707bed51973c to your computer and use it in GitHub Desktop.
Save metalcated/0871083fde2b5adf2067707bed51973c to your computer and use it in GitHub Desktop.
Some scripts to help with turning a CentOS 7 VM into a template in Proxmox

EL7 VM Templatization for Proxmox

Description

These are some handy tools to turn a VM into a template, so that creating a new VM is as simple as (full) clone and boot. There are several assumptions made that may not necessarily match with anyone else's environment:

  • CentOS 7 minimal install (will probably work on any flavor of EL7)
  • DHCP server available
  • rootfs (/) is on the last partition of the primary disk, and is a primary partition
  • a centos user exists on the VM (this is not a hard requirement, nothing bad will happen if it's not true)

Right now, the main things it will do is on the first time a new VM boots it will:

  • generate a new hostname (configurable, defaults to using UUIDs)
  • grow the rootfs

Setup

  1. Create a new VM (with a very small disk, like <=8GB) and install CentOS 7 minimal
  2. Customize new install with whatever software/users/ssh keys you will want on every VM by default
  3. Copy each of the four files to the location specified in the comment at the top:
    • cp ./vm-{seal,firstrun}.sh /usr/local/sbin/
    • cp ./vm-firstrun.example-config /etc/sysconfig/vm-firstrun
    • cp ./vm-firstrun.service /etc/systemd/system/vm-firstrun.service
  4. Make the two .sh scripts executable: chmod +x /usr/local/sbin/vm-{seal,firstrun}.sh
  5. Let systemd see the new unit file: systemctl daemon-reload
  6. Once all your customizations are done and you're ready to turn it into a template, run: /usr/local/sbin/vm-seal.sh
  7. The VM should shutdown, then in Proxmox you can just right-click and convert to template

Usage

After doing the setup, to create a new VM:

  1. do a full clone of the template
  2. grow the size of the disk if needed
  3. start the VM

If you ever need to make changes to your template:

  1. follow the above steps to create a new VM from the template
  2. make your changes on the new VM that will become the new template
  3. when done making changes, run /usr/local/sbin/vm-seal.sh
  4. after the new VM stops, convert it to a template and delete the old template

Note that because it touches /.autorelabel, the first boot can take a few minutes while the SELinux contexts are re-applied or whatever, if SELinux is disabled in your environment this may not matter.

How it works

It's very simple, vm-seal.sh basically de-configures the parts of the system that should be unique, then removes any log files or anything that shouldn't really be on a newly-installed system. Then it enables vm-firstrun.service in systemd and does a shutdown. At the next boot, systemd starts the vm-firstrun.service which just runs vm-firstrun.sh, which generates a new hostname and grows the rootfs. Then it disables the vm-firstrun.service so that it won't run again next time the VM is rebooted.

# /etc/sysconfig/vm-firstrun
# CFG_HOSTNAME_SCRIPT="uuidgen"
# CFG_HOSTNAME_PREFIX=""
# CFG_HOSTNAME_POSTFIX=""
# CFG_DOMAIN="localdomain"
# CFG_ROOTFS_DISK="/dev/sda"
# CFG_ROOTFS_PARTITION="3"
# CFG_ROOTFS_TYPE="xfs"
# CFG_SERVICE_NAME="vm-firstrun"
# /etc/systemd/system/vm-firstrun.service
[Unit]
Description=Initialize this template-created VM
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/vm-firstrun.sh
[Install]
WantedBy=multi-user.target
#!/bin/bash
# /usr/local/sbin/vm-firstrun.sh
# This script depends on having these packages installed:
# - cloud-utils-growpart
# - parted
# This should be a simple bash file that sets the CFG_* variables
[ -f /etc/sysconfig/vm-firstrun ] && . /etc/sysconfig/vm-firstrun
## Set default values for anything that wasn't already set
# This will be run at firstboot to generate the hostname
CFG_HOSTNAME_SCRIPT="${CFG_HOSTNAME_SCRIPT:=uuidgen}"
# These can be set in config, there's just no reason for a default besides (blank)
# CFG_HOSTNAME_PREFIX="${CFG_HOSTNAME_PREFIX:=}"
# CFG_HOSTNAME_POSTFIX="${CFG_HOSTNAME_POSTFIX:=}"
CFG_DOMAIN="${CFG_DOMAIN:=localdomain}"
CFG_ROOTFS_DISK="${CFG_ROOTFS_DISK:=/dev/sda}"
CFG_ROOTFS_PARTITION="${CFG_ROOTFS_PARTITION:=3}"
CFG_ROOTFS_TYPE="${CFG_ROOTFS_TYPE:=xfs}"
CFG_SERVICE_NAME="${CFG_SERVICE_NAME:=vm-firstrun}"
## Helper Functions
function log() {
echo "$@" | logger --stderr -t vm-firstrun
}
## Do the things
old_hostname="$(hostname -f)"
new_hostname="${CFG_HOSTNAME_PREFIX}$(${CFG_HOSTNAME_SCRIPT})${CFG_HOSTNAME_POSTFIX}"
if ! [ -z "${CFG_DOMAIN}" ]; then
new_hostname="${new_hostname}.${CFG_DOMAIN}"
fi
log "Setting hostname from '${old_hostname}' to '${new_hostname}'"
hostnamectl set-hostname "${new_hostname}"
if [ -b "${CFG_ROOTFS_DISK}" ]; then
if [ -b "${CFG_ROOTFS_DISK}${CFG_ROOTFS_PARTITION}" ]; then
# expand the partition
log "Expanding rootfs partition"
growpart "${CFG_ROOTFS_DISK}" "${CFG_ROOTFS_PARTITION}"
# reload partition table
log "Reloading partition table"
partprobe "${CFG_ROOTFS_DISK}"
# grow the rootfs
case "${CFG_ROOTFS_TYPE}" in
xfs)
log "Growing rootfs of type: ${CFG_ROOTFS_TYPE}"
xfs_growfs /
;;
ext*)
log "Growing ${CFG_ROOTFS_TYPE} rootfs on device: ${CFG_ROOTFS_DISK}${CFG_ROOTFS_PARTITION}"
resize2fs "${CFG_ROOTFS_DISK}${CFG_ROOTFS_PARTITION}"
;;
*)
log "Unsupported rootfs type: ${CFG_ROOTFS_TYPE}"
log "Doing nothing, please grow the fs manually"
;;
esac
else
log "rootfs partition not found, unable to expand: ${CFG_ROOTFS_DISK}${CFG_ROOTFS_PARTITION}"
fi
else
log "rootfs disk not found, unable to expand: ${CFG_ROOTFS_DISK}"
fi
log "initial config done, disabling myself"
systemctl disable "${CFG_SERVICE_NAME}"
#!/bin/bash
# /usr/local/sbin/vm-seal.sh
unset HISTFILE
yum update -y
yum clean all -y
: > /etc/machine-id
hostnamectl set-hostname localhost.localdomain
systemctl enable vm-firstrun
rm -f /etc/ssh/ssh_host_*
rm -rf /root/.ssh/
rm -f /root/anaconda-ks.cfg
rm -f /root/.bash_history
rm -f /home/centos/.bash_history
rm -f /home/centos/.ssh/known_hosts
rm -f /var/log/boot.log
rm -f /var/log/cron
rm -f /var/log/dmesg
rm -f /var/log/grubby
rm -f /var/log/lastlog
rm -f /var/log/maillog
rm -f /var/log/messages
rm -f /var/log/secure
rm -f /var/log/spooler
rm -f /var/log/tallylog
rm -f /var/log/wpa_supplicant.log
rm -f /var/log/wtmp
rm -f /var/log/yum.log
rm -f /var/log/audit/audit.log
rm -f /var/log/tuned/tuned.log
updatedb
touch /.autorelabel
sys-unconfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment