Skip to content

Instantly share code, notes, and snippets.

@in03
Last active December 29, 2024 05:51
Show Gist options
  • Save in03/990359840db63d2debc47387f8766c8e to your computer and use it in GitHub Desktop.
Save in03/990359840db63d2debc47387f8766c8e to your computer and use it in GitHub Desktop.
Configures an LXC container with Nvidia GPU passthrough.
#!/bin/bash
# Constants
SCRIPT_NAME="install_nvidia_driver_host.sh"
SCRIPT_PATH="/usr/local/bin/$SCRIPT_NAME"
DRIVER_DIR="/usr/local/share/nvidia" # Directory to store the NVIDIA driver file
KERNEL_HOOK_PATH="/etc/kernel/postinst.d/nvidia-driver-reinstall"
KERNEL_TRACK_FILE="/var/lib/nvidia-driver-installed-kernel"
# Logging function
log() {
local COLOR=""
local RESET="\033[0m"
local DATE=$(date +%Y-%m-%d)
local LOG_FILE="/var/log/nvidia-driver-install.log"
local MESSAGE="$1"
case "$1" in
Success*|*finish*|*done*|*complete*) COLOR="\033[32m" ;; # Green
Error*) COLOR="\033[31m" ;; # Red
Warning*) COLOR="\033[33m" ;; # Orange
Info*) COLOR="\033[36m" ;; # Cyan
Debug*) COLOR="\033[35m" ;; # Magenta
*) COLOR=""
esac
# Print to terminal with color
echo -e "$DATE | ${COLOR}${MESSAGE}${RESET}"
# Log to file without color codes
# echo "$DATE | $MESSAGE" >> "$LOG_FILE"
}
trap 'echo; log "Error: Process killed"; exit 1' SIGTERM
trap 'echo; log "Warning: User exited."; exit 0' SIGINT
# Function to install script
install_self() {
log "Info: Installing script to $SCRIPT_PATH..."
cp "$0" "$SCRIPT_PATH"
chmod +x "$SCRIPT_PATH"
log "Success: Script installed to $SCRIPT_PATH."
log "Info: Installing kernel hook to $KERNEL_HOOK_PATH..."
echo "#!/bin/bash" > "$KERNEL_HOOK_PATH"
echo "$SCRIPT_PATH --silent" >> "$KERNEL_HOOK_PATH"
chmod +x "$KERNEL_HOOK_PATH"
log "Info: Kernel hook successfully installed."
}
# Function to install the NVIDIA driver
install_driver() {
DRIVER_FILE=$(ls "$DRIVER_DIR"/NVIDIA-Linux-*.run 2>/dev/null | head -n 1)
if [[ -z "$DRIVER_FILE" ]]; then
log "Error: NVIDIA driver file not found."
log "Info: Please ensure a driver file is added to $DRIVER_DIR, matching pattern \"NVIDIA-Linux-*.run\""
exit 1
fi
log "Info: Successfully detected NVIDIA driver file: $DRIVER_FILE."
log "Info: Current kernel is $(uname -r)"
log "Info: Installing kernel headers and build tools"
apt update && apt install -y gcc make dkms build-essential pve-headers-"$(uname -r)" linux-source
chmod +x "$DRIVER_FILE"
"${DRIVER_FILE}" --dkms --silent
if [[ $? -eq 0 ]]; then
log "Info: NVIDIA driver installed successfully."
echo "$CURRENT_KERNEL" > "$KERNEL_TRACK_FILE"
else
log "Error: NVIDIA driver installation failed."
exit 1
fi
}
# Check for silent mode
SILENT=false
if [[ "$1" == "--silent" ]]; then
SILENT=true
fi
# Detect interactive mode
if ! $SILENT; then
echo "
██████╗ ██╗ ██╗███████╗ ███╗ ██╗██╗ ██╗ ███╗ ██████╗ ████████╗██████╗
██╔══██╗██║ ██║██╔════╝ ████╗ ██║██║ ██║██╔██╗██╔══██╗╚══██╔══╝██╔══██╗
██████╔╝██║ ██║█████╗ ██╔██╗ ██║██║ ██║╚═╝╚═╝██║ ██║ ██║ ██████╔╝
██╔═══╝ ╚██╗ ██╔╝██╔══╝ ██║╚██╗██║╚██╗ ██╔╝ ██║ ██║ ██║ ██╔══██╗
██║ ╚████╔╝ ███████╗ ██║ ╚████║ ╚████╔╝ ██████╔╝ ██║ ██║ ██║
╚═╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═══╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
Proxmox Virtual Environment - Nvidia Updater.
"
log "Info: Running in interactive mode."
# Prompt for installation
echo "------------"
read -p "Do you want to install this script and enable it as a post-kernel update hook? (y/n): " INSTALL
if [[ "$INSTALL" =~ ^[Yy]$ ]]; then
install_self
else
log "Warning: Installation skipped. Run manually if needed."
exit 0
fi
else
log "Info: Running in silent mode."
fi
# Check current kernel version
CURRENT_KERNEL=$(uname -r)
log "Info: Current kernel is $CURRENT_KERNEL."
# Check if the driver is already installed for this kernel
if [[ -f "$KERNEL_TRACK_FILE" ]]; then
LAST_KERNEL=$(cat "$KERNEL_TRACK_FILE")
if [[ "$CURRENT_KERNEL" == "$LAST_KERNEL" ]]; then
log "Info: NVIDIA driver already installed for kernel $CURRENT_KERNEL. Nothing to be done."
exit 0
fi
fi
# Install the NVIDIA driver (store and reference driver file)
log "Info: Installing NVIDIA driver for kernel $CURRENT_KERNEL..."
install_driver
log "Info: NVIDIA driver installation complete."
# Optional reboot prompt (interactive mode only)
if ! $SILENT; then
echo "---"
read -p "Do you want to reboot now? (y/n): " REBOOT
if [[ "$REBOOT" =~ ^[Yy]$ ]]; then
log "Info: Rebooting system..."
reboot
else
log "Warning: Reboot skipped. Please reboot manually to complete the installation."
fi
fi
#!/bin/bash
# Check if whiptail is installed
if ! command -v whiptail &> /dev/null; then
echo "whiptail is required but not installed. Installing whiptail..."
apt update && apt install -y whiptail
fi
# List all LXC containers
LXC_CONTAINERS=$(pct list | awk 'NR>1 {print $1 " " $2}')
if [ -z "$LXC_CONTAINERS" ]; then
echo "No LXC containers found."
exit 1
fi
# Prompt the user to select an LXC container
LXC_ID=$(whiptail --title "Select LXC Container" --menu "Choose the LXC container to install the NVIDIA driver:" 20 78 10 $(echo "$LXC_CONTAINERS") 3>&1 1>&2 2>&3)
if [ $? -ne 0 ]; then
echo "No LXC container selected. Exiting..."
exit 1
fi
# Detect the NVIDIA driver file
DRIVER_FILE=$(ls NVIDIA-Linux-*.run | head -n 1)
if [ ! -f "$DRIVER_FILE" ]; then
echo "NVIDIA driver file not found in the current directory."
exit 1
fi
echo "Detected NVIDIA driver: $DRIVER_FILE"
# Parse the major device numbers for NVIDIA devices
echo "Fetching NVIDIA device numbers from /dev/nvidia*..."
DEVICES_OUTPUT=$(ls -al /dev/nvidia*)
if [ -z "$DEVICES_OUTPUT" ]; then
echo "NVIDIA devices not found. Ensure your GPU is detected."
exit 1
fi
# Extract the major numbers
MAJOR_1=$(echo "$DEVICES_OUTPUT" | grep -m1 '/dev/nvidia0' | awk '{print $5}' | cut -d, -f1)
MAJOR_2=$(echo "$DEVICES_OUTPUT" | grep -m1 '/dev/nvidia-uvm' | awk '{print $5}' | cut -d, -f1)
if [ -z "$MAJOR_1" ] || [ -z "$MAJOR_2" ]; then
echo "Failed to detect major device numbers. Exiting..."
exit 1
fi
echo "Detected major numbers: 195=$MAJOR_1, 507=$MAJOR_2"
# Inject the necessary device configurations into the LXC configuration
LXC_CONF_PATH="/etc/pve/lxc/$LXC_ID.conf"
echo "Updating LXC container configuration at $LXC_CONF_PATH..."
# Add the required lines for NVIDIA GPU passthrough
cat <<EOL >> "$LXC_CONF_PATH"
# NVIDIA GPU Passthrough
lxc.cgroup2.devices.allow: c $MAJOR_1:* rwm
lxc.cgroup2.devices.allow: c $MAJOR_2:* rwm
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
EOL
echo "LXC container configuration updated with NVIDIA passthrough."
# Copy NVIDIA driver to LXC container
echo "Copying NVIDIA driver to LXC container $LXC_ID..."
pct push "$LXC_ID" "$DRIVER_FILE" "/root/nvidia-driver.run"
# Install the NVIDIA driver in the LXC container
echo "Installing the NVIDIA driver in the LXC container..."
pct exec "$LXC_ID" -- bash -c "
chmod +x /root/nvidia-driver.run &&
/root/nvidia-driver.run --silent &&
rm /root/nvidia-driver.run
"
# Restart the LXC container to apply changes
echo "Restarting the LXC container $LXC_ID..."
pct stop "$LXC_ID" && pct start "$LXC_ID"
echo "NVIDIA driver installation and passthrough configuration completed in LXC container $LXC_ID."
@in03
Copy link
Author

in03 commented Oct 21, 2024

  • Removed steps
  • Renamed weird MAJOR_195, etc. variables
  • Removed gcc and make as deps from non dkms install, since not required to build

@in03
Copy link
Author

in03 commented Dec 29, 2024

A little bit of a WIP.

  • Host installation script now hooks post-kernel-installation.
  • No real testing done to confirm. Running interactively should work fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment