每次搭建GPU基础设施时,你都要重复同样的步骤:安装CUDA驱动程序和DCGM工具,进行操作系统级别的GPU优化设置,然后解决各种依赖性问题。这种老套的流程每次都会出现,不仅浪费了昂贵的云资源,还会在实际开始工作之前让人感到十分沮丧。

在本文中,你将学习如何使用Packer来构建一个可重复使用的、经过优化的GPU机器镜像。这个镜像会预先安装NVIDIA驱动程序、CUDA工具包、NVIDIA容器工具包、DCGM以及系统级别的GPU优化设置,比如持久化模式。

目录

先决条件

  • HashiCorp Packer 版本 >= 1.9

  • Google Compute Packer插件(通过packer init命令安装)

  • 可选地,如果需要为EC2环境构建镜像,还可以使用AWS Packer插件,只需在node.pkr.hcl文件中添加amazon-ebs资源来源即可

  • 需要拥有启用Compute Engine API的GCP项目账户(或具有EC2访问权限的AWS账户)

  • 需要GCP认证凭据(使用gcloud auth application-default login进行登录)或AWS凭证

  • 必须能够使用相应的NVIDIA GPU实例类型(例如,在GCP上可以使用A100、H100、L4型号;在AWS上可以使用p4d、p5、G6型号)

项目设置

步骤1:安装Packer

要开始使用,如果您使用的是macOS,可以按照以下步骤安装Packer;而对于Linux和Windows系统,则可以参考官方文档中的安装指南这里

首先,您需要通过终端安装官方的Packer插件包。

请先安装HashiCorp提供的插件仓库,该仓库包含了所有与HashiCorp相关的软件包。

$ brew tap hashicorp/tap

接下来,使用hashicorp/tap/packer命令来安装Packer本身。

步骤2:设置项目目录结构

在安装完Packer之后,您需要创建项目目录。为了保持代码的整洁性并明确各模块的功能分工,项目目录的结构应该如下所示。请使用以下命令在packer_demo文件夹中创建相应的文件:

mkdir -p packer_demo/script && touch packer_demo/{build.pkr.hcl,source.pkr.hcl,variable.pkr.hcl,local.pkr.hcl,plugins.pkr.hcl,values.pkrvars.hcl} packer_demo/script/base.sh

最终,您的文件目录结构应该如下所示:

packer_demo
├── build.pkr.hcl                 # 构建流程配置文件
├── source.pkr.hcl                # GCP资源定义文件
├── variable.pkr.hcl              # 变量定义文件及默认值
├── local.pkr.hcl                 # 本地配置文件
├── plugins.pkr.hcl                # Packer插件需求文件
├── values.pkrvars.hcl             # 变量取值配置文件(可自行修改)
├── script/
│   ├── base.sh                  # 基本脚本文件

步骤3:安装Packer插件

plugins.pkr.hcl文件中,您需要在packer块内指定所需的插件。其中packer {}块用于配置Packer的整体设置,包括指定所需插件的版本。在packer块中还有required_plugins部分,它会列出构建镜像时必须使用的所有插件。如果您使用的是Azure或AWS平台,可以在这里查看最新的插件信息这里

packer {
  required_plugins {
    googlecompute = {
      source  = "github.com/hashicorp/googlecompute"
      version = "~> 1"
    }
  }
}

完成配置后,使用以下命令初始化Packer插件:

packer init .

步骤4:定义数据源配置

在插件初始化完成后,你现在可以定义源配置块了。源配置块用于指定具体的构建插件,而该插件随后会被构建配置块调用。源配置块中需要包含你的项目ID、虚拟机创建所在的区域、基础镜像类型(比如Debian、Ubuntu等),以及基础镜像对应的项目ID

在GCP中,每个镜像都有一个对应的项目ID,例如Ubuntu对应的ID就是“ubuntu-os-cloud”。由于你正在为GPU虚拟机创建基础镜像,因此需要将机器类型设置为GPU机型,这样创建出来的虚拟机才能运行相应的命令。

source "googlecompute" "gpu-node" {
  project_id              = var.project_id
  zone                    = var.zone
  source_image_family     = var.image_family
  source_image_project_id = var.image_project_id
  ssh_username            = var.ssh_username
  machine_type            = var.machine_type



  image_name        = var.image_name
  image_description = var.image_description

  disk_size           = var.disk_size
  on_host_maintenance = "TERMINATE"

  tags = ["gpu-node"]
}

在Google Cloud Compute Engine中,将on_host_maintenance = "TERMINATE"设置为“TERMINATE”可以确保在基础设施维护期间虚拟机实例会直接停止运行,而不会被迁移至其他服务器上。这对于使用GPU或专用硬件而言非常重要,因为这类设备无法进行迁移操作,设置此选项可以有效防止数据丢失。

你可以在variable.pkr.hcl文件中定义所有变量,并在values.pkrvars.hcl文件中为这些变量设置具体的值。请务必将values.pkrvars.hcl文件添加到Git的忽略列表中。

variable "image_name" {
  type        = string
  description = "生成后的镜像名称"
}

variable "image_description" {
  type        = string
  description = "镜像的描述信息"
}

variable "project_id" {
  type        = string
  description = "用于创建镜像的GCP项目ID"
}

variable "image_family" {
  type        = string
  description = "镜像所属的系列"
}

variable "image_project_id" {
  type        = list(string)
  description = "用于查找基础镜像的项目ID"
}

variable "zone" {
  type        = string
  description = "构建实例创建所在的GCP区域"
}

variable "ssh_username" {
  type        = string
  description = "用于连接虚拟机的SSH用户名"
}
variable "machine_type" {
  type        = string
  description = "用于构建实例的机器类型"
}

variable "cuda_version" {
  type        = string
  description = "CUDA工具包版本"
  default     = "13.1"
}

variable "driver_version" {
  type        = string
  description = "NVIDIA驱动程序版本"
  default     = "590.48.01"
}

variable "disk_size" {
  type        = number
  description = "启动磁盘的大小(单位:GB)
  default     = 50
}

values.pkrvars.hcl

image_name        = "base-gpu-image-{{timestamp }}"
image_description = "Ubuntu 24.04 LTS,包含GPU驱动程序及健康检查功能"
project_id        = "你的GCP项目ID"
image_family      = "ubuntu-2404-lts-amd64"
image_project_id  = ["ubuntu-os-cloud"]
zone              = "us-central1-a"
ssh_username      = "packer"
machine_type      = "g2-standard-4"
disk_size        = 50
driver_version   = "590.48.01"
cuda_version      = "13.1" 

步骤5:编写构建模板

创建文件build.pkr.hcl。其中build块用于创建临时实例、运行配置脚本,并生成最终镜像。

此模板中的配置脚本分为以下几部分:

  • 第一个配置脚本负责执行系统更新及升级操作。

  • 第二个配置脚本会重启实例(expectdisconnect = true)。

  • 第三个配置脚本会等待实例重新启动完成,然后执行script/base.sh。该脚本会设置max_retries参数以处理临时性的SSH连接超时问题,并传递DRIVER_VERSIONCUDA_VERSION环境变量。

最后,还有一个后处理脚本用于输出镜像ID及构建完成状态:

build {
  sources = ["source.googlecompute gpu-node"]

  provisioner "shell" {
    inline = [
      "set -e",
      "sudo apt update",
      "sudo apt -y dist-upgrade"
    ]
  }

  provisioner "shell" {
    expectdisconnect = true
    inline            = ["sudo reboot"]
  }

  # 安装NVIDIA驱动程序、CUDA及DCGM相关组件
  provisioner "shell" {
    pause_before = "60s"
    script       = "script/base.sh"
    max_retries  = 2
    environment_vars = [
      "DRIVER_VERSION=${var.driver_version}",
      "CUDA_VERSION=${var.cuda_version}"
    ]
  }

  post-processor "shell-local" {
    inline = [
      "echo '=== 镜像构建完成 ==='",
      "echo '镜像ID: ${build.ID}'",
      "date"
    ]
  }
}

步骤6:编写GPU配置脚本

现在我们来详细分析这个配置脚本的各个部分。

第1节:预安装操作(内核头文件)

在安装NVIDIA驱动程序之前,系统需要相应的内核头文件及构建工具。NVIDIA驱动程序在安装过程中会通过DKMS机制编译内核模块,因此如果当前运行版本的内核所对应的内核头文件缺失,构建过程将会失败,导致驱动程序无法在系统启动时正常加载。

log "正在安装内核头文件及构建工具..."
sudo apt-get install -qq -y \
  "linux-headers-$(uname -r)" \
  build-essential \
  dkms \
  curl \
  wget

第2节:安装NVIDIA的Apt仓库

这段脚本会根据您使用的Linux发行版,下载并安装NVIDIA官方的密钥包。该密钥包包含了系统验证CUDA软件包所需的可信签名密钥。

log "正在添加NVIDIA CUDA apt仓库 (${DISTRO})..."  
wget -q "https://developer.download.nvidia.com/compute/cuda/repos/\({DISTRO}/\){ARCH}/cuda-keyring_1.1-1_all.deb" \
  -O /tmp/cuda-keyring.deb  
sudo dpkg -i /tmp/cuda-keyring.deb  
rm /tmp/cuda-keyring.deb  
sudo apt-get update -qq  

第3节:固定NVIDIA驱动程序的版本

将NVIDIA驱动程序固定为特定版本,可以确保系统始终安装并使用该版本驱动程序,即使仓库中出现了更新版本的驱动程序也是如此。

NVIDIA驱动程序与CUDA工具包版本、内核版本以及Docker或NVIDIA Container Toolkit等容器运行时环境紧密相关。

如果这些组件不匹配,例如系统自动升级到了较新的驱动程序版本,可能会导致CUDA无法正常工作,从而破坏GPU加速功能,或者使不同环境中的机器配置出现不一致的情况。

log "正在将驱动程序固定为版本 ${DRIVER_VERSION}..."  
sudo apt-get install -qq -y "nvidia-driver-pinning-${DRIVER_VERSION}"  

第4节:安装驱动程序

libnvidia-compute包仅安装与计算相关的用户空间库(即CUDA驱动程序组件),而nvidia-dkms-open包则安装开源NVIDIA内核模块,这些模块是通过DKMS在本地编译生成的。

这两个包结合起来,就能为您提供一个功能完备的CUDA驱动程序环境,而且完全不需要任何图形界面或相关的图形组件。

在这里,我们使用了NVIDIA专为计算任务设计的驱动程序栈,并采用了开源内核模块,因为这样就可以避免安装任何与显示相关的组件,而这些组件其实并不是必需的。

这种基于DKMS的安装方法更加适合Linux发行版的使用需求,因为它体积小、专注于计算功能。

log "正在安装NVIDIA专用计算驱动程序(使用开源内核模块)..."  
sudo apt-get -V install -y \
  libnvidia-compute \
  nvidia-dkms-open  

第5节:安装CUDA工具包

这段脚本会为指定的版本安装CUDA工具包,然后确保所有用户和所有的shell会话都能使用CUDA的可执行文件和库文件。

它会把CUDA的二进制文件添加到PATH环境变量中,因此像nvcccuda-gdbcuda-memcheck这样的命令就可以直接使用,而无需指定完整的路径。同时,它还会把CUDA库文件添加到LD_LIBRARY_PATH环境变量中,这样应用程序在运行时就能找到这些共享库文件。

log "正在安装CUDA工具包 ${CUDA_VERSION}..."  
sudo apt-get install -qq -y "cuda-toolkit-${CUDA_VERSION}"  

# 使所有用户和会话都能使用CUDA相关的路径设置  
cat <<『EOF』 | sudo tee /etc/profile.d/cuda.sh  
export PATH=/usr/local/cuda/bin:$PATH  
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}  
EOF  
echo "/usr/local/cuda/lib64" | sudo tee /etc/ld.so.conf.d/cuda.conf  
sudo ldconfig  

第6节:NVIDIA容器工具包

此步骤用于安装NVIDIA容器工具包,并对其进行配置,以确保Docker或containerd等容器能够安全、正确地访问GPU。对于Kubernetes中的GPU节点、使用Docker的GPU工作负载,以及任何需要在容器内利用GPU加速的系统而言,这都是一项至关重要的操作。

log "正在安装NVIDIA容器工具包..."  
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
  | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg  

curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list  

sudo apt-get update -qq  
sudo apt-get install -qq -y nvidia-container-toolkit  

# 为containerd进行配置(如果系统使用的是Kubernetes作为运行时环境)  
sudo nvidia-ctk runtime configure --runtime=containerd  

# 如果系统中安装了Docker,也需为其进行配置  
if systemctl list-unit-files | grep -q "^docker.service"; then  
  sudo nvidia-ctk runtime configure --runtime=docker  
fi  

第7节:安装DCGM(数据中心GPU管理工具)

本节介绍了NVIDIA DCGM的安装与配置过程。DCGM是NVIDIA专为数据中心GPU开发的管理与监控工具。

该工具能够提供设备健康状况监测、故障诊断功能,同时支持温度、时钟频率、功耗等各项性能数据的实时采集,并具备错误报告机制。此外,它还能与Kubernetes、Prometheus等监控系统无缝集成。您的GPU监控方案离不开DCGM的支持。

脚本会检测已安装的DCGM版本,确保其符合NVIDIA 590系列驱动程序所要求的最低版本要求。通过这种方式,可以有效避免GPU驱动程序与DCGM之间的不兼容问题,从而保证监控功能的正常运行。此外,如果您使用的是A100/H100 DGX等多GPU架构服务器,该脚本还会启用NVLink/NVSwitch的连接管理功能。

log "正在安装DCGM..."  
sudo apt-get install -qq -y datacenter-gpu-manager  

