User Tools

Site Tools


computing:vmserver

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
computing:vmserver [2022/11/12 18:32] oemb1905computing:vmserver [2024/02/17 20:45] oemb1905
Line 7: Line 7:
 ------------------------------------------- -------------------------------------------
  
-was given dual 8-core Xeon SuperMicro server (32 threads)with 8 HD bays in use, 96GBRAM, 8x 6TB Western Digital in Raid1 zfs mirror (24TB actual), with a 120GBSSD boot volume stuck behind the power front panel running non-GUI Debian. (Thanks to Kilo Sierra for the donation.) My first job was to calculate whether my PSU was up to the task I intended for it. I used a 500W PSU. From my calculations, determined that the RAM would be around 360W at capacity but rarely hit that or even closethat the HDs would often (especially on boot) hit up to 21.3W per drive, or around 150W total, and that excluded the boot SSD volume. The motherboard would be 100W, putting me at 610W. Since I did not expect the RAM, HDs, and other physical components to concurrently hit peak consumption, I considered it safe to proceed, and figured no more than around 75% of that ceiling would be used at any one time. The next step was to install the physical host OS (Debianand setup the basics of the system (hostname, DNS, etc., basic package installs)On the 120GB SSD boot volume, I used luks pam_mount encrypted home directory, where could store keys for the zfs pool and/or other sensitive data. I used a nifty trick in order to first create the pools simply with short names, and then magically change them to block ids without having to make the pool creation syntax cumbersome.+//vmserver//       
 + 
 +------------------------------------------- 
 + 
 +am currently running Supermicro 6028U-TRTP+ w/ Dual 12-core Xeon E5-2650 at 2.2Ghz384GB RAM, with four two-way mirrors of Samsung enterprise SSDs for the primary vdev, and two two-way mirrors of 16TB platters for the backup vdevAll drives using SAS. I am using a 500W PSU. I determine the RAM would be about 5-10W a stick, the mobo about 100W, and the drives would consume most of the rest at roughly 18-22W per drive. The next step was to install Debian on the bare metal to control and manage the virtualization environmentThe virtualization stack is virsh and kvm/qemuAs for the file system and drive formatting, I used luks and pam_mount to open an encrypted home partition and mapped home directoryuse this encrypted home directory to store keys for the zfs pool and/or other sensitive data, thus protecting them behind FDEAdditionally, I create file-level encrypted zfs data sets within each of the vdevs that are unlocked by the keys on the LUKS home partitionInstead of tracking each UUID down on your initial build, do the following:
  
   zpool create -m /mnt/pool pool -f mirror sda sdb mirror sdc sdh mirror sde sdf mirror sdg sdh   zpool create -m /mnt/pool pool -f mirror sda sdb mirror sdc sdh mirror sde sdf mirror sdg sdh
Line 13: Line 17:
   zpool import -d /dev/disk/by-id pool   zpool import -d /dev/disk/by-id pool
  
-Now that pool was created, I created two encrypted datasets, which is zfs name for encrypted file storage inside the pool. The datasets each unlock by pulling a dd-generated key from the encrypted (and separate) home partition on the SSD boot volume. set up the keys/datasets as follows:+Once the pool is created, you can create your encrypted datasets. To do soI made some unlock keys with the dd command and placed the keys in a hidden directory inside that LUKS encrypted home partition I mentioned above:
  
   dd if=/dev/random of=/secure/area/example.key bs=1 count=32   dd if=/dev/random of=/secure/area/example.key bs=1 count=32
   zfs create -o encryption=on -o keyformat=raw -o keylocation=file:///mnt/vault/example.key pool/dataset   zfs create -o encryption=on -o keyformat=raw -o keylocation=file:///mnt/vault/example.key pool/dataset
  
-When you create this on the current running instanceit will also mount it for you as a courtesy, but upon reboot, you need to load the keythen mount the dataset using zfs commandsIn my caseI created three datasets (one for raw isosone for disk images, and a last one for backup sparse tarballs). Each one was created as follows:+When the system rebootsthe vdevs will automatically mount but the data sets won't because the LUKS keys won't be available until you mount the home partition by logging in to the user that holds the keys. For security reasonsthis must be done manually or it defeats the entire purposeSoonce the administrator has logged in to the user in a screen session (rememberit is using pam_mount)they simple detach from that session and then load the keys and datasets as follows:
  
   zfs load-key pool/dataset   zfs load-key pool/dataset
   zfs mount pool/dataset   zfs mount pool/dataset
      
-Once I created all the datasetsI made a script that would load the keys and unlock all of themthen rebooted and tested it for functionalityUpon verifying that the datasets workedI could now feel comfortable creating VMs again, since the hard drive images for those VMs would be stored in encrypted datasets with zfs. My next task was to create both snapshots within zfswhich would handle routine rollbacks and smaller errors/mistakes. did that by creating a small script that runs via cron 4 times a day, or every 6 hours:+If you have a lot of data setsyou can make simple script to load them all at onceetcSince we have zfsit's a good idea to run some snapshots. To do that, I created a small shell script with the following commands and then set it to run 4 times a day, or every 6 hours:
  
   DATE=date +"%Y%m%d-%H:%M:%S"   DATE=date +"%Y%m%d-%H:%M:%S"
Line 31: Line 35:
   /usr/sbin/zfs snapshot pool@backup_$DATE   /usr/sbin/zfs snapshot pool@backup_$DATE
  
-The snapshots allow me to perform roll backs when end-users make mistakes, e.g., delete an instructional video after a class session, etc., or what have you.  To delete all snapshots and start over, run:+Make sure to manage your snapshots and only retain as many as you can etc., as they will impact performanceIf you need to zap all of them and start over, you can use this command:
  
   zfs list -H -o name -t snapshot | xargs -n1 zfs destroy   zfs list -H -o name -t snapshot | xargs -n1 zfs destroy
  
-Of course, off-site backups are essential. To do this, I use small script that powers down the VMuses ''cp'' with the ''--sparse=always'' flag to preserve space, and then uses tar with pbzip2 compression to save even more spaceFrom my researchbsdtar seems to honor sparsity better than gnutar so install that with ''sudo apt install libarchive-tools''The ''cp'' command is not optional, moreoverfor remember tar will not work directly on an ''.img'' fileHere'a small shell script with a loop for multiple VMs within the same directory. I also added a command at the end that will delete any tarballs older than 180 days.+Off-site //full// backups are essential but they take long time to download. For that reasonit's best to have the images as small as possible. When using ''cp'' in your workflow, make sure to specify ''--sparse=always''Before powering the virtual hard disk back upyou should run ''virt-sparsify'' on the image to free up the unused blocks on the host and that are not actually used in the VMIn order for the VM to designate those blocks as empty, ensure that you are running fstrim within the VM. If you want the ls command to show the size of the virtual disk that remains after the zeroingyou will need to run ''qemu-img create'' on it, which will create a new copy of the image without listing the ballooned sizethe new purged virtual hard disk image can then be copied to backup directory where one can compress and tarball it to further reduce its size. I use BSD tar and the pbzip2 compression which makes ridiculously small images. GNU tar glitches with the script for some reason. BSD tar can be downloaded with ''sudo apt install libarchive-tools''. I made script to automate all of those steps for a qcow2 image. I also adapted that to work for raw images.
  
-  DATE=`date +"%Y%m%d-%H:%M:%S"+[[https://repo.haacksnetworking.org/haacknet/haackingclub/-/blob/main/scripts/virtualmachines/vm-bu-production-QCOW-loop.sh|vm-bu-production-QCOW-loop.sh]] \\ 
-  IMG="vm1.img  vm2.img" +[[https://repo.haacksnetworking.org/haacknet/haackingclub/-/blob/main/scripts/virtualmachines/vm-bu-production-RAW-loop.sh|vm-bu-production-RAW-loop.sh]]
-  for i in $IMG; +
-  do +
-  virsh shutdown $i +
-  wait +
-  cd /mnt/vms/backups +
-  cp -ar --sparse=always /mnt/vms/students/$i /mnt/vms/backups/SANE_$i.bak +
-  wait +
-  virsh start $i +
-  bsdtar --use-compress-program=pbzip2 -Scf SANE_$i.tar.bz2 SANE_$i.bak +
-  mv /mnt/vms/backups/SANE_$i.tar.bz2 /mnt/vms/backups/tarballs/$i:_SANE_$DATE:_.tar.bz2 +
-  rm /mnt/vms/backups/SANE_$i.bak +
-  find /mnt/vms/backups/tarballs -type f -mtime +180 -delete+
  
-In addition to daily live images using the above, scriptalso run a 1/3 days version called SANE , which runs virsh shutdown domain before copying/tarballing and then runs virsh start domain at the end of the tarballing. The host is set to keep 30 days worth of images, but you can easily adjust the flag in the last line above to your use caseAfter these run, pull the changes to offsite backup ``/`` computer using rsync on the offsite host as follows:+On the off-site backup machineI originally would pull the tarballs down using a one line rsync scriptwould adjust the cron timing of the rsync script to work well with when the tarballs are created
  
-  sudo rsync -av --log-file=/home/logs/backup-of-vm.log --ignore-existing -e 'ssh -i /home/user/.ssh/id_rsa' root@domain.com:/backups/tarballs/ /media/user/Backups/+  sudo rsync -av --log-file=/home/logs/backup-of-vm-tarballs.log --ignore-existing -e 'ssh -i /home/user/.ssh/id_rsa' root@domain.com:/backups/tarballs/ /media/user/Backups/ 
 +   
 +Since then, I've switched to using rsnapshot to pull down the tarballs in some cases. The rsnapshot configurations can be found here: 
 + 
 +[[https://repo.haacksnetworking.org/haacknet/haackingclub/-/tree/main/scripts/rsnapshot|Rsnapshot Scripts]]
  
-Since the workstation is on rsnapshot, I get redundant dailies on its backup that extend beyond the quantity on the physical host (because of space on my primary workstation).  
  
 **** ****
Line 62: Line 57:
 -- Network Bridge Setup / VMs -- -- Network Bridge Setup / VMs --
  
-Once the physical host was configured, I needed to edit its network settings and create a virtual switch that VMs could be allocated ips through. To do this, I kept it simple and used bridge-utils package and some manual editing in ''/etc/network/interfaces''.+Up until now, I've covered how to provision the machines with virt-manager, how to backup the machines on the physical host, and how to pull those backups to an off-site workstation. Now will discuss how to assign each VM an external IP. The first step is to provision the physical host with a virtual switch (wrongly called a bridge) to which VMs can connect. To do this, I kept it simple and used ''ifup'' and ''bridge-utils'' package and some manual editing in ''/etc/network/interfaces''.
      
   sudo apt install bridge-utils   sudo apt install bridge-utils
Line 68: Line 63:
   sudo nano /etc/network/interfaces   sudo nano /etc/network/interfaces
  
-Now that you have added the routing software package and created the virtual switch, you need to reconfigure your interfaces file so that your host OS knows how to negotiate a connection again. In my case, I used 2/10 ips I purchased at the data center for the physical host. +Now that you have added created the virtual switch, you need to reconfigure your physical host's ''/etc/network/interfaces'' file to use the switch. In my case, I used 1 IP for the host itself, and another for the switch, meaning that two ethernet cables are plugged into my physical host. I did this so that if I hose my virtual switch settings, I still have a separate connection to the box. Here's the configuration in ''interfaces'':
  
-  #eth0 (debian required the alt name for some reason) <- 1st physical port backup+  #eth0  [1st physical port]
   auto ent8s0g0   auto ent8s0g0
     iface ent8s0f0 inet static     iface ent8s0f0 inet static
Line 78: Line 73:
     nameserver 8.8.8.8     nameserver 8.8.8.8
  
-  #eth1 (debian required the alt name for some reason) <- 1nd physical port for bridge+  #eth1 [2nd physical port]
   auto enp8s0g1   auto enp8s0g1
   iface enp8s0g1 inet manual   iface enp8s0g1 inet manual
Line 90: Line 85:
     nameserver 8.8.8.8     nameserver 8.8.8.8
          
-Once that's done, you can restart networking.service (or optionally network-manager if you prefer). After that, see if your changes stuck by with ''ip a''The output of ''ip a'' will now show ''br0 state UP'' in the output of interface ''enp8s0g1'' and down below, you will see the bridge interface, ''br0''and this interface, or virtual switch, is what you connect your virtualization software to. In my case, I just specify ''br0'' in virt-manager in the network section. For smaller environmentsfor examplebeing at home and/or behind a dhcp router, then the following configuration should be sufficient:+After that, either reboot or ''systemctl restart networking.service'' to make the changes currentExecute ''ip a'' and you should see both external IPs on two separate interfaces, and you should see ''br0 state UP'' in the output of the second interface ''enp8s0g1''. You should also run some ''ping 8.8.8.8'' and ''ping google.com'' tests to confirm you can route. If anyone wants to do this in a homesmall business, or other non-public facing environment, you can easily use dhcp and provision the home/small business server's ''interface'' file as follows:
  
   auto eth1   auto eth1
Line 99: Line 94:
         bridge_ports eth1         bridge_ports eth1
  
-The above home-version allows, for example, users to have a virtual machine that gets an ip address on your LAN and makes ssh access far easier, for exampleOkay, back to the server setup. Wellthe next thing to do is to test whether or not you can send/receive packets on those interfacesTo do that, run a few ping tests:+The above home-version allows, for example, users to have a virtual machine that gets an ip address on your LAN and makes ssh/xrdp access far easier. If you have any trouble routing on the physical hostit could be that you do not have nameservers setupIf that's the casedo the following:
  
-  ping 8.8.8.8 +    echo nameserver 8.8.8.8 > /etc/resolv.conf 
-  ping google.com+    systemctl restart networking.service
  
-At this stagethese tests failed and I was not able to route and had no functional DNS servers. Running ''cat /etc/resolv.conf'' confirmed that DNS was only localhostso it made sense I could not routeSince I use Debian, this was an easy fix, and I simply provided my host with nameservers as follows:+Now that the virtual switch is setupI can now provision VMs and connect them to the virtual switch ''br0'' in virt-manager. You can provision the VMs within the GUI using X passthroughor use the command lineFirstcreate a virtual disk to your desired size by excuting ''sudo qemu-img create -f raw new 1000G'' and then run something like this:
  
-  echo nameserver 8.8.8.8 > /etc/resolv.conf+  sudo virt-install --name=new.img \ 
 +  --os-type=Linux \ 
 +  --os-variant=debian10 \ 
 +  --vcpu=1 \ 
 +  --ram=2048 \ 
 +  --disk path=/mnt/vms/students/new.img \ 
 +  --graphics spice \ 
 +  --location=/mnt/vms/isos/debian-11.4.0-amd64-netinst.iso \ 
 +  --network bridge:br0
  
-After this stepyou can either restart ''networking.service'' or if you prefer ''network-manager.service'' and/or reboot. Since I had just done a lot, I decided to just reboot. Upon rebooting, I ran the same ping tests above, and both successfully received bytes back. Now that the physical host has two ips and can route, it was time to setup the VMs and make sure they could connect to the virtual switch, or br0. To do this, I first configured a vanilla install of debian within virt-manager. Then, using the console of virt-manager for that VM, I edited the guest OS network configuration files as follows:+The machine will open in virt-viewerbut if you lose the connection you can reconnect easily with:
  
-  sudo nano /etc/network/interfaces+  virt-viewer --connect qemu:///system --wait new.img  
 +   
 +Once you finish installation, configure the guestOS interfaces file ''sudo nano /etc/network/interfaces'' with the IP you intend to assign it. You should have something like this:
  
   auto epr1   auto epr1
Line 119: Line 124:
     nameservers 8.8.8.8     nameservers 8.8.8.8
  
-Rememberthe configuration above is within the guest OS of the VM in virt-manager and not the physical host. In my example, I used ''epr1'' because that's the name of the network interface when you run ''ip a'' within the guest OS. For smaller/home set-ups using dhcp, you would change the configuration files as follows:+If you are creating VMs attached to a virtual switch on the smaller home/business environmentthen adjust the guest OS by executing ''sudo nano /etc/network/interfaces'' and then something like this recipe:
  
-  sudo nano /etc/network/interfaces +  auto epr1 
-  <auto epr1> +  iface epr1 inet dhcp
-  <iface epr1 inet dhcp>+
  
-Notes for Ubuntu VMs: On some of my VMsI am required to use Ubuntu. Ubuntu has now deprecated ''ifupdown'' in favor of ''netplan'' and disabled manual editing of ''/etc/resolv.conf'' so unless you want to make the above interfaces in YAML in netplanthen you have to temporarily enable NAT in ''virt-manager'' and reboot the VM. Once NAT is enabled and you can route, then add ifupdown, remove netplan, and add the ''resolvconf'' package as follows:+If your guest OS uses Ubuntu, you will need to do extra steps to ensure that the guestOS can routeThis is because Ubuntu-based distros have deprecated ''ifupdown'' in favor of ''netplan'' and disabled manual editing of ''/etc/resolv.conf''. So, either you want to learn netplan syntax and make interface changes using its YAML derivativeor you can install the optional ''resolvconf'' package to restore ''ifupdown'' functionality. To do this, adjust the VM provision script above (or use the virt-manager GUI with X passthrough) to temporarily use NAT then override Ubuntu defaults and restore ''ifupdown'' functionality as follows:
  
   sudo apt install ifupdown   sudo apt install ifupdown
   sudo apt remove --purge netplan.io   sudo apt remove --purge netplan.io
-  <enter the bridge network config above in /etc/network/interfaces> 
   sudo apt install resolvconf   sudo apt install resolvconf
   sudo nano /etc/resolvconf/resolv.conf.d/tail   sudo nano /etc/resolvconf/resolv.conf.d/tail
   <nameserver 8.8.8.8>   <nameserver 8.8.8.8>
-  sudo reboot+  systemctl restart networking.service 
 + 
 +You should once again execute ''ping 8.8.8.8'' and ''ping google.com'' to confirm you can route within the guest OS. Sometimes, I find a reboot is required. At this stage, you now have a physical host configured with a virtual switch, and one VM provisioned to use the switch with its own external IP. Both the physical host and guest OS in this scenario are public facing so take precautions to properly secure each by checking services ''netstat -tulpn'' and/or utilizing a firewall. The main things to configure at this point are ssh access so you no longer need to rely on the virt-viewer console which is slow. To do that, you will need to add packages (if you use the netinst.iso). To make that easy, I keep the sources.list on my primary business server:  
 + 
 +  wget https://haacksnetworking.org/sources.list 
 + 
 +Once you grab the ''sources.list'' file, install ''openssh-server'' and exchange keys, you can now use a shell to ssh into the guestOS henceforward. This means that at this point you are now in a position to create VMs and various production environments at will or start working on the one you just created. Another thing to consider is to create base VMs that have ''interfaces'' and ''ssh'' access all ready to go, and then leverage those to make new instances using ''cp''. Alternately, you can power down a base VM and then clone it as follows: 
 + 
 +  virt-clone \ 
 +  --original=clean \ 
 +  --name=sequoia \ 
 +  --file=/mnt/vms/students/sequoia.img
  
-Make sure to restart ''networking.service'' or ''network-manager.service'' at this point and conduct some ping tests on both ''8.8.8.8'' and ''google.com''. Sometimes, I find a reboot is required. Some online tutorials report that you need additional configuring for traffic to pass properly and/or for NAT to function. However, in my experience, this is all handled by virt-manager. In summary, the point of this project was to create my own virtualized VPS infrastructure, to run my own stuff and for clients. At presentI have ported my business site over, created a teaching nextcloud for Talk with students and for resource sharinga big blue button instance (that proves to be a major problem and source of pain), a minecraft server, some gamer sites, and some testing VPS for my kids. Here's a few to check out:+The purpose of this project was to create my own virtualized VPS infrastructure (using KVM and VMs), to run my own production environments and for clients, students, and family. Here's a few to check out:
  
-  * [[https://haacksnetworking.org|Haack's Networking]] +  * [[https://nextcloud.haacksnetworking.org|Haack's Networking - Nextcloud Talk Instance]] 
-  * [[https://mrhaack.org|Mr. Haack]] +  * [[https://mrhaack.org|GNU/Linux Social - Mastodon Instance]] 
-  * [[http://space.hackingclub.org|Space]] +  * [[http://space.hackingclub.org|My Daughter'Space Website]] 
 +  * [[http://bianca.hackingclub.org|A Student's Pentesting Website]]
  
-The last one is my 10 year old daughter'projectIt's coming along nicely, and serves as a great way to teach her basic html, CSS, and JSThe next part of this write-up includes how to do the same overall virtualization of infrastructure and VPS leveraging as above, but does so with LUKS firstRead on to see what originally did ... the reason I ultimately rejected thismoreoverwas because you can't use zfs tools when hard drives fail if you do it that way. ;<+That'all folks! Well ... except for one more thing. When I first did all of this, I was convinced that zfs should be within LUKS as it was difficult for me to let go of LUKS / full disk encryption. I've now decided that's insane because of one primary reason. Namelyby putting zfs (or any file system) within LUKS, you lose the hot swapability that you have when zfs (or regular RAID) run directly on the hardware. That would mean that replacing a hard drive would require an entire server rebuild, which is insane. However, it is arguably more secure that way, so if budget and time permits, I've retained how I put zfs inside LUKS in the passage that follows. Proceed at your own risk lol.
  
 -- LUKS FIRST, ZFS SECOND - (LEGACY SETUP, NOT CURRENT) -- -- LUKS FIRST, ZFS SECOND - (LEGACY SETUP, NOT CURRENT) --
Line 177: Line 192:
 Rebooting in this manner takes about 3-5 minutes for the host, and 2 minutes to screen into my user name, detach, and run the mount LUKS script to mount the pools/datasets, etc. Again, I ultimately rejected this because you cannot use zfs tools when hard drives fail with this setup. Rebooting in this manner takes about 3-5 minutes for the host, and 2 minutes to screen into my user name, detach, and run the mount LUKS script to mount the pools/datasets, etc. Again, I ultimately rejected this because you cannot use zfs tools when hard drives fail with this setup.
  
- --- //[[jonathan@haacksnetworking.org|oemb1905]] 2022/07/26 19:31//+ --- //[[jonathan@haacksnetworking.org|oemb1905]] 2022/11/12 12:39//
computing/vmserver.txt · Last modified: 2024/02/17 21:11 by oemb1905