Created
August 1, 2024 21:05
-
-
Save adeelahmad/30c498652a1138fea97c5322681eedbf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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