DCGM_VER=\((dpkg -s datacenter-gpu-manager 2>/dev/null | awk '/^Version:/{print \)2}' | sed 's/^[0-9]*://')  
DCGM_MAJOR=\((echo "\){DCGM_VER}" | cut -d. -f1)  
DCGM_MINOR=\((echo "\){DCGM_VER}" | cut -d. -f2)  
if [[ "\({DCGM_major}" -lt 4 ]] || { [[ "\){DCGM.major}" -eq 4 ]] && [[ "${DCGM_MINOR}" -lt 3 ]]; }; then  
  error "安装的DCGM版本低于NVIDIA 590系列驱动程序所需的最低版本4.3。请检查您的CUDA配置。"  
fi  
log "DCGM已成功安装,版本为:${DCGM_VER}"  

sudo systemctl enable nvidia-dcgm  
sudo systemctl start nvidia-dcgm  

# 如果系统使用NVLink/NVSwitch技术,还需启用相应的连接管理工具  
if systemctl list-unit-files | grep -q "^nvidia-fabricmanager.service"; then  
  log "正在为NVLink GPU启用连接管理工具..."  
  sudo systemctl enable nvidia-fabricmanager  
  sudo systemctl start nvidia-fabricmanager  
fi  

第8节:启用持久化模式

NVIDIA驱动程序在GPU空闲时通常会自动卸载。当新的工作负载开始运行时,驱动程序需要重新加载、重新初始化GPU,并设置内存映射机制。这一过程会导致几百毫秒到几秒钟的延迟,具体延迟时间取决于所使用的GPU和系统配置。

启用“nvidia-persistenced”功能后,即使没有GPU工作负载在运行,NVIDIA驱动程序也会一直保留在内存中。

log "正在启用nvidia-persistenced功能..."  
sudo systemctl enable nvidia-persistenced  
sudo systemctl start nvidia-persistenced  

第9节:针对GPU计算工作负载的系统调优

本部分介绍了一组适用于高性能GPU服务器、Kubernetes GPU节点以及机器学习/AI工作负载的系统级性能与稳定性优化措施

每一项优化措施都是为了解决在实际GPU应用环境中出现的特定瓶颈问题或不稳定现象而设计的。

  • 交换空间和内存管理:禁用交换空间并将vm.swappiness=0设置为默认值,可以防止内核将占用GPU资源的进程移至交换空间。GPU工作负载对延迟非常敏感,使用交换空间可能会导致CUDA上下文重置或GPU驱动程序超时。

  • 大容量内存分配与hugepages:将vm.nr_hugepages=2048设置为默认值,可以创建一个hugepages缓冲区池,从而减少大规模连续内存分配时对TLB机制的负担。CUDA、NCCL以及深度学习框架在处理大量数据时经常需要分配大容量内存,而hugepages技术能够有效提升内存带宽并降低延迟,这一点在多GPU服务器上尤为有用。

  • CPU频率调节器:安装cpupower工具,并将CPU频率调节器设置为performance模式,可以确保CPU始终以最高频率运行而不会降频。在数据预处理、内核程序启动以及NCCL通信等阶段,GPU工作负载往往会受到CPU性能的限制,因此保持CPU全速运行有助于提升整体效率。

  • NUMA与拓扑管理工具:安装numactllibnuma-dev以及hwloc等工具,可以帮助将进程绑定到特定的NUMA节点上,了解CPU与GPU之间的协作关系,并优化多GPU系统的资源分配方案。

  • 禁用irqbalance功能:关闭并禁用irqbalance服务后,NVIDIA驱动程序就可以自行管理中断请求的分配机制。对于GPU服务器而言,如果启用了irqbalance功能,它可能会将GPU相关的中断请求分配到性能较低的CPU上,从而导致延迟增加和吞吐量下降。

log "正在应用系统调优设置..."  

# 禁用交换空间(对Kubernetes调度器和机器学习任务的稳定性至关重要)  
sudo swapoff -a  
sudo sed -i '/ swap / s/^/#/' /etc/fstab  
echo "vm.swappiness=0" | sudo tee /etc/sysctl.d/99-gpu-swappiness.conf  

# hugepages——减少大规模内存分配时对TLB机制的负担  
echo "vm.nr_hugepages=2048" | sudo tee /etc/sysctl.d/99-gpu-hugepages.conf  

# CPU性能调节器设置  
sudo apt-get install -qq -y linux-tools-common "linux-tools-$(uname -r)" || true  
sudo cpupower frequency-set -g performance || true  

# NUMA与拓扑管理工具,用于优化GPU资源分配  
sudo apt-get install -qq -y numactl libnuma-dev hwloc  

# 禁用irqbalance功能,让NVIDIA驱动程序自行管理中断请求  
sudo systemctl disable irqbalance || true  
sudo systemctl stop irqbalance || true  

# 现在应用所有系统配置设置  
sudo sysctl --system  

完整的base.sh脚本如下:

#!/bin/bash
set -euo pipefail

log()   { echo "[BASE] $1"; }
error() { echo "[BASE][ERROR] $1" >>&2; exit 1; }

###############################################################
###############################################################
[[ -z "${DRIVER_VERSION:-}" ]] && error "未设置DRIVER_VERSION。"
[[ -z "${CUDA_VERSION:-}"   ]] && error "未设置CUDA_VERSION。"

log "DRIVER_VERSION : ${DRIVER_VERSION}"
log "CUDA_VERSION   : ${CUDA_VERSION}"

DISTRO=\((. /etc/os-release &&& echo "\){ID}${VERSION_ID}" | tr -d '.')
ARCH="x86_64"

export DEBIAN_FRONTEND=noninteractive

###############################################################
# 1. 系统更新
###############################################################
log "正在更新系统软件包..."
sudo apt-get update -qq
sudo apt-get upgrade -qq -y

###############################################################
# 2. 安装前的准备——内核头文件
#    来源:https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/ubuntu.html
###############################################################
log "正在安装内核头文件和构建工具..."
sudo apt-get install -qq -y \
  "linux-headers-$(uname -r)" \
  build-essential \
  dkms \
  curl \
  wget

###############################################################
# 3. NVIDIA CUDA仓库
###############################################################
log "正在添加NVIDIA CUDA apt仓库 (${DISTRO})..."
wget -q "https://developer.download.nvidia.com/compute/cuda/repos/\({DISTRO}/\){ARCH}/cuda-keyring_1.1-1_all.deb" \
  -O /tmp/cuda-keyring.deb
sudo dpkg -i /tmp/cuda-keyring.deb
rm /tmp/cuda-keyringdeb
sudo apt-get update -qq

###############################################################
# 4. 在安装之前固定驱动程序版本(需要590及以上版本)
###############################################################
log "正在将驱动程序版本固定为${DRIVER_VERSION}..."
sudo apt-get install -qq -y "nvidia-driver-pinning-${DRIVER_VERSION}"

###############################################################
# 5. 仅用于计算任务的驱动程序——开放内核模块
#    来源:NVIDIA驱动程序安装指南——仅用于计算任务的系统(开放内核模块)
#
#    libnvidia-compute  = 仅包含计算相关库(不包含GL/Vulkan/display功能)
#    nvidia-dkms-open   = 通过DKMS构建的开源内核模块
#
#    对于Ampere、Hopper和Blackwell系列的数据中心GPU(如A100、H100等),开放内核模块是NVIDIA推荐的安装选项
###############################################################
log "正在安装NVIDIA仅用于计算任务的驱动程序(开放内核模块)..."
sudo apt-get -V install -y \
  libnvidia-compute \
  nvidia-dkms-open

###############################################################
# 6. CUDA工具包
###############################################################
log "正在安装CUDA工具包${CUDA_VERSION}..."
sudo apt-get install -qq -y "cuda-toolkit-${CUDA_VERSION}"

# 为所有用户和会话永久设置CUDA路径
cat << 'EOF' | sudo tee /etc/profile.d/cuda.sh
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}
EOF
echo "/usr/local/cuda/lib64" | sudo tee /etc/ld.so.conf.d/cuda.conf
sudo ldconfig

###############################################################
# 7. NVIDIA容器工具包
#    在Docker、containerd或Kubernetes中运行GPU任务时需要这个工具包
###############################################################
log "正在安装NVIDIA容器工具包..."
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
  | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update -qq
sudo apt-get install -qq -y nvidia-container-toolkit

# 如果系统中安装了containerd,则进行相应配置
if systemctl list-unit-files | grep -q "^docker.service"; then
  sudo nvidia-ctk runtime configure --runtime=docker
fi

###############################################################
# 8. DCGM——数据中心GPU管理工具
###############################################################
log "正在安装DCGM..."
sudo apt-get install -qq -y datacenter-gpu-manager
 
DCGM_VER=\((dpkg -s datacenter-gpu-manager 2>./dev/null | awk '/^Version:/{print \)2}' | sed 's/^[0-9]*://')
DCGM_MAJOR=\((echo "\){DCGM_VER}" | cut -d. -f1)
DCGM_MINOR=\((echo "\){DCGM_VER}" | cut -d. -f2)
if [[ "\({DCGM_major}" -lt 4 ]] || { [[ "\){DCGM_MAJOR}" -eq 4 ]] && [[ "${DCGM_MINOR}" -lt 3 ]]; }; then
  error "DCGM版本${DCGM_VER}低于驱动程序590及以上版本所需的最低版本4.3。请检查您的CUDA仓库设置。" 
fi
log "DCGM已安装:${DCGM_VER}"

sudo systemctl enable nvidia-dcgm
sudo systemctl start  nvidia-dcgm

# Fabric Manager——仅适用于NVLink/NVSwitch GPU(如A100/H100多GPU节点)
if systemctl list-unit-files | grep -q "^nvidia-fabricmanager.service"; then
  log "正在为NVLink GPU启用nvidia-fabricmanager..."
  sudo systemctl enable nvidia-fabricmanager
  sudo systemctl start  nvidia-fabricmanager
fi

###############################################################
# 9. NVIDIA持久化守护进程
#    这个守护进程可以确保驱动程序在多个任务之间保持加载状态,从而减少在新任务开始时进行首次CUDA调用所导致的延迟
###############################################################
log "正在启用nvidia-persistenced..."
sudo systemctl enable nvidia-persistenced
sudo systemctl start  nvidia-persistenced

###############################################################
# 10. 为GPU计算任务优化系统配置
###############################################################
log "正在应用系统优化设置..."

# 禁用交换分区(这对Kubernetes调度器和机器学习任务的稳定性至关重要)
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
echo "vm.swappiness=0"     | sudo tee /etc/sysctl.d/99-gpu-swappiness.conf

# 设置大页内存参数——可以减少大规模内存分配时TLB带来的压力
echo "vm.nr_hugepages=2048" | sudo tee /etc/sysctl.d/99-gpu-hugepages.conf

# 配置CPU性能调节机制
sudo apt-get install -qq -y linux-tools-common "linux-tools-$(uname -r)" || true
sudo cpupower frequency-set -g performance || true

# 为了优化GPU任务的调度,需要安装NUMA和拓扑相关工具
sudo apt-get install -qq -y numactl libnuma-dev hwloc

# 禁用irqbalance功能——让NVIDIA驱动程序来管理中断分配
sudo systemctl disable irqbalance || true
sudo systemctl stop    irqbalance || true

# 现在应用所有刚刚设置的sysctl参数
sudo sysctl --system

###############################################################
# 安装完成
###############################################################
log "============================================"
log "基础配置阶段已经结束。"
log "  操作系统:${DISTRO}"
log "  驱动程序:${DRIVER_VERSION}(开放内核模块,仅用于计算任务)"
log "  CUDA工具包:cuda-toolkit-${CUDA_VERSION}"
log "  DCGM版本:${DCGM_VER}"
log "============================================"

步骤7:组装并运行构建过程

首先验证模板,然后再运行构建过程。验证能够及时发现语法错误或变量问题,这样构建就不会在配置有误的情况下开始。

packer validate -var-file=values.pkrvars.hcl .

如果验证成功,你会看到类似“配置有效”这样的确认信息。之后就可以开始构建过程了。这个过程会创建一个临时虚拟机,运行相应的配置脚本,并最终生成一个镜像文件。

packer build -var-file=values.pkrvars.hcl .

构建通常需要15到20分钟的时间,具体取决于网络速度和包的安装情况。请关注Packer日志中以下三个关键节点:

  • 实例创建——确认临时虚拟机已经成功配置。

  • 配置脚本执行结果——会显示每个脚本步骤的执行情况(如更新操作、重启系统、执行script/base.sh脚本)以及可能出现的错误。

  • 镜像生成完成——表示构建过程已经结束,镜像文件已经生成。

如果构建失败,请复制出现问题的配置脚本对应的日志信息,在修复相关问题后重新运行构建过程。为了快速排查故障,也可以在类似的测试虚拟机上本地运行出问题的配置脚本进行调试。

googlecompute.gpu-node: 输出结果会显示为这种颜色。
==> googlecompute gpu-node: 检查发现镜像文件不存在...
==>> googlecompute gpu-node: 正在为实例创建临时RSA SSH密钥...
==>> googlecompute gpu-node: 无法创建持久化磁盘
==>> googlecompute gpu-node> 使用的镜像版本为:ubuntu-2404-noble-amd64-v20260225
==>> googlecompute gpu-node> 正在创建实例...
==>> googlecompute gpu-node> 加载区域设置为:us-central1-a
==>> googlecompute gpu-node> 选择的机器类型为:g2-standard-4
==>> googlecompute gpu-node> 正在请求创建实例...
==>> googlecompute gpu-node> 等待实例创建完成...
==>> googlecompute gpu-node> 实例已经创建成功!
==>> googlecompute gpu-node> 等待实例启动...
==>> googlecompute gpu-node> 实例的IP地址为:34.58.58.214
==>> googlecompute gpu-node> 正在使用SSH连接工具进行连接:34.58.58.214
==>> googlecompute gpu-node> 等待SSH连接建立完成...
systemd-logind.service
==>> googlecompute gpu-node> 重新启动unattended-upgrades服务
==>> googlecompute gpu-node:
==>> googlecompute gpu-node> 没有容器需要重启。
==>> googlecompute gpu-node:
==>> googlecompute gpu-node> 有些用户会使用过时的二进制文件...
==>> googlecompute gpu-node> packer @ session #1: sshd[1535]
==>> googlecompute gpu-node> packer @ user manager service: systemd[1540]
==>> 将暂停1分钟,然后继续执行下一个配置步骤...
==>> 正在使用shell脚本进行配置:script/base.sh
==>> [BASE] 驱动程序版本:590.48.01
==>> [BASE] CUDA版本:13.1
==>> [BASE] 正在更新系统包...
==>> [BASE] 正在安装内核头文件和构建工具...
==>> [BASE] 正在安装CUDA Toolkit 13.1...
==>> [BASE] 正在安装DCGM...
==>> [BASE] 正在启用nvidia-persistenced功能...
==>> [BASE] 正在应用系统优化设置...
==>> vm.swappiness=0
==>> vm.nr_hugepages=2048
==>> 正在设置CPU相关参数:0
==>> 设置新参数时出现错误。常见错误原因包括...
==>> [BASE] =================================-----------
==>> [BASE] 基础配置步骤已完成。
==> [BASE] 操作系统版本:ubuntu2404
==>> [BASE] 驱动程序版本:590.48.01(开放源代码内核模块,仅用于计算任务)
==>> [BASE] CUDA版本:cuda-toolkit-13.1
==>> [BASE] DCGM版本:1:3.3.9
==>> [BASE] =================================-----------
==>> [BASE] 正在删除实例...
==>> 实例已经成功删除!
==>> 正在生成镜像文件...
==>> 正在删除相关磁盘...
==>> 磁盘已经删除成功!
==>> 正在运行后续处理脚本:(类型为shell-local)
==>> googlecompute gpu-node (shell-local): 正在运行本地shell脚本…
==>> googlecompute gpu-node (shell-local): === 镜像生成完成 ===
==>> googlecompute gpu-node (shell-local): 镜像ID为:packer-69b6c2ee-883a-3602-7bb5-059f1ba27c8b
==>> googlecompute gpu-node (shell-local): 2026年3月15日,星期三,15:50:09(WAT时间)
构建“googlecompute.gpu-node”耗时17分钟55秒完成。
==>> 等待过程也持续了17分钟55秒。
==>> 构建任务已经完成。成功构建生成的镜像文件为:
-->> googlecompute gpu-node: 在“my_project-00000”项目中生成了一个名为base-gpu-image-1773585134的镜像文件

步骤8:测试图像并验证GPU配置

请在GCP控制台中确认该图像是否存在:计算 → 存储 → 图像,然后找到你新建的操作系统镜像。

你在GCP上的图像信息

使用该镜像创建一个测试虚拟机:

gcloud compute instances create my-gpu-vm \
  --machine-type=g2-standard-4 \
  --accelerator

当虚拟机处于正在运行状态时,请确认NVIDIA驱动程序及GPU已正确安装:

Nvidia-SMI命令的输出结果,显示了驱动程序版本和CUDA版本
用于验证持久化模式是否已启用的图像

nvidia-smi的输出结果确认了以下内容:

  • 驱动程序版本590.48.01已成功加载。

  • CUDA 13.1版本也已安装完毕。

  • 持久化模式处于开启状态。

  • 检测到的L4 GPU拥有23GB的显存。

  • 未发现任何ECC错误。

  • 当前没有正在运行的进程,虚拟机处于空闲状态。

这正是一个正常的操作系统镜像应该具备的状态。注意Disp.A: Off这一项吗?这说明我们选择的仅用于计算任务的驱动程序配置是有效的——显示适配器并未被激活。

你可以通过运行命令nvcc --version来确认CUDA工具包是否已正确安装。从输出结果中可以明确看到,版本13.1确实已经按照要求安装完毕。

NVCC版本查询命令的输出结果

接下来,我们通过运行命令dcgmi discovery -l来确认DCGM是否已成功安装。如果输出结果正常,说明DCGM正在运行,并且能够与驱动程序正常通信。

DCGM查询命令的输出结果,显示了设备信息

结论

现在,您已经获得了一个经过优化、适用于GPU运行的基础镜像。该镜像包含了使用开源内核模块构建的NVIDIA计算驱动程序、用于监控的DCGM工具,以及CUDA工具包。此外,您还针对GPU计算工作负载进行了操作系统级别的优化调整,从而确保环境的一致性及可重复性,而无需进行任何手动配置。

接下来,您可以通过添加应用程序层脚本来进一步扩展这个镜像,从而安装PyTorch、TensorFlow或vLLM等框架;或者创建一个实例模板,利用这个镜像来扩展您的GPU基础设施。

完整的Packer项目还提供了用于训练和推理工作负载的额外脚本,这些脚本可以帮助您进一步优化和完善您的镜像配置。

参考资料

Comments are closed.