Skip to content

Instantly share code, notes, and snippets.

@adeelahmad
Created August 1, 2024 21:05
Show Gist options
  • Select an option

  • Save adeelahmad/30c498652a1138fea97c5322681eedbf to your computer and use it in GitHub Desktop.

Select an option

Save adeelahmad/30c498652a1138fea97c5322681eedbf to your computer and use it in GitHub Desktop.
#!/bin/bash
# Ultimate ZFS Proxmox Tuner Script
# Function to detect existing ZFS pools
detect_zfs_pools() {
zpool list -H -o name
}
# Function to detect SCSI disks dynamically
detect_scsi_disks() {
ls /dev/disk/by-id/*scsi* | xargs -n 1 readlink -f
}
# Function to detect NVMe devices
detect_nvme_devices() {
ls /dev/disk/by-id/*NVMe* | xargs readlink -f
}
# Function to get disk size in bytes
get_disk_size() {
local device=$1
blockdev --getsize64 $device
}
# Function to calculate L2ARC_WRITE_MAX as 5% of disk size
calculate_l2arc_write_max() {
local device=$1
local size=$(get_disk_size $device)
echo $(( size / 20 )) # 5% of disk size
}
# Function to check if running on Proxmox
is_proxmox() {
[ -f /etc/pve/pve.version ]
}
# Function to get total system memory
get_total_memory() {
awk '/MemTotal/ {print $2}' /proc/meminfo
}
# Function to calculate optimal ARC size (50% of total memory)
calculate_arc_size() {
local total_mem=$(get_total_memory)
echo $((total_mem / 2 / 1024))M
}
# Function to set ZFS properties
set_zfs_properties() {
local target=$1
echo "Setting ZFS properties for $target..."
zfs set compression=lz4 $target
zfs set atime=off $target
zfs set relatime=on $target
zfs set xattr=sa $target
zfs set dnodesize=auto $target
zfs set sync=standard $target
zfs set redundant_metadata=most $target
zfs set recordsize=128k $target
}
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
# Check if running on Proxmox
if ! is_proxmox; then
echo "This script is designed for Proxmox. It may not work correctly on other systems."
read -p "Do you want to continue anyway? (y/n): " CONTINUE
if [[ $CONTINUE != "y" ]]; then
echo "Exiting script."
exit 1
fi
fi
# Detect existing ZFS pools
EXISTING_POOLS=$(detect_zfs_pools)
if [ -z "$EXISTING_POOLS" ]; then
echo "No existing ZFS pools detected."
exit 1
fi
# Prompt for pool selection
echo "Detected ZFS pools:"
select POOL_NAME in $EXISTING_POOLS; do
if [ -n "$POOL_NAME" ]; then
break
else
echo "Invalid selection. Please try again."
fi
done
# Detect disks and NVMe devices
DISKS=($(detect_scsi_disks))
NVME_DEVICES=($(detect_nvme_devices))
if [ ${#DISKS[@]} -eq 0 ] && [ ${#NVME_DEVICES[@]} -eq 0 ]; then
echo "No SCSI or NVMe devices detected. Exiting."
exit 1
fi
# Calculate ARC size
ARC_SIZE=$(calculate_arc_size)
# Display and confirm details
echo "ZFS Pool Name: $POOL_NAME"
echo "SCSI Disks: ${DISKS[*]}"
echo "NVMe Devices: ${NVME_DEVICES[*]}"
echo "Calculated ARC Size: $ARC_SIZE"
read -p "Are these details correct? (y/n): " CONFIRM
if [[ $CONFIRM != "y" ]]; then
echo "Exiting script. Please run again if you want to make changes."
exit 1
fi
# Install required packages
echo "Checking and installing required packages..."
REQUIRED_PKG=("zfsutils-linux" "hdparm" "smartmontools" "iotop" "sysstat")
for PKG in "${REQUIRED_PKG[@]}"; do
if ! dpkg -l | grep -q $PKG; then
echo "Installing $PKG..."
apt-get update
apt-get install -y $PKG
fi
done
# Set disk parameters and enable SMART
for DISK in "${DISKS[@]}" "${NVME_DEVICES[@]}"; do
echo "Setting parameters for $DISK..."
hdparm -W1 $DISK
smartctl -s on $DISK
done
# Set ZFS tuning parameters
echo "Setting ZFS tuning parameters..."
ZFS_ARC_MAX=$(numfmt --from=iec $ARC_SIZE)
echo "options zfs zfs_arc_max=$ZFS_ARC_MAX" > /etc/modprobe.d/zfs.conf
echo "options zfs zfs_prefetch_disable=1" >> /etc/modprobe.d/zfs.conf
echo "options zfs zfs_txg_timeout=5" >> /etc/modprobe.d/zfs.conf
# Reload ZFS module
modprobe -r zfs
modprobe zfs
# Set pool and dataset properties
echo "Setting pool and dataset properties..."
set_zfs_properties $POOL_NAME
# Check for and set properties on the root dataset if it exists
ROOT_DATASET="${POOL_NAME}/ROOT"
if zfs list $ROOT_DATASET &>/dev/null; then
echo "Root dataset found. Setting properties for $ROOT_DATASET..."
set_zfs_properties $ROOT_DATASET
fi
# Iterate through all datasets and set properties
for dataset in $(zfs list -H -o name -r $POOL_NAME); do
if [ "$dataset" != "$POOL_NAME" ] && [ "$dataset" != "$ROOT_DATASET" ]; then
echo "Setting properties for dataset: $dataset"
set_zfs_properties $dataset
fi
done
# Set disk cache and queue settings
for DISK in "${DISKS[@]}" "${NVME_DEVICES[@]}"; do
echo "Setting disk cache and queue settings for $DISK..."
echo 0 > /sys/block/$(basename $DISK)/queue/read_ahead_kb
echo deadline > /sys/block/$(basename $DISK)/queue/scheduler
echo 256 > /sys/block/$(basename $DISK)/queue/nr_requests
done
# Configure sysctl settings
echo "Configuring sysctl settings..."
SYSCTL_CONF="/etc/sysctl.d/99-zfs-tuning.conf"
cat <<EOF > $SYSCTL_CONF
# ZFS tuning parameters
vm.swappiness=10
vm.dirty_background_ratio=5
vm.dirty_ratio=15
vm.min_free_kbytes=1048576
vm.dirty_expire_centisecs=3000
vm.dirty_writeback_centisecs=300
vm.vfs_cache_pressure=50
EOF
sysctl -p $SYSCTL_CONF
# Schedule cron jobs for maintenance tasks
echo "Setting up cron jobs for maintenance tasks..."
(crontab -l 2>/dev/null; echo "0 3 * * 0 zpool scrub $POOL_NAME") | crontab -
(crontab -l 2>/dev/null; echo "0 4 * * * echo 3 > /proc/sys/vm/drop_caches") | crontab -
(crontab -l 2>/dev/null; echo "@reboot for DISK in ${DISKS[@]} ${NVME_DEVICES[@]}; do echo 0 > /sys/block/$(basename $DISK)/queue/read_ahead_kb; echo deadline > /sys/block/$(basename $DISK)/queue/scheduler; echo 256 > /sys/block/$(basename $DISK)/queue/nr_requests; done") | crontab -
# Set up ZFS auto-snapshots
echo "Setting up ZFS auto-snapshots..."
apt-get install -y zfs-auto-snapshot
zfs set com.sun:auto-snapshot=true $POOL_NAME
# Enable email notifications for ZFS events
echo "Enabling email notifications for ZFS events..."
apt-get install -y postfix
zpool set autoreplace=on $POOL_NAME
# Set up monitoring
echo "Setting up monitoring..."
apt-get install -y prometheus-node-exporter
systemctl enable prometheus-node-exporter
systemctl start prometheus-node-exporter
# Display pool status
zpool status $POOL_NAME
echo "Ultimate ZFS Proxmox tuning complete!"
# Optional: Reboot recommendation
echo "It is recommended to reboot your system to apply all changes."
read -p "Do you want to reboot now? (y/n): " REBOOT
if [[ $REBOOT == "y" ]]; then
reboot
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment