diff --git a/README.md b/README.md index f14460c..b74dfd5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# template-config +# 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 + 1. Customize new install with whatever software/users/ssh keys you will want on *every* VM by default + 1. 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` + 1. Make the two .sh scripts executable: `chmod +x /usr/local/sbin/vm-{seal,firstrun}.sh` + 1. Let systemd see the new unit file: `systemctl daemon-reload` + 1. Once all your customizations are done and you're ready to turn it into a template, run: `/usr/local/sbin/vm-seal.sh` + 1. 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 + 1. grow the size of the disk if needed + 1. 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 + 1. make your changes on the new VM that will become the new template + 1. when done making changes, run `/usr/local/sbin/vm-seal.sh` + 1. 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. \ No newline at end of file diff --git a/vm-firstrun b/vm-firstrun new file mode 100644 index 0000000..7543889 Binary files /dev/null and b/vm-firstrun differ diff --git a/vm-firstrun.example-config b/vm-firstrun.example-config new file mode 100644 index 0000000..80a1918 --- /dev/null +++ b/vm-firstrun.example-config @@ -0,0 +1,10 @@ +# /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" + diff --git a/vm-firstrun.service b/vm-firstrun.service new file mode 100644 index 0000000..ae279fc --- /dev/null +++ b/vm-firstrun.service @@ -0,0 +1,11 @@ +# /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 + diff --git a/vm-firstrun.sh b/vm-firstrun.sh new file mode 100644 index 0000000..1b53e78 --- /dev/null +++ b/vm-firstrun.sh @@ -0,0 +1,73 @@ +#!/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}" + diff --git a/vm-seal.sh b/vm-seal.sh new file mode 100644 index 0000000..78c9b7f --- /dev/null +++ b/vm-seal.sh @@ -0,0 +1,44 @@ +#!/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 